Commit 5b92c4ec authored by vasil's avatar vasil

branches/5.1:

Fix Bug#34053:
* In CREATE TABLE and DROP TABLE check whether the table in question is one
  of the magic innodb_monitor tables and whether the user has enough rights
  to mess with it before doing anything else.
* Implement a mysql-test testcase.

Approved by:	Heikki
parent 44a1a6ba
...@@ -44,6 +44,10 @@ have disabled the InnoDB inlining in this file. */ ...@@ -44,6 +44,10 @@ have disabled the InnoDB inlining in this file. */
/* This is needed because of Bug #3596. Let us hope that pthread_mutex_t /* 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. */ is defined the same in both builds: the MySQL server and the InnoDB plugin. */
extern pthread_mutex_t LOCK_thread_count; 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 */ #endif /* MYSQL_SERVER */
/** to protect innobase_open_files */ /** to protect innobase_open_files */
...@@ -4645,6 +4649,12 @@ innodb_check_for_record_too_big_error( ...@@ -4645,6 +4649,12 @@ innodb_check_for_record_too_big_error(
} }
} }
/* 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. */ Creates a table definition to an InnoDB database. */
static static
...@@ -4681,6 +4691,12 @@ create_table_def( ...@@ -4681,6 +4691,12 @@ create_table_def(
DBUG_ENTER("create_table_def"); DBUG_ENTER("create_table_def");
DBUG_PRINT("enter", ("table_name: %s", table_name)); 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; n_cols = form->s->fields;
/* We pass 0 as the space id, and determine at a lower level the space /* We pass 0 as the space id, and determine at a lower level the space
...@@ -5221,6 +5237,14 @@ ha_innobase::delete_table( ...@@ -5221,6 +5237,14 @@ ha_innobase::delete_table(
DBUG_ENTER("ha_innobase::delete_table"); 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 /* Get the transaction associated with the current thd, or create one
if not yet created */ if not yet created */
...@@ -5254,11 +5278,6 @@ ha_innobase::delete_table( ...@@ -5254,11 +5278,6 @@ ha_innobase::delete_table(
assert(name_len < 1000); 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 */ /* Drop the table in InnoDB */
error = row_drop_table_for_mysql(norm_name, trx, error = row_drop_table_for_mysql(norm_name, trx,
......
...@@ -464,6 +464,16 @@ row_check_table_for_mysql( ...@@ -464,6 +464,16 @@ row_check_table_for_mysql(
row_prebuilt_t* prebuilt); /* in: prebuilt struct in MySQL row_prebuilt_t* prebuilt); /* in: prebuilt struct in MySQL
handle */ 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 /* A struct describing a place for an individual column in the MySQL
row format which is presented to the table handler in ha_innobase. row format which is presented to the table handler in ha_innobase.
This template struct is used to speed up row transformations between This template struct is used to speed up row transformations between
......
SET storage_engine=InnoDB;
#
# 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
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;
CREATE TABLE innodb_monitorx (a INT) ENGINE=INNODB;
DROP TABLE innodb_monitorx;
CREATE TABLE innodb_monito (a INT) ENGINE=INNODB;
DROP TABLE innodb_monito;
CREATE TABLE xinnodb_monitor (a INT) ENGINE=INNODB;
DROP TABLE xinnodb_monitor;
CREATE TABLE nnodb_monitor (a INT) ENGINE=INNODB;
DROP TABLE nnodb_monitor;
-- 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;
DROP USER 'shane'@'localhost';
-- disconnect con1
...@@ -57,6 +57,12 @@ static const char S_innodb_tablespace_monitor[] = "innodb_tablespace_monitor"; ...@@ -57,6 +57,12 @@ 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_table_monitor[] = "innodb_table_monitor";
static const char S_innodb_mem_validate[] = "innodb_mem_validate"; 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. */ Determine if the given name is a name reserved for MySQL system tables. */
static static
...@@ -1809,9 +1815,7 @@ row_create_table_for_mysql( ...@@ -1809,9 +1815,7 @@ row_create_table_for_mysql(
table_name++; table_name++;
table_name_len = strlen(table_name) + 1; table_name_len = strlen(table_name) + 1;
if (table_name_len == sizeof S_innodb_monitor if (STR_EQ(table_name, table_name_len, S_innodb_monitor)) {
&& !memcmp(table_name, S_innodb_monitor,
sizeof S_innodb_monitor)) {
/* Table equals "innodb_monitor": /* Table equals "innodb_monitor":
start monitor prints */ start monitor prints */
...@@ -1822,28 +1826,24 @@ row_create_table_for_mysql( ...@@ -1822,28 +1826,24 @@ row_create_table_for_mysql(
of InnoDB monitor prints */ of InnoDB monitor prints */
os_event_set(srv_lock_timeout_thread_event); os_event_set(srv_lock_timeout_thread_event);
} else if (table_name_len == sizeof S_innodb_lock_monitor } else if (STR_EQ(table_name, table_name_len,
&& !memcmp(table_name, S_innodb_lock_monitor, S_innodb_lock_monitor)) {
sizeof S_innodb_lock_monitor)) {
srv_print_innodb_monitor = TRUE; srv_print_innodb_monitor = TRUE;
srv_print_innodb_lock_monitor = TRUE; srv_print_innodb_lock_monitor = TRUE;
os_event_set(srv_lock_timeout_thread_event); os_event_set(srv_lock_timeout_thread_event);
} else if (table_name_len == sizeof S_innodb_tablespace_monitor } else if (STR_EQ(table_name, table_name_len,
&& !memcmp(table_name, S_innodb_tablespace_monitor, S_innodb_tablespace_monitor)) {
sizeof S_innodb_tablespace_monitor)) {
srv_print_innodb_tablespace_monitor = TRUE; srv_print_innodb_tablespace_monitor = TRUE;
os_event_set(srv_lock_timeout_thread_event); os_event_set(srv_lock_timeout_thread_event);
} else if (table_name_len == sizeof S_innodb_table_monitor } else if (STR_EQ(table_name, table_name_len,
&& !memcmp(table_name, S_innodb_table_monitor, S_innodb_table_monitor)) {
sizeof S_innodb_table_monitor)) {
srv_print_innodb_table_monitor = TRUE; srv_print_innodb_table_monitor = TRUE;
os_event_set(srv_lock_timeout_thread_event); os_event_set(srv_lock_timeout_thread_event);
} else if (table_name_len == sizeof S_innodb_mem_validate } else if (STR_EQ(table_name, table_name_len,
&& !memcmp(table_name, S_innodb_mem_validate, S_innodb_mem_validate)) {
sizeof S_innodb_mem_validate)) {
/* We define here a debugging feature intended for /* We define here a debugging feature intended for
developers */ developers */
...@@ -4130,3 +4130,33 @@ row_check_table_for_mysql( ...@@ -4130,3 +4130,33 @@ row_check_table_for_mysql(
return(ret); 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);
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment