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:
parent
e28d6ee66a
commit
b51c8cab3e
@ -137,6 +137,30 @@ static my_bool acquire_plugins(THD *thd, plugin_ref plugin, void *arg)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
@brief Acquire audit plugins
|
||||||
|
|
||||||
|
@param[in] thd MySQL thread handle
|
||||||
|
@param[in] event_class Audit event class
|
||||||
|
|
||||||
|
@details Ensure that audit plugins interested in given event
|
||||||
|
class are locked by current thread.
|
||||||
|
*/
|
||||||
|
void mysql_audit_acquire_plugins(THD *thd, uint event_class)
|
||||||
|
{
|
||||||
|
unsigned long event_class_mask[MYSQL_AUDIT_CLASS_MASK_SIZE];
|
||||||
|
DBUG_ENTER("mysql_audit_acquire_plugins");
|
||||||
|
set_audit_mask(event_class_mask, event_class);
|
||||||
|
if (thd && !check_audit_mask(mysql_global_audit_mask, event_class_mask) &&
|
||||||
|
check_audit_mask(thd->audit_class_mask, event_class_mask))
|
||||||
|
{
|
||||||
|
plugin_foreach(thd, acquire_plugins, MYSQL_AUDIT_PLUGIN, &event_class);
|
||||||
|
add_audit_mask(thd->audit_class_mask, event_class_mask);
|
||||||
|
}
|
||||||
|
DBUG_VOID_RETURN;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Notify the audit system of an event
|
Notify the audit system of an event
|
||||||
|
|
||||||
@ -151,21 +175,8 @@ void mysql_audit_notify(THD *thd, uint event_class, uint event_subtype, ...)
|
|||||||
{
|
{
|
||||||
va_list ap;
|
va_list ap;
|
||||||
audit_handler_t *handlers= audit_handlers + event_class;
|
audit_handler_t *handlers= audit_handlers + event_class;
|
||||||
unsigned long event_class_mask[MYSQL_AUDIT_CLASS_MASK_SIZE];
|
|
||||||
|
|
||||||
DBUG_ASSERT(event_class < audit_handlers_count);
|
DBUG_ASSERT(event_class < audit_handlers_count);
|
||||||
|
mysql_audit_acquire_plugins(thd, event_class);
|
||||||
set_audit_mask(event_class_mask, event_class);
|
|
||||||
/*
|
|
||||||
Check to see if we have acquired the audit plugins for the
|
|
||||||
required audit event classes.
|
|
||||||
*/
|
|
||||||
if (thd && check_audit_mask(thd->audit_class_mask, event_class_mask))
|
|
||||||
{
|
|
||||||
plugin_foreach(thd, acquire_plugins, MYSQL_AUDIT_PLUGIN, &event_class);
|
|
||||||
add_audit_mask(thd->audit_class_mask, event_class_mask);
|
|
||||||
}
|
|
||||||
|
|
||||||
va_start(ap, event_subtype);
|
va_start(ap, event_subtype);
|
||||||
(*handlers)(thd, event_subtype, ap);
|
(*handlers)(thd, event_subtype, ap);
|
||||||
va_end(ap);
|
va_end(ap);
|
||||||
@ -448,6 +459,11 @@ static void event_class_dispatch(THD *thd, const struct mysql_event *event)
|
|||||||
#else /* EMBEDDED_LIBRARY */
|
#else /* EMBEDDED_LIBRARY */
|
||||||
|
|
||||||
|
|
||||||
|
void mysql_audit_acquire_plugins(THD *thd, uint event_class)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void mysql_audit_initialize()
|
void mysql_audit_initialize()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
@ -29,6 +29,7 @@ extern void mysql_audit_finalize();
|
|||||||
|
|
||||||
extern void mysql_audit_init_thd(THD *thd);
|
extern void mysql_audit_init_thd(THD *thd);
|
||||||
extern void mysql_audit_free_thd(THD *thd);
|
extern void mysql_audit_free_thd(THD *thd);
|
||||||
|
extern void mysql_audit_acquire_plugins(THD *thd, uint event_class);
|
||||||
|
|
||||||
|
|
||||||
extern void mysql_audit_notify(THD *thd, uint event_class,
|
extern void mysql_audit_notify(THD *thd, uint event_class,
|
||||||
|
@ -29,7 +29,7 @@
|
|||||||
#include "records.h" // init_read_record, end_read_record
|
#include "records.h" // init_read_record, end_read_record
|
||||||
#include <my_pthread.h>
|
#include <my_pthread.h>
|
||||||
#include <my_getopt.h>
|
#include <my_getopt.h>
|
||||||
#include <mysql/plugin_audit.h>
|
#include "sql_audit.h"
|
||||||
#include "lock.h" // MYSQL_LOCK_IGNORE_TIMEOUT
|
#include "lock.h" // MYSQL_LOCK_IGNORE_TIMEOUT
|
||||||
#define REPORT_TO_LOG 1
|
#define REPORT_TO_LOG 1
|
||||||
#define REPORT_TO_USER 2
|
#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)))
|
MYSQL_LOCK_IGNORE_TIMEOUT)))
|
||||||
DBUG_RETURN(TRUE);
|
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_mutex_lock(&LOCK_plugin);
|
||||||
mysql_rwlock_wrlock(&LOCK_system_variables_hash);
|
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)))
|
if (! (table= open_ltable(thd, &tables, TL_WRITE, MYSQL_LOCK_IGNORE_TIMEOUT)))
|
||||||
DBUG_RETURN(TRUE);
|
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_mutex_lock(&LOCK_plugin);
|
||||||
if (!(plugin= plugin_find_internal(name, MYSQL_ANY_PLUGIN)))
|
if (!(plugin= plugin_find_internal(name, MYSQL_ANY_PLUGIN)))
|
||||||
{
|
{
|
||||||
|
Loading…
x
Reference in New Issue
Block a user