BUG#32111 - Security Breach via DATA/INDEX DIRECORY and RENAME TABLE

RENAME TABLE against a table with DATA/INDEX DIRECTORY overwrites
the file to which the symlink points.

This is security issue, because it is possible to create a table with
some name in some non-system database and set DATA/INDEX DIRECTORY
to mysql system database. Renaming this table to one of mysql system
tables (e.g. user, host) would overwrite the system table.

Return an error when the file to which the symlink points exist.
parent 5cbe511f
...@@ -84,3 +84,9 @@ t1 CREATE TABLE `t1` ( ...@@ -84,3 +84,9 @@ t1 CREATE TABLE `t1` (
`b` int(11) default NULL `b` int(11) default NULL
) TYPE=MyISAM ) TYPE=MyISAM
drop table t1; drop table t1;
CREATE TABLE t1(a INT)
DATA DIRECTORY='TEST_DIR/var/master-data/mysql'
INDEX DIRECTORY='TEST_DIR/var/master-data/mysql';
RENAME TABLE t1 TO user;
Can't create/write to file 'TEST_DIR/var/master-data/mysql/user.MYI' (Errcode: 17)
DROP TABLE t1;
...@@ -112,3 +112,15 @@ eval alter table t1 index directory="$MYSQL_TEST_DIR/var/log"; ...@@ -112,3 +112,15 @@ eval alter table t1 index directory="$MYSQL_TEST_DIR/var/log";
enable_query_log; enable_query_log;
show create table t1; show create table t1;
drop table t1; drop table t1;
#
# BUG#32111 - Security Breach via DATA/INDEX DIRECORY and RENAME TABLE
#
--replace_result $MYSQL_TEST_DIR TEST_DIR
eval CREATE TABLE t1(a INT)
DATA DIRECTORY='$MYSQL_TEST_DIR/var/master-data/mysql'
INDEX DIRECTORY='$MYSQL_TEST_DIR/var/master-data/mysql';
--replace_result $MYSQL_TEST_DIR TEST_DIR
--error 1
RENAME TABLE t1 TO user;
DROP TABLE t1;
...@@ -120,6 +120,7 @@ int my_rename_with_symlink(const char *from, const char *to, myf MyFlags) ...@@ -120,6 +120,7 @@ int my_rename_with_symlink(const char *from, const char *to, myf MyFlags)
int was_symlink= (!my_disable_symlinks && int was_symlink= (!my_disable_symlinks &&
!my_readlink(link_name, from, MYF(0))); !my_readlink(link_name, from, MYF(0)));
int result=0; int result=0;
int name_is_different;
DBUG_ENTER("my_rename_with_symlink"); DBUG_ENTER("my_rename_with_symlink");
if (!was_symlink) if (!was_symlink)
...@@ -128,6 +129,14 @@ int my_rename_with_symlink(const char *from, const char *to, myf MyFlags) ...@@ -128,6 +129,14 @@ int my_rename_with_symlink(const char *from, const char *to, myf MyFlags)
/* Change filename that symlink pointed to */ /* Change filename that symlink pointed to */
strmov(tmp_name, to); strmov(tmp_name, to);
fn_same(tmp_name,link_name,1); /* Copy dir */ fn_same(tmp_name,link_name,1); /* Copy dir */
name_is_different= strcmp(link_name, tmp_name);
if (name_is_different && !access(tmp_name, F_OK))
{
my_errno= EEXIST;
if (MyFlags & MY_WME)
my_error(EE_CANTCREATEFILE, MYF(0), tmp_name, EEXIST);
DBUG_RETURN(1);
}
/* Create new symlink */ /* Create new symlink */
if (my_symlink(tmp_name, to, MyFlags)) if (my_symlink(tmp_name, to, MyFlags))
...@@ -139,7 +148,7 @@ int my_rename_with_symlink(const char *from, const char *to, myf MyFlags) ...@@ -139,7 +148,7 @@ int my_rename_with_symlink(const char *from, const char *to, myf MyFlags)
the same basename and different directories. the same basename and different directories.
*/ */
if (strcmp(link_name, tmp_name) && my_rename(link_name, tmp_name, MyFlags)) if (name_is_different && my_rename(link_name, tmp_name, MyFlags))
{ {
int save_errno=my_errno; int save_errno=my_errno;
my_delete(to, MyFlags); /* Remove created symlink */ my_delete(to, MyFlags); /* Remove created symlink */
......
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