From 14362356d14b80242d60dceb9b34f988bbcc9945 Mon Sep 17 00:00:00 2001 From: Yuchen Pei Date: Thu, 8 Oct 2026 14:21:20 +1100 Subject: [PATCH] MDEV-41064 Use my_safe_alloca for unescaped json server option string This fixes segv when the option string is longer than thread stack --- mysql-test/main/servers.result | 6 ++++++ mysql-test/main/servers.test | 8 ++++++++ sql/sql_servers.cc | 8 +++++++- 3 files changed, 21 insertions(+), 1 deletion(-) diff --git a/mysql-test/main/servers.result b/mysql-test/main/servers.result index ea7567ecfef..bf96107c945 100644 --- a/mysql-test/main/servers.result +++ b/mysql-test/main/servers.result @@ -200,4 +200,10 @@ show create server s1; Server Create Server s1 CREATE SERVER `s1` FOREIGN DATA WRAPPER `my'sql` OPTIONS (`ho``st` 'va''lue'); drop server s1; +# +# MDEV-41064 MariaDB Server stack overflow when FLUSH PRIVILEGES parses a large JSON value from mysql.servers.Options inside a stored procedure +# +INSERT INTO mysql.servers (Server_name, Options) VALUES ('t1', CONCAT('{"x": "', REPEAT('a', 12000000), '"}')); +FLUSH PRIVILEGES; +DELETE FROM mysql.servers WHERE Server_name = 't1'; # End of 11.8 tests diff --git a/mysql-test/main/servers.test b/mysql-test/main/servers.test index 2e58fc2a4e9..caf619d1b74 100644 --- a/mysql-test/main/servers.test +++ b/mysql-test/main/servers.test @@ -200,4 +200,12 @@ create server s1 foreign data wrapper 'my''sql' options (`ho``st` 'va''lue'); show create server s1; drop server s1; +--echo # +--echo # MDEV-41064 MariaDB Server stack overflow when FLUSH PRIVILEGES parses a large JSON value from mysql.servers.Options inside a stored procedure +--echo # + +INSERT INTO mysql.servers (Server_name, Options) VALUES ('t1', CONCAT('{"x": "', REPEAT('a', 12000000), '"}')); +FLUSH PRIVILEGES; +DELETE FROM mysql.servers WHERE Server_name = 't1'; + --echo # End of 11.8 tests diff --git a/sql/sql_servers.cc b/sql/sql_servers.cc index bc76ea1c370..e6bc5b4f12e 100644 --- a/sql/sql_servers.cc +++ b/sql/sql_servers.cc @@ -421,14 +421,20 @@ static bool parse_server_options_json(FOREIGN_SERVER *server, char *ptr) if (option->value.length) { LEX_CSTRING *optval= &option->value; - char *unescaped= (char *) alloca(optval->length); + char *unescaped= (char *) my_safe_alloca(optval->length); + if (!unescaped) + DBUG_RETURN(TRUE); int len= json_unescape_json(optval->str, optval->str + optval->length, unescaped, unescaped + optval->length); if (len < 0) + { + my_safe_afree(unescaped, optval->length); DBUG_RETURN(TRUE); + } DBUG_ASSERT(len <= (int) optval->length); if (len < (int) optval->length) strncpy((char *) optval->str, unescaped, len); + my_safe_afree(unescaped, optval->length); optval->length= len; } }