From 736449d30ffb2ec71bd700ac84eb38ba30bb662c Mon Sep 17 00:00:00 2001 From: Vladislav Vaintroub Date: Tue, 21 May 2024 16:03:13 +0200 Subject: [PATCH] MDEV-34205: ASAN stack buffer overflow in strxnmov() in frm_file_exists Correct the second parameter for strxnmov to prevent potential buffer overflows. The second parameter must be one less than the size of the input buffer to avoid writing past the end of the buffer. While the second parameter is usually correct, there are exceptions that need fixing. This commit addresses the issue within frm_file_exists() and other affected places. --- mysql-test/main/drop.result | 5 +++++ mysql-test/main/drop.test | 6 ++++++ sql/handler.cc | 2 +- sql/sql_parse.cc | 2 +- sql/sql_table.cc | 2 +- sql/sys_vars.cc | 2 +- storage/innobase/handler/ha_innodb.cc | 2 +- 7 files changed, 16 insertions(+), 5 deletions(-) diff --git a/mysql-test/main/drop.result b/mysql-test/main/drop.result index d50ffabc9fa..710986fa1ec 100644 --- a/mysql-test/main/drop.result +++ b/mysql-test/main/drop.result @@ -256,3 +256,8 @@ drop database mysqltest; Warnings: Note 1008 Can't drop database 'mysqltest'; database doesn't exist set @@session.sql_if_exists=0; +# +# MDEV-34205 ASAN stack-buffer-overflow in strxnmov | frm_file_exists +# +DROP TABLE `##################################################_long`.`#################################################_long`; +ERROR 42S02: Unknown table '##################################################_long.#########################################...' diff --git a/mysql-test/main/drop.test b/mysql-test/main/drop.test index 5185ce30db0..6b926d3f0c1 100644 --- a/mysql-test/main/drop.test +++ b/mysql-test/main/drop.test @@ -361,3 +361,9 @@ drop table mysqltest.does_not_exists; drop database mysqltest; drop database mysqltest; set @@session.sql_if_exists=0; + +--echo # +--echo # MDEV-34205 ASAN stack-buffer-overflow in strxnmov | frm_file_exists +--echo # +--error ER_BAD_TABLE_ERROR +DROP TABLE `##################################################_long`.`#################################################_long`; diff --git a/sql/handler.cc b/sql/handler.cc index 42e1c3e7212..3acc0246aab 100644 --- a/sql/handler.cc +++ b/sql/handler.cc @@ -4356,7 +4356,7 @@ void handler::print_error(int error, myf errflag) if (error < HA_ERR_FIRST && bas_ext()[0]) { char buff[FN_REFLEN]; - strxnmov(buff, sizeof(buff), + strxnmov(buff, sizeof(buff)-1, table_share->normalized_path.str, bas_ext()[0], NULL); my_error(textno, errflag, buff, error); } diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index e458cd51dde..b071c74b245 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -9564,7 +9564,7 @@ sql_kill_user(THD *thd, LEX_USER *user, killed_state state) break; case ER_KILL_DENIED_ERROR: char buf[DEFINER_LENGTH+1]; - strxnmov(buf, sizeof(buf), user->user.str, "@", user->host.str, NULL); + strxnmov(buf, sizeof(buf)-1, user->user.str, "@", user->host.str, NULL); my_printf_error(ER_KILL_DENIED_ERROR, ER_THD(thd, ER_CANNOT_USER), MYF(0), "KILL USER", buf); break; diff --git a/sql/sql_table.cc b/sql/sql_table.cc index 7941f1de78c..1ef0a6e3bef 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -1906,7 +1906,7 @@ bool mysql_write_frm(ALTER_PARTITION_PARAM_TYPE *lpt, uint flags) */ build_table_filename(path, sizeof(path) - 1, lpt->alter_info->db.str, lpt->alter_info->table_name.str, "", 0); - strxnmov(frm_name, sizeof(frm_name), path, reg_ext, NullS); + strxnmov(frm_name, sizeof(frm_name)-1, path, reg_ext, NullS); /* When we are changing to use new frm file we need to ensure that we don't collide with another thread in process to open the frm file. diff --git a/sql/sys_vars.cc b/sql/sys_vars.cc index 9a4180ae000..8ccd1bb235e 100644 --- a/sql/sys_vars.cc +++ b/sql/sys_vars.cc @@ -4655,7 +4655,7 @@ bool Sys_var_timestamp::on_check_access_session(THD *thd) const break; } char buf[1024]; - strxnmov(buf, sizeof(buf), "--secure-timestamp=", + strxnmov(buf, sizeof(buf)-1, "--secure-timestamp=", secure_timestamp_levels[opt_secure_timestamp], NULL); my_error(ER_OPTION_PREVENTS_STATEMENT, MYF(0), buf); return true; diff --git a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc index ff928a7d92a..7bed0ed73eb 100644 --- a/storage/innobase/handler/ha_innodb.cc +++ b/storage/innobase/handler/ha_innodb.cc @@ -13313,7 +13313,7 @@ ha_innobase::discard_or_import_tablespace( static bool frm_file_exists(const char *path) { char buff[FN_REFLEN]; - strxnmov(buff, FN_REFLEN, path, reg_ext, NullS); + strxnmov(buff, sizeof(buff)-1, path, reg_ext, NullS); return !access(buff, F_OK); }