Index: mysql-test/innodb_bug34053.result =================================================================== --- mysql-test/innodb_bug34053.result (revision 0) +++ mysql-test/innodb_bug34053.result (revision 0) @@ -0,0 +1 @@ +SET storage_engine=InnoDB; Index: mysql-test/innodb_bug34053.test =================================================================== --- mysql-test/innodb_bug34053.test (revision 0) +++ mysql-test/innodb_bug34053.test (revision 0) @@ -0,0 +1,44 @@ +# +# Make sure http://bugs.mysql.com/34053 remains fixed. +# + +-- source include/have_innodb.inc + +SET storage_engine=InnoDB; + +# we do not really care about what gets printed, we are only +# interested in getting success or failure according to our +# expectations +-- disable_query_log +-- disable_result_log + +#-- disable_warnings +#DROP TABLE IF EXISTS t1, t2, t3, t4, t5_nontrans; +#-- enable_warnings + +GRANT USAGE ON *.* TO 'shane'@'localhost' IDENTIFIED BY '12345'; +FLUSH PRIVILEGES; + +-- connect (con1,localhost,shane,12345,) + +-- connection con1 +-- error ER_SPECIFIC_ACCESS_DENIED_ERROR +CREATE TABLE innodb_monitor (a INT) ENGINE=INNODB; +-- error ER_SPECIFIC_ACCESS_DENIED_ERROR +CREATE TABLE innodb_mem_validate (a INT) ENGINE=INNODB; + +-- connection default +CREATE TABLE innodb_monitor (a INT) ENGINE=INNODB; +CREATE TABLE innodb_mem_validate (a INT) ENGINE=INNODB; + +-- connection con1 +-- error ER_SPECIFIC_ACCESS_DENIED_ERROR +DROP TABLE innodb_monitor; +-- error ER_SPECIFIC_ACCESS_DENIED_ERROR +DROP TABLE innodb_mem_validate; + +-- connection default +DROP TABLE innodb_monitor; +DROP TABLE innodb_mem_validate; + +-- disconnect con1 Index: handler/ha_innodb.cc =================================================================== --- handler/ha_innodb.cc (revision 2271) +++ handler/ha_innodb.cc (working copy) @@ -41,12 +41,16 @@ have disabled the InnoDB inlining in thi #include #ifndef MYSQL_SERVER /* This is needed because of Bug #3596. Let us hope that pthread_mutex_t is defined the same in both builds: the MySQL server and the InnoDB plugin. */ extern pthread_mutex_t LOCK_thread_count; + +/* this is defined in mysql_priv.h inside #ifdef MYSQL_SERVER +but we need it here */ +bool check_global_access(THD *thd, ulong want_access); #endif /* MYSQL_SERVER */ /** to protect innobase_open_files */ static pthread_mutex_t innobase_share_mutex; /** to force correct commit order in binlog */ static pthread_mutex_t prepare_commit_mutex; @@ -4642,12 +4646,18 @@ innodb_check_for_record_too_big_error( = page_get_free_space_of_empty_noninline(comp) / 2; my_error(ER_TOO_BIG_ROWSIZE, MYF(0), max_row_size); } } +/* limit innodb monitor access to users with PROCESS privilege. +See http://bugs.mysql.com/32710 for expl. why we choose PROCESS. */ +#define IS_MAGIC_TABLE_AND_USER_DENIED_ACCESS(table_name, thd) \ + (row_is_magic_monitor_table(table_name) \ + && check_global_access(thd, PROCESS_ACL)) + /********************************************************************* Creates a table definition to an InnoDB database. */ static int create_table_def( /*=============*/ @@ -4678,12 +4688,18 @@ create_table_def( ulint charset_no; ulint i; DBUG_ENTER("create_table_def"); DBUG_PRINT("enter", ("table_name: %s", table_name)); + ut_a(trx->mysql_thd != NULL); + if (IS_MAGIC_TABLE_AND_USER_DENIED_ACCESS(table_name, + (THD*) trx->mysql_thd)) { + DBUG_RETURN(HA_ERR_GENERIC); + } + n_cols = form->s->fields; /* We pass 0 as the space id, and determine at a lower level the space id where to store the table */ table = dict_mem_table_create(table_name, 0, n_cols, flags); @@ -5218,12 +5234,20 @@ ha_innobase::delete_table( trx_t* trx; THD *thd = ha_thd(); char norm_name[1000]; DBUG_ENTER("ha_innobase::delete_table"); + /* Strangely, MySQL passes the table name without the '.frm' + extension, in contrast to ::create */ + normalize_table_name(norm_name, name); + + if (IS_MAGIC_TABLE_AND_USER_DENIED_ACCESS(norm_name, thd)) { + DBUG_RETURN(HA_ERR_GENERIC); + } + /* Get the transaction associated with the current thd, or create one if not yet created */ parent_trx = check_trx_exists(thd); /* In case MySQL calls this in the middle of a SELECT query, release @@ -5251,17 +5275,12 @@ ha_innobase::delete_table( } name_len = strlen(name); assert(name_len < 1000); - /* Strangely, MySQL passes the table name without the '.frm' - extension, in contrast to ::create */ - - normalize_table_name(norm_name, name); - /* Drop the table in InnoDB */ error = row_drop_table_for_mysql(norm_name, trx, thd_sql_command(thd) == SQLCOM_DROP_DB); Index: include/row0mysql.h =================================================================== --- include/row0mysql.h (revision 2272) +++ include/row0mysql.h (working copy) @@ -461,12 +461,22 @@ ulint row_check_table_for_mysql( /*======================*/ /* out: DB_ERROR or DB_SUCCESS */ row_prebuilt_t* prebuilt); /* in: prebuilt struct in MySQL handle */ +/************************************************************************* +Determines if a table is a magic monitor table. */ + +ibool +row_is_magic_monitor_table( +/*=======================*/ + /* out: TRUE if monitor table */ + const char* table_name); /* in: name of the table, in the + form database/table_name */ + /* A struct describing a place for an individual column in the MySQL row format which is presented to the table handler in ha_innobase. This template struct is used to speed up row transformations between Innobase and MySQL. */ typedef struct mysql_row_templ_struct mysql_row_templ_t; Index: row/row0mysql.c =================================================================== --- row/row0mysql.c (revision 2272) +++ row/row0mysql.c (working copy) @@ -54,12 +54,18 @@ ibool row_mysql_drop_list_inited = FALSE static const char S_innodb_monitor[] = "innodb_monitor"; static const char S_innodb_lock_monitor[] = "innodb_lock_monitor"; static const char S_innodb_tablespace_monitor[] = "innodb_tablespace_monitor"; static const char S_innodb_table_monitor[] = "innodb_table_monitor"; static const char S_innodb_mem_validate[] = "innodb_mem_validate"; +/* Evaluates to true if str1 equals str2_onstack, used for comparing +the above strings. */ +#define STR_EQ(str1, str1_len, str2_onstack) \ + ((str1_len) == sizeof(str2_onstack) \ + && memcmp(str1, str2_onstack, sizeof(str2_onstack)) == 0) + /*********************************************************************** Determine if the given name is a name reserved for MySQL system tables. */ static ibool row_mysql_is_system_table( /*======================*/ @@ -1806,47 +1812,41 @@ row_create_table_for_mysql( ignore the database name prefix in the comparisons. */ table_name = strchr(table->name, '/'); ut_a(table_name); table_name++; table_name_len = strlen(table_name) + 1; - if (table_name_len == sizeof S_innodb_monitor - && !memcmp(table_name, S_innodb_monitor, - sizeof S_innodb_monitor)) { + if (STR_EQ(table_name, table_name_len, S_innodb_monitor)) { /* Table equals "innodb_monitor": start monitor prints */ srv_print_innodb_monitor = TRUE; /* The lock timeout monitor thread also takes care of InnoDB monitor prints */ os_event_set(srv_lock_timeout_thread_event); - } else if (table_name_len == sizeof S_innodb_lock_monitor - && !memcmp(table_name, S_innodb_lock_monitor, - sizeof S_innodb_lock_monitor)) { + } else if (STR_EQ(table_name, table_name_len, + S_innodb_lock_monitor)) { srv_print_innodb_monitor = TRUE; srv_print_innodb_lock_monitor = TRUE; os_event_set(srv_lock_timeout_thread_event); - } else if (table_name_len == sizeof S_innodb_tablespace_monitor - && !memcmp(table_name, S_innodb_tablespace_monitor, - sizeof S_innodb_tablespace_monitor)) { + } else if (STR_EQ(table_name, table_name_len, + S_innodb_tablespace_monitor)) { srv_print_innodb_tablespace_monitor = TRUE; os_event_set(srv_lock_timeout_thread_event); - } else if (table_name_len == sizeof S_innodb_table_monitor - && !memcmp(table_name, S_innodb_table_monitor, - sizeof S_innodb_table_monitor)) { + } else if (STR_EQ(table_name, table_name_len, + S_innodb_table_monitor)) { srv_print_innodb_table_monitor = TRUE; os_event_set(srv_lock_timeout_thread_event); - } else if (table_name_len == sizeof S_innodb_mem_validate - && !memcmp(table_name, S_innodb_mem_validate, - sizeof S_innodb_mem_validate)) { + } else if (STR_EQ(table_name, table_name_len, + S_innodb_mem_validate)) { /* We define here a debugging feature intended for developers */ fputs("Validating InnoDB memory:\n" "to use this feature you must compile InnoDB with\n" "UNIV_MEM_DEBUG defined in univ.i and" @@ -4127,6 +4127,36 @@ row_check_table_for_mysql( mutex_exit(&kernel_mutex); prebuilt->trx->op_info = ""; return(ret); } + +/************************************************************************* +Determines if a table is a magic monitor table. */ + +ibool +row_is_magic_monitor_table( +/*=======================*/ + /* out: TRUE if monitor table */ + const char* table_name) /* in: name of the table, in the + form database/table_name */ +{ + const char* name; /* table_name without database/ */ + ulint len; + + name = strchr(table_name, '/'); + ut_a(name != NULL); + name++; + len = strlen(name) + 1; + + if (STR_EQ(name, len, S_innodb_monitor) + || STR_EQ(name, len, S_innodb_lock_monitor) + || STR_EQ(name, len, S_innodb_tablespace_monitor) + || STR_EQ(name, len, S_innodb_table_monitor) + || STR_EQ(name, len, S_innodb_mem_validate)) { + + return(TRUE); + } + + return(FALSE); +}