1
0
mirror of https://github.com/MariaDB/server.git synced 2025-07-30 16:24:05 +03:00

BUG#54989 - With null_audit installed, server hangs on an

attempt to install a plugin twice

Server crashes when [UN]INSTALL PLUGIN fails (returns an
error) and general log is disabled and there are audit
plugins interested in MYSQL_AUDIT_GENERAL_CLASS. 

When audit event is triggered, audit subsystem acquires interested
plugins by walking through plugin list. Evidently plugin list
iterator protects plugin list by acquiring LOCK_plugin, see
plugin_foreach_with_mask().

On the other hand [UN]INSTALL PLUGIN is acquiring LOCK_plugin
rather for a long time.

When audit event is triggered during [UN]INSTALL PLUGIN, plugin
list iterator acquires the same lock (within the same thread)
second time.

Repeatable only with general_log disabled, because general_log
triggers MYSQL_AUDIT_GENERAL_LOG event, which acquires audit
plugins before [UN]INSTALL PLUGIN acquired LOCK_plugin.

With this fix we pre-acquire audit plugins for events that
may potentially occur during [UN]INSTALL PLUGIN.

This hack should be removed when LOCK_plugin is fixed so it
protects only what it supposed to protect.

No test case for this fix - we do not have facility to test
audit plugins yet.

sql/sql_audit.cc:
  Move "acquire audit plugin" logics to a separate
  function.
sql/sql_audit.h:
  Move "acquire audit plugin" logics to a separate
  function.
sql/sql_plugin.cc:
  Pre-acquire audit plugins for events that may potentially occur
  during [UN]INSTALL PLUGIN.
This commit is contained in:
Sergey Vojtovich
2010-08-20 13:58:28 +04:00
parent e28d6ee66a
commit b51c8cab3e
3 changed files with 74 additions and 15 deletions

View File

@ -29,7 +29,7 @@
#include "records.h" // init_read_record, end_read_record
#include <my_pthread.h>
#include <my_getopt.h>
#include <mysql/plugin_audit.h>
#include "sql_audit.h"
#include "lock.h" // MYSQL_LOCK_IGNORE_TIMEOUT
#define REPORT_TO_LOG 1
#define REPORT_TO_USER 2
@ -1703,6 +1703,27 @@ bool mysql_install_plugin(THD *thd, const LEX_STRING *name, const LEX_STRING *dl
MYSQL_LOCK_IGNORE_TIMEOUT)))
DBUG_RETURN(TRUE);
/*
Pre-acquire audit plugins for events that may potentially occur
during [UN]INSTALL PLUGIN.
When audit event is triggered, audit subsystem acquires interested
plugins by walking through plugin list. Evidently plugin list
iterator protects plugin list by acquiring LOCK_plugin, see
plugin_foreach_with_mask().
On the other hand [UN]INSTALL PLUGIN is acquiring LOCK_plugin
rather for a long time.
When audit event is triggered during [UN]INSTALL PLUGIN, plugin
list iterator acquires the same lock (within the same thread)
second time.
This hack should be removed when LOCK_plugin is fixed so it
protects only what it supposed to protect.
*/
mysql_audit_acquire_plugins(thd, MYSQL_AUDIT_GENERAL_CLASS);
mysql_mutex_lock(&LOCK_plugin);
mysql_rwlock_wrlock(&LOCK_system_variables_hash);
@ -1783,6 +1804,27 @@ bool mysql_uninstall_plugin(THD *thd, const LEX_STRING *name)
if (! (table= open_ltable(thd, &tables, TL_WRITE, MYSQL_LOCK_IGNORE_TIMEOUT)))
DBUG_RETURN(TRUE);
/*
Pre-acquire audit plugins for events that may potentially occur
during [UN]INSTALL PLUGIN.
When audit event is triggered, audit subsystem acquires interested
plugins by walking through plugin list. Evidently plugin list
iterator protects plugin list by acquiring LOCK_plugin, see
plugin_foreach_with_mask().
On the other hand [UN]INSTALL PLUGIN is acquiring LOCK_plugin
rather for a long time.
When audit event is triggered during [UN]INSTALL PLUGIN, plugin
list iterator acquires the same lock (within the same thread)
second time.
This hack should be removed when LOCK_plugin is fixed so it
protects only what it supposed to protect.
*/
mysql_audit_acquire_plugins(thd, MYSQL_AUDIT_GENERAL_CLASS);
mysql_mutex_lock(&LOCK_plugin);
if (!(plugin= plugin_find_internal(name, MYSQL_ANY_PLUGIN)))
{