diff options
author | Mats Kindahl <mats.kindahl@oracle.com> | 2010-11-04 11:00:59 +0100 |
---|---|---|
committer | Mats Kindahl <mats.kindahl@oracle.com> | 2010-11-04 11:00:59 +0100 |
commit | d817b7cb8af1f0f4754ffd14135a86660a23006d (patch) | |
tree | c5426bf51ab430f6ea8c6d3ff41aed4633f171b9 | |
parent | 69aea87d5f424efc92708a44d0d3753958210610 (diff) | |
download | mariadb-git-d817b7cb8af1f0f4754ffd14135a86660a23006d.tar.gz |
BUG#57108: mysqld crashes when I attempt to install plugin
If a relative path is supplied to option --defaults-file or
--defaults-extra-file, the server will crash when executing
an INSTALL PLUGIN command. The reason is that the defaults
file is initially read relative the current working directory
when the server is started, but when INSTALL PLUGIN is executed,
the server has changed working directory to the data directory.
Since there is no check that the call to my_load_defaults()
inside mysql_install_plugin(), the subsequence call to
free_defaults() will crash the server.
This patch fixes the problem by:
- Prepending the current working directory to the file name when
a relative path is given to the --defaults-file or --defaults-
extra-file option the first time my_load_defaults() is called,
which is just after the server has started in main().
- Adding a check of the return value of my_load_defaults() inside
mysql_install_plugin() and aborting command (with an error) if
an error is returned.
- It also adds a check of the return value for load_defaults in
lib_sql.cc for the embedded server since that was missing.
To test that the relative files for the options --defaults-file and
--defaults-extra-file is handled properly, mysql-test-run.pl is also
changed to not add a --defaults-file option if one is provided in the
tests *.opt file.
-rw-r--r-- | include/my_sys.h | 2 | ||||
-rw-r--r-- | libmysqld/lib_sql.cc | 3 | ||||
-rwxr-xr-x | mysql-test/mysql-test-run.pl | 11 | ||||
-rw-r--r-- | mysql-test/std_data/bug57108.cnf | 95 | ||||
-rw-r--r-- | mysql-test/suite/bugs/r/bug57108.result | 5 | ||||
-rw-r--r-- | mysql-test/suite/bugs/t/bug57108-master.opt | 2 | ||||
-rw-r--r-- | mysql-test/suite/bugs/t/bug57108.test | 12 | ||||
-rw-r--r-- | mysys/default.c | 61 | ||||
-rw-r--r-- | sql/sql_plugin.cc | 6 |
9 files changed, 184 insertions, 13 deletions
diff --git a/include/my_sys.h b/include/my_sys.h index 23c9b2da55f..7b437e2a745 100644 --- a/include/my_sys.h +++ b/include/my_sys.h @@ -256,7 +256,7 @@ extern my_bool my_disable_locking, my_disable_async_io, extern char wild_many,wild_one,wild_prefix; extern const char *charsets_dir; /* from default.c */ -extern char *my_defaults_extra_file; +extern const char *my_defaults_extra_file; extern const char *my_defaults_group_suffix; extern const char *my_defaults_file; diff --git a/libmysqld/lib_sql.cc b/libmysqld/lib_sql.cc index 1c9b773de15..b07ae1de96b 100644 --- a/libmysqld/lib_sql.cc +++ b/libmysqld/lib_sql.cc @@ -506,7 +506,8 @@ int init_embedded_server(int argc, char **argv, char **groups) orig_argc= *argcp; orig_argv= *argvp; - load_defaults("my", (const char **)groups, argcp, argvp); + if (load_defaults("my", (const char **)groups, argcp, argvp)) + return 1; defaults_argc= *argcp; defaults_argv= *argvp; remaining_argc= argc; diff --git a/mysql-test/mysql-test-run.pl b/mysql-test/mysql-test-run.pl index 88719ff5bb2..db9e6eda2bc 100755 --- a/mysql-test/mysql-test-run.pl +++ b/mysql-test/mysql-test-run.pl @@ -4406,7 +4406,13 @@ sub mysqld_arguments ($$$) { my $mysqld= shift; my $extra_opts= shift; - mtr_add_arg($args, "--defaults-file=%s", $path_config_file); + my @defaults = grep(/^--defaults-file=/, @$extra_opts); + if (@defaults > 0) { + mtr_add_arg($args, pop(@defaults)) + } + else { + mtr_add_arg($args, "--defaults-file=%s", $path_config_file); + } # When mysqld is run by a root user(euid is 0), it will fail # to start unless we specify what user to run as, see BUG#30630 @@ -4442,6 +4448,9 @@ sub mysqld_arguments ($$$) { my $found_skip_core= 0; foreach my $arg ( @$extra_opts ) { + # Skip --defaults-file option since it's handled above. + next if $arg =~ /^--defaults-file/; + # Allow --skip-core-file to be set in <testname>-[master|slave].opt file if ($arg eq "--skip-core-file") { diff --git a/mysql-test/std_data/bug57108.cnf b/mysql-test/std_data/bug57108.cnf new file mode 100644 index 00000000000..5fd8c485cf0 --- /dev/null +++ b/mysql-test/std_data/bug57108.cnf @@ -0,0 +1,95 @@ +[mysqld] +open-files-limit=1024 +character-set-server=latin1 +connect-timeout=4711 +log-bin-trust-function-creators=1 +key_buffer_size=1M +sort_buffer=256K +max_heap_table_size=1M +loose-innodb_data_file_path=ibdata1:10M:autoextend +loose-innodb_buffer_pool_size=8M +loose-innodb_write_io_threads=2 +loose-innodb_read_io_threads=2 +loose-innodb_log_buffer_size=1M +loose-innodb_log_file_size=5M +loose-innodb_additional_mem_pool_size=1M +loose-innodb_log_files_in_group=2 +slave-net-timeout=120 +log-bin=mysqld-bin +loose-enable-performance-schema +loose-performance-schema-max-mutex-instances=10000 +loose-performance-schema-max-rwlock-instances=10000 +loose-performance-schema-max-table-instances=500 +loose-performance-schema-max-table-handles=1000 +binlog-direct-non-transactional-updates + +[mysql] +default-character-set=latin1 + +[mysqlshow] +default-character-set=latin1 + +[mysqlimport] +default-character-set=latin1 + +[mysqlcheck] +default-character-set=latin1 + +[mysql_upgrade] +default-character-set=latin1 +tmpdir=/home/bzr/bugs/b57108-5.5-bugteam/mysql-test/var/tmp + +[mysqld.1] +#!run-master-sh +log-bin=master-bin +loose-enable-performance-schema +basedir=/home/bzr/bugs/b57108-5.5-bugteam +tmpdir=/home/bzr/bugs/b57108-5.5-bugteam/mysql-test/var/tmp/mysqld.1 +character-sets-dir=/home/bzr/bugs/b57108-5.5-bugteam/sql/share/charsets +lc-messages-dir=/home/bzr/bugs/b57108-5.5-bugteam/sql/share/ +datadir=/home/bzr/bugs/b57108-5.5-bugteam/mysql-test/var/mysqld.1/data +pid-file=/home/bzr/bugs/b57108-5.5-bugteam/mysql-test/var/run/mysqld.1.pid +#host=localhost +port=13000 +socket=/home/bzr/bugs/b57108-5.5-bugteam/mysql-test/var/tmp/mysqld.1.sock +#log-error=/home/bzr/bugs/b57108-5.5-bugteam/mysql-test/var/log/mysqld.1.err +general_log=1 +general_log_file=/home/bzr/bugs/b57108-5.5-bugteam/mysql-test/var/mysqld.1/mysqld.log +slow_query_log=1 +slow_query_log_file=/home/bzr/bugs/b57108-5.5-bugteam/mysql-test/var/mysqld.1/mysqld-slow.log +#user=root +#password= +server-id=1 +secure-file-priv=/home/bzr/bugs/b57108-5.5-bugteam/mysql-test/var +ssl-ca=/home/bzr/bugs/b57108-5.5-bugteam/mysql-test/std_data/cacert.pem +ssl-cert=/home/bzr/bugs/b57108-5.5-bugteam/mysql-test/std_data/server-cert.pem +ssl-key=/home/bzr/bugs/b57108-5.5-bugteam/mysql-test/std_data/server-key.pem + +[mysqlbinlog] +disable-force-if-open +character-sets-dir=/home/bzr/bugs/b57108-5.5-bugteam/sql/share/charsets + +[ENV] +MASTER_MYPORT=13000 +MASTER_MYSOCK=/home/bzr/bugs/b57108-5.5-bugteam/mysql-test/var/tmp/mysqld.1.sock + +[client] +password= +user=root +port=13000 +host=localhost +socket=/home/bzr/bugs/b57108-5.5-bugteam/mysql-test/var/tmp/mysqld.1.sock + +[mysqltest] +ssl-ca=/home/bzr/bugs/b57108-5.5-bugteam/mysql-test/std_data/cacert.pem +ssl-cert=/home/bzr/bugs/b57108-5.5-bugteam/mysql-test/std_data/client-cert.pem +ssl-key=/home/bzr/bugs/b57108-5.5-bugteam/mysql-test/std_data/client-key.pem +skip-ssl=1 + +[client.1] +password= +user=root +port=13000 +host=localhost +socket=/home/bzr/bugs/b57108-5.5-bugteam/mysql-test/var/tmp/mysqld.1.sock + diff --git a/mysql-test/suite/bugs/r/bug57108.result b/mysql-test/suite/bugs/r/bug57108.result new file mode 100644 index 00000000000..ad60b07a1e3 --- /dev/null +++ b/mysql-test/suite/bugs/r/bug57108.result @@ -0,0 +1,5 @@ +INSTALL PLUGIN example SONAME 'ha_example.so'; +SELECT @@global.connect_timeout AS connect_timeout, @@global.local_infile AS local_infile; +connect_timeout 4711 +local_infile 1 +UNINSTALL PLUGIN example; diff --git a/mysql-test/suite/bugs/t/bug57108-master.opt b/mysql-test/suite/bugs/t/bug57108-master.opt new file mode 100644 index 00000000000..c2ab1c2ead6 --- /dev/null +++ b/mysql-test/suite/bugs/t/bug57108-master.opt @@ -0,0 +1,2 @@ +--defaults-file=std_data/bug57108.cnf +$EXAMPLE_PLUGIN_OPT diff --git a/mysql-test/suite/bugs/t/bug57108.test b/mysql-test/suite/bugs/t/bug57108.test new file mode 100644 index 00000000000..1006a7b30f1 --- /dev/null +++ b/mysql-test/suite/bugs/t/bug57108.test @@ -0,0 +1,12 @@ +--source include/not_windows_embedded.inc +--source include/have_example_plugin.inc + +# Test that we can install a plugin despite the fact that we have +# switched directory after starting the server and am using a relative +# --defaults-file. +--replace_regex /\.dll/.so/ +eval INSTALL PLUGIN example SONAME $HA_EXAMPLE_SO; + +--query_vertical SELECT @@global.connect_timeout AS connect_timeout, @@global.local_infile AS local_infile + +UNINSTALL PLUGIN example; diff --git a/mysys/default.c b/mysys/default.c index 0e0883e1fcf..a57f1150816 100644 --- a/mysys/default.c +++ b/mysys/default.c @@ -66,7 +66,9 @@ const char *args_separator= "----args-separator----"; const char *my_defaults_file=0; const char *my_defaults_group_suffix=0; -char *my_defaults_extra_file=0; +const char *my_defaults_extra_file=0; + +static my_bool defaults_already_read= FALSE; /* Which directories are searched for options (and in which order) */ @@ -140,6 +142,36 @@ static char *remove_end_comment(char *ptr); /* + Expand a file name so that the current working directory is added if + the name is relative. + + RETURNS + 0 All OK + 2 Out of memory or path to long + 3 Not able to get working directory + */ + +static int +fn_expand(const char *filename, const char **filename_var) +{ + char dir[FN_REFLEN], buf[FN_REFLEN]; + const int flags= MY_UNPACK_FILENAME | MY_SAFE_PATH | MY_RELATIVE_PATH; + const char *result_path= NULL; + DBUG_ENTER("fn_expand"); + DBUG_PRINT("enter", ("filename: %s, buf: 0x%lx", filename, (unsigned long) buf)); + if (my_getwd(dir, sizeof(dir), MYF(0))) + DBUG_RETURN(3); + DBUG_PRINT("debug", ("dir: %s", dir)); + if (fn_format(buf, filename, dir, NULL, flags) == NULL || + (result_path= my_strdup(buf, MYF(0))) == NULL) + DBUG_RETURN(2); + DBUG_PRINT("return", ("result: %s", result_path)); + DBUG_ASSERT(result_path != NULL); + *filename_var= result_path; + DBUG_RETURN(0); +} + +/* Process config files in default directories. SYNOPSIS @@ -167,6 +199,7 @@ static char *remove_end_comment(char *ptr); 0 ok 1 given cinf_file doesn't exist 2 out of memory + 3 Can't get current working directory The global variable 'my_defaults_group_suffix' is updated with value for --defaults_group_suffix @@ -189,11 +222,21 @@ int my_search_option_files(const char *conf_file, int *argc, char ***argv, if (! my_defaults_group_suffix) my_defaults_group_suffix= getenv(STRINGIFY_ARG(DEFAULT_GROUP_SUFFIX_ENV)); - if (forced_extra_defaults) - my_defaults_extra_file= (char *) forced_extra_defaults; - - if (forced_default_file) - my_defaults_file= forced_default_file; + if (forced_extra_defaults && !defaults_already_read) + { + int error= fn_expand(forced_extra_defaults, &my_defaults_extra_file); + if (error) + DBUG_RETURN(error); + } + + if (forced_default_file && !defaults_already_read) + { + int error= fn_expand(forced_default_file, &my_defaults_file); + if (error) + DBUG_RETURN(error); + } + + defaults_already_read= TRUE; /* We can only handle 'defaults-group-suffix' if we are called from @@ -236,15 +279,15 @@ int my_search_option_files(const char *conf_file, int *argc, char ***argv, group->type_names[group->count]= 0; } - if (forced_default_file) + if (my_defaults_file) { if ((error= search_default_file_with_ext(func, func_ctx, "", "", - forced_default_file, 0)) < 0) + my_defaults_file, 0)) < 0) goto err; if (error > 0) { fprintf(stderr, "Could not open required defaults file: %s\n", - forced_default_file); + my_defaults_file); goto err; } } diff --git a/sql/sql_plugin.cc b/sql/sql_plugin.cc index 451277712db..0fe89cd3748 100644 --- a/sql/sql_plugin.cc +++ b/sql/sql_plugin.cc @@ -1738,7 +1738,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); |