Skip to content

Commit 422f320

Browse files
committed
MDEV-29409 Buffer overflow in my_wc_mb_filename() on RENAME TABLE
dict_table_rename_in_cache(), dict_table_get_highest_foreign_id(): Reserve sufficient space for the fkid[] buffer, and ensure that the fkid[] will be NUL-terminated. The fkid[] must accommodate both the database name (which is already encoded in my_charset_filename) and the constraint name (which must be converted to my_charset_filename) so that we can check if it is in the format databasename/tablename_ibfk_1 (all encoded in my_charset_filename).
1 parent b260903 commit 422f320

File tree

3 files changed

+33
-6
lines changed

3 files changed

+33
-6
lines changed

mysql-test/suite/innodb/r/foreign_key_not_windows.result

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,14 @@ CREATE TABLE `d255`.`d245` (x INT) ENGINE=InnoDB;
1818
DROP TABLE `d255`.`d250`;
1919
RENAME TABLE `d250#`.`d245` TO `d250#`.`d250`;
2020
RENAME TABLE `d255`.`d250` TO a;
21-
DROP DATABASE `d255`;
2221
DROP TABLE a,t;
22+
#
23+
# MDEV-29409 Buffer overflow in my_wc_mb_filename() on RENAME TABLE
24+
#
25+
CREATE TABLE `d255`.t(a INT PRIMARY KEY)ENGINE=InnoDB;
26+
CREATE TABLE `d255`.u(a INT PRIMARY KEY,
27+
CONSTRAINT `d320` FOREIGN KEY (a) REFERENCES `d255`.t (a)) ENGINE=InnoDB;
28+
RENAME TABLE `d255`.u TO u;
29+
DROP TABLE u;
30+
DROP DATABASE `d255`;
2331
# End of 10.3 tests

mysql-test/suite/innodb/t/foreign_key_not_windows.test

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,24 @@ eval RENAME TABLE `$d255`.`$d245` TO `$d255`.`$d250`;
5454
--replace_result $d250 d250 $d255 d255
5555
eval RENAME TABLE `$d255`.`$d250` TO a;
5656
--replace_result $d255 d255
57-
eval DROP DATABASE `$d255`;
5857
DROP TABLE a,t;
5958

59+
--echo #
60+
--echo # MDEV-29409 Buffer overflow in my_wc_mb_filename() on RENAME TABLE
61+
--echo #
62+
63+
let $d225=#############################################;
64+
let $d320=################################################################;
65+
66+
--replace_result $d255 d255
67+
eval CREATE TABLE `$d255`.t(a INT PRIMARY KEY)ENGINE=InnoDB;
68+
--replace_result $d255 d255 $d320 d320
69+
eval CREATE TABLE `$d255`.u(a INT PRIMARY KEY,
70+
CONSTRAINT `$d320` FOREIGN KEY (a) REFERENCES `$d255`.t (a)) ENGINE=InnoDB;
71+
--replace_result $d255 d255
72+
eval RENAME TABLE `$d255`.u TO u;
73+
DROP TABLE u;
74+
--replace_result $d255 d255
75+
eval DROP DATABASE `$d255`;
76+
6077
--echo # End of 10.3 tests

storage/innobase/dict/dict0dict.cc

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1595,7 +1595,7 @@ dict_table_rename_in_cache(
15951595
in UTF-8 charset. The variable fkid here is used
15961596
to store foreign key constraint name in charset
15971597
my_charset_filename for comparison further below. */
1598-
char fkid[MAX_TABLE_NAME_LEN+20];
1598+
char fkid[MAX_TABLE_NAME_LEN * 2 + 20];
15991599
ibool on_tmp = FALSE;
16001600

16011601
/* The old table name in my_charset_filename is stored
@@ -1629,7 +1629,8 @@ dict_table_rename_in_cache(
16291629
}
16301630
}
16311631

1632-
strncpy(fkid, foreign->id, MAX_TABLE_NAME_LEN);
1632+
strncpy(fkid, foreign->id, (sizeof fkid) - 1);
1633+
fkid[(sizeof fkid) - 1] = '\0';
16331634

16341635
if (strstr(fkid, TEMP_TABLE_PATH_PREFIX) == NULL) {
16351636
innobase_convert_to_filename_charset(
@@ -3671,10 +3672,11 @@ dict_table_get_highest_foreign_id(
36713672
for (dict_foreign_set::iterator it = table->foreign_set.begin();
36723673
it != table->foreign_set.end();
36733674
++it) {
3674-
char fkid[MAX_TABLE_NAME_LEN+20];
3675+
char fkid[MAX_TABLE_NAME_LEN * 2 + 20];
36753676
foreign = *it;
36763677

3677-
strcpy(fkid, foreign->id);
3678+
strncpy(fkid, foreign->id, (sizeof fkid) - 1);
3679+
fkid[(sizeof fkid) - 1] = '\0';
36783680
/* Convert foreign key identifier on dictionary memory
36793681
cache to filename charset. */
36803682
innobase_convert_to_filename_charset(

0 commit comments

Comments
 (0)