From b86a2f03b6a9a0b5e222fb2f52b07c85c491479e Mon Sep 17 00:00:00 2001 From: Yuchen Pei Date: Mon, 6 May 2024 14:46:18 +1000 Subject: [PATCH] MDEV-32640 Reset thd->lex->mi.connection_name.str towards the end of mysql_execute_command Reset the connection_name to contain a null string, if the pointer points to the same space as that of the system variable default_master_connection. We do this because the system variable may be updated which could free the pointer and create a new one, causing use-after-free for re-execution of prepared statements and stored procedures where the LEX may be reused. This allows connection_name to be set again be to the system variable pointer in the next call of this function (see earlier in this function), after any possible updates to the system variable. --- mysql-test/suite/sys_vars/r/mdev_32640.result | 15 +++++++++++++++ mysql-test/suite/sys_vars/t/mdev_32640.test | 18 ++++++++++++++++++ sql/sql_parse.cc | 18 ++++++++++++++++++ 3 files changed, 51 insertions(+) create mode 100644 mysql-test/suite/sys_vars/r/mdev_32640.result create mode 100644 mysql-test/suite/sys_vars/t/mdev_32640.test diff --git a/mysql-test/suite/sys_vars/r/mdev_32640.result b/mysql-test/suite/sys_vars/r/mdev_32640.result new file mode 100644 index 00000000000..ea93f3a7c4a --- /dev/null +++ b/mysql-test/suite/sys_vars/r/mdev_32640.result @@ -0,0 +1,15 @@ +PREPARE s_1 FROM 'SHOW RELAYLOG EVENTS'; +/* 1 */ SET default_master_connection='MASTER'; +/* 1 */ EXECUTE s_1; +ERROR HY000: There is no master connection 'MASTER' +/* 2 */ SET default_master_connection='MASTER'; +/* 2 */ EXECUTE s_1; +ERROR HY000: There is no master connection 'MASTER' +create procedure p() SHOW RELAYLOG EVENTS; +/* 1 */ SET default_master_connection='MASTER'; +/* 1 */ call p; +ERROR HY000: There is no master connection 'MASTER' +/* 2 */ SET default_master_connection='MASTER'; +/* 2 */ call p; +ERROR HY000: There is no master connection 'MASTER' +drop procedure p; diff --git a/mysql-test/suite/sys_vars/t/mdev_32640.test b/mysql-test/suite/sys_vars/t/mdev_32640.test new file mode 100644 index 00000000000..693bb1e9d16 --- /dev/null +++ b/mysql-test/suite/sys_vars/t/mdev_32640.test @@ -0,0 +1,18 @@ +--source include/not_embedded.inc + +PREPARE s_1 FROM 'SHOW RELAYLOG EVENTS'; +/* 1 */ SET default_master_connection='MASTER'; +--error WARN_NO_MASTER_INFO +/* 1 */ EXECUTE s_1; +/* 2 */ SET default_master_connection='MASTER'; +--error WARN_NO_MASTER_INFO +/* 2 */ EXECUTE s_1; + +create procedure p() SHOW RELAYLOG EVENTS; +/* 1 */ SET default_master_connection='MASTER'; +--error WARN_NO_MASTER_INFO +/* 1 */ call p; +/* 2 */ SET default_master_connection='MASTER'; +--error WARN_NO_MASTER_INFO +/* 2 */ call p; +drop procedure p; diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index db99dfe6d21..2eb27c43081 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -5993,6 +5993,24 @@ finish: thd->wsrep_PA_safe= true; #endif /* WITH_WSREP */ + /* + Reset the connection_name to contain a null string, if the + pointer points to the same space as that of the system variable + default_master_connection. + + We do this because the system variable may be updated which could + free the pointer and create a new one, causing use-after-free for + re-execution of prepared statements and stored procedures where + the LEX may be reused. + + This allows connection_name to be set again be to the system + variable pointer in the next call of this function (see earlier in + this function), after any possible updates to the system variable. + */ + if (thd->lex->mi.connection_name.str == + thd->variables.default_master_connection.str) + thd->lex->mi.connection_name= null_clex_str; + if (lex->sql_command != SQLCOM_SET_OPTION) DEBUG_SYNC(thd, "end_of_statement"); DBUG_RETURN(res || thd->is_error());