diff options
Diffstat (limited to 'sql/sql_plugin.cc')
-rw-r--r-- | sql/sql_plugin.cc | 89 |
1 files changed, 64 insertions, 25 deletions
diff --git a/sql/sql_plugin.cc b/sql/sql_plugin.cc index 066a7512eaf..d36654c4c18 100644 --- a/sql/sql_plugin.cc +++ b/sql/sql_plugin.cc @@ -1,4 +1,4 @@ -/* Copyright (C) 2005 MySQL AB, 2009 Sun Microsystems, Inc. +/* Copyright (c) 2005, 2011, Oracle and/or its affiliates. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -11,7 +11,7 @@ You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #include "sql_priv.h" // SHOW_MY_BOOL #include "unireg.h" @@ -30,6 +30,7 @@ #include <my_pthread.h> #include <my_getopt.h> #include "sql_audit.h" +#include <mysql/plugin_auth.h> #include "lock.h" // MYSQL_LOCK_IGNORE_TIMEOUT #include <mysql/plugin_auth.h> #define REPORT_TO_LOG 1 @@ -42,9 +43,8 @@ extern struct st_maria_plugin *mysql_mandatory_plugins[]; @note The order of the enumeration is critical. @see construct_options */ -static const char *global_plugin_typelib_names[]= - { "OFF", "ON", "FORCE", NULL }; -enum enum_plugin_load_policy {PLUGIN_OFF, PLUGIN_ON, PLUGIN_FORCE}; +const char *global_plugin_typelib_names[]= + { "OFF", "ON", "FORCE", "FORCE_PLUS_PERMANENT", NULL }; static TYPELIB global_plugin_typelib= { array_elements(global_plugin_typelib_names)-1, "", global_plugin_typelib_names, NULL }; @@ -301,6 +301,26 @@ static void report_error(int where_to, uint error, ...) } } +/** + Check if the provided path is valid in the sense that it does cause + a relative reference outside the directory. + + @note Currently, this function only check if there are any + characters in FN_DIRSEP in the string, but it might change in the + future. + + @code + check_valid_path("../foo.so") -> true + check_valid_path("foo.so") -> false + @endcode + */ +bool check_valid_path(const char *path, size_t len) +{ + size_t prefix= my_strcspn(files_charset_info, path, path + len, FN_DIRSEP); + return prefix < len; +} + + /**************************************************************************** Value type thunks, allows the C world to play in the C++ world ****************************************************************************/ @@ -492,7 +512,8 @@ static my_bool read_mysql_plugin_info(struct st_plugin_dl *plugin_dl, if (!cur) { free_plugin_mem(plugin_dl); - report_error(report, ER_OUTOFMEMORY, plugin_dl->dl.length); + report_error(report, ER_OUTOFMEMORY, + static_cast<int>(plugin_dl.dl.length)); DBUG_RETURN(TRUE); } /* @@ -617,7 +638,8 @@ static my_bool read_maria_plugin_info(struct st_plugin_dl *plugin_dl, if (!cur) { free_plugin_mem(plugin_dl); - report_error(report, ER_OUTOFMEMORY, plugin_dl->dl.length); + report_error(report, ER_OUTOFMEMORY, + static_cast<int>(plugin_dl.dl.length)); DBUG_RETURN(TRUE); } /* @@ -648,13 +670,15 @@ static st_plugin_dl *plugin_dl_add(const LEX_STRING *dl, int report) struct st_plugin_dl *tmp, plugin_dl; void *sym; DBUG_ENTER("plugin_dl_add"); + DBUG_PRINT("enter", ("dl->str: '%s', dl->length: %d", + dl->str, (int) dl->length)); plugin_dir_len= strlen(opt_plugin_dir); /* Ensure that the dll doesn't have a path. This is done to ensure that only approved libraries from the plugin directory are used (to make this even remotely secure). */ - if (my_strchr(files_charset_info, dl->str, dl->str + dl->length, FN_LIBCHAR) || + if (check_valid_path(dl->str, dl->length) || check_string_char_length((LEX_STRING *) dl, "", NAME_CHAR_LEN, system_charset_info, 1) || plugin_dir_len + dl->length + 1 >= FN_REFLEN) @@ -729,7 +753,8 @@ static st_plugin_dl *plugin_dl_add(const LEX_STRING *dl, int report) if (! (plugin_dl.dl.str= (char*) my_malloc(plugin_dl.dl.length, MYF(0)))) { free_plugin_mem(&plugin_dl); - report_error(report, ER_OUTOFMEMORY, plugin_dl.dl.length); + report_error(report, ER_OUTOFMEMORY, + static_cast<int>(plugin_dl.dl.length)); DBUG_RETURN(0); } plugin_dl.dl.length= copy_and_convert(plugin_dl.dl.str, plugin_dl.dl.length, @@ -740,7 +765,8 @@ static st_plugin_dl *plugin_dl_add(const LEX_STRING *dl, int report) if (! (tmp= plugin_dl_insert_or_reuse(&plugin_dl))) { free_plugin_mem(&plugin_dl); - report_error(report, ER_OUTOFMEMORY, sizeof(struct st_plugin_dl)); + report_error(report, ER_OUTOFMEMORY, + static_cast<int>(sizeof(struct st_plugin_dl))); DBUG_RETURN(0); } DBUG_RETURN(tmp); @@ -1014,6 +1040,7 @@ static bool plugin_add(MEM_ROOT *tmp_root, tmp.name.length= name_len; tmp.ref_count= 0; tmp.state= PLUGIN_IS_UNINITIALIZED; + tmp.load_option= PLUGIN_ON; if (test_plugin_options(tmp_root, &tmp, argc, argv)) tmp.state= PLUGIN_IS_DISABLED; @@ -1460,7 +1487,7 @@ int plugin_init(int *argc, char **argv, int flags) tmp.name.str= (char *)plugin->name; tmp.name.length= strlen(plugin->name); tmp.state= 0; - tmp.is_mandatory= mandatory; + tmp.load_option= mandatory ? PLUGIN_FORCE : PLUGIN_ON; /* If the performance schema is compiled in, @@ -1479,7 +1506,7 @@ int plugin_init(int *argc, char **argv, int flags) to work, by using '--skip-performance-schema' (the plugin) */ if (!my_strcasecmp(&my_charset_latin1, plugin->name, "PERFORMANCE_SCHEMA")) - tmp.is_mandatory= true; + tmp.load_option= PLUGIN_FORCE; free_root(&tmp_root, MYF(MY_MARK_BLOCKS_FREE)); if (test_plugin_options(&tmp_root, &tmp, argc, argv)) @@ -1557,7 +1584,8 @@ int plugin_init(int *argc, char **argv, int flags) while ((plugin_ptr= *(--reap))) { mysql_mutex_unlock(&LOCK_plugin); - if (plugin_ptr->is_mandatory) + if (plugin_ptr->load_option == PLUGIN_FORCE || + plugin_ptr->load_option == PLUGIN_FORCE_PLUS_PERMANENT) reaped_mandatory_plugin= TRUE; plugin_deinitialize(plugin_ptr, true); mysql_mutex_lock(&LOCK_plugin); @@ -1961,7 +1989,11 @@ bool mysql_install_plugin(THD *thd, const LEX_STRING *name, const LEX_STRING *dl mysql_mutex_lock(&LOCK_plugin); mysql_rwlock_wrlock(&LOCK_system_variables_hash); - my_load_defaults(MYSQL_CONFIG_NAME, load_default_groups, &argc, &argv, NULL); + if (my_load_defaults(MYSQL_CONFIG_NAME, load_default_groups, &argc, &argv, NULL)) + { + report_error(REPORT_TO_USER, ER_PLUGIN_IS_NOT_LOADED, name->str); + goto err; + } error= plugin_add(thd->mem_root, name, dl, &argc, argv, REPORT_TO_USER); if (argv) free_defaults(argv); @@ -2073,6 +2105,11 @@ bool mysql_uninstall_plugin(THD *thd, const LEX_STRING *name) my_error(ER_SP_DOES_NOT_EXIST, MYF(0), "PLUGIN", name->str); goto err; } + if (plugin->load_option == PLUGIN_FORCE_PLUS_PERMANENT) + { + my_error(ER_PLUGIN_IS_PERMANENT, MYF(0), name->str); + goto err; + } plugin->state= PLUGIN_IS_DELETED; if (plugin->ref_count) @@ -3283,7 +3320,8 @@ static int construct_options(MEM_ROOT *mem_root, struct st_plugin_int *tmp, plugin_dash.length + 1); strxmov(plugin_name_with_prefix_ptr, plugin_dash.str, plugin_name_ptr, NullS); - if (!tmp->is_mandatory) + if (tmp->load_option != PLUGIN_FORCE && + tmp->load_option != PLUGIN_FORCE_PLUS_PERMANENT) { /* support --skip-plugin-foo syntax */ options[0].name= plugin_name_ptr; @@ -3543,7 +3581,8 @@ static int test_plugin_options(MEM_ROOT *tmp_root, struct st_plugin_int *tmp, { struct sys_var_chain chain= { NULL, NULL }; bool disable_plugin; - enum_plugin_load_policy plugin_load_policy= tmp->is_mandatory ? PLUGIN_FORCE : PLUGIN_ON; + enum_plugin_load_option plugin_load_option= tmp->load_option; + MEM_ROOT *mem_root= alloc_root_inited(&tmp->mem_root) ? &tmp->mem_root : &plugin_mem_root; st_mysql_sys_var **opt; @@ -3557,13 +3596,11 @@ static int test_plugin_options(MEM_ROOT *tmp_root, struct st_plugin_int *tmp, DBUG_ENTER("test_plugin_options"); DBUG_ASSERT(tmp->plugin && tmp->name.str); -#ifdef WITH_NDBCLUSTER_STORAGE_ENGINE /* The 'ndbcluster' storage engines is always disabled by default. */ if (!my_strcasecmp(&my_charset_latin1, tmp->name.str, "ndbcluster")) - plugin_load_policy= PLUGIN_OFF; -#endif + plugin_load_option= PLUGIN_OFF; for (opt= tmp->plugin->system_vars; opt && *opt; opt++) count+= 2; /* --{plugin}-{optname} and --plugin-{plugin}-{optname} */ @@ -3587,8 +3624,9 @@ static int test_plugin_options(MEM_ROOT *tmp_root, struct st_plugin_int *tmp, We adjust the default value to account for the hardcoded exceptions we have set for the federated and ndbcluster storage engines. */ - if (!tmp->is_mandatory) - opts[0].def_value= opts[1].def_value= plugin_load_policy; + if (tmp->load_option != PLUGIN_FORCE && + tmp->load_option != PLUGIN_FORCE_PLUS_PERMANENT) + opts[0].def_value= opts[1].def_value= plugin_load_option; error= handle_options(argc, &argv, opts, NULL); (*argc)++; /* add back one for the program name */ @@ -3603,12 +3641,13 @@ static int test_plugin_options(MEM_ROOT *tmp_root, struct st_plugin_int *tmp, Set plugin loading policy from option value. First element in the option list is always the <plugin name> option value. */ - if (!tmp->is_mandatory) - plugin_load_policy= (enum_plugin_load_policy)*(ulong*)opts[0].value; + if (tmp->load_option != PLUGIN_FORCE && + tmp->load_option != PLUGIN_FORCE_PLUS_PERMANENT) + plugin_load_option= (enum_plugin_load_option) *(ulong*) opts[0].value; } - disable_plugin= (plugin_load_policy == PLUGIN_OFF); - tmp->is_mandatory= (plugin_load_policy == PLUGIN_FORCE); + disable_plugin= (plugin_load_option == PLUGIN_OFF); + tmp->load_option= plugin_load_option; /* If the plugin is disabled it should not be initialized. |