Bug #58198 | Read of freed memory when "USE db" and "SHOW PROCESSLIST" | ||
---|---|---|---|
Submitted: | 15 Nov 2010 10:40 | Modified: | 22 Aug 2013 17:04 |
Reporter: | Guilhem Bichot | Email Updates: | |
Status: | Closed | Impact on me: | |
Category: | MySQL Server: General | Severity: | S1 (Critical) |
Version: | 5.1.54,5.5.8,5.6 | OS: | Linux |
Assigned to: | CPU Architecture: | Any |
[15 Nov 2010 10:40]
Guilhem Bichot
[15 Nov 2010 10:47]
MySQL Verification Team
related: bug 53822
[15 Nov 2010 10:50]
MySQL Verification Team
full outputs from valgrind
Attachment: bug58198_5.5.8_valgrind_output.txt (text/plain), 7.40 KiB.
[15 Nov 2010 10:54]
MySQL Verification Team
full outputs from valgrind
Attachment: bug58198_5.1.54_valgrind_output.txt (text/plain), 2.24 KiB.
[15 Nov 2010 20:18]
Guilhem Bichot
Sorry Miguel; here is a working patch: === modified file 'sql/sql_db.cc' --- sql/sql_db.cc 2010-10-21 12:30:57 +0000 +++ sql/sql_db.cc 2010-11-15 20:17:46 +0000 @@ -38,6 +38,7 @@ #ifdef __WIN__ #include <direct.h> #endif +#include "debug_sync.h" #define MAX_DROP_TABLE_Q_LEN 1024 @@ -1291,6 +1292,7 @@ we just call THD::reset_db(). Since THD::reset_db() does not releases the previous database name, we should do it explicitly. */ + DEBUG_SYNC(thd, "before_free_db"); my_free(thd->db); thd->reset_db(new_db_name->str, new_db_name->length); === modified file 'sql/sql_show.cc' --- sql/sql_show.cc 2010-11-03 14:31:27 +0000 +++ sql/sql_show.cc 2010-11-15 10:21:55 +0000 @@ -1818,7 +1818,11 @@ tmp_sctx->host_or_ip : tmp_sctx->host ? tmp_sctx->host : ""); if ((thd_info->db=tmp->db)) // Safe test + { + if (thd_info->thread_id==3) + DEBUG_SYNC(thd, "after_read_db_ptr"); thd_info->db=thd->strdup(thd_info->db); + } thd_info->command=(int) tmp->get_command(); mysql_mutex_lock(&tmp->LOCK_thd_data); if ((mysys_var= tmp->mysys_var))
[16 Nov 2010 5:08]
MySQL Verification Team
Guilhem, Miguel, you need no patches to repeat the bug. Just run in 10 threads: use test use information_schema use mysql show processlist
[17 Nov 2010 11:33]
MySQL Verification Team
Thank you for the feedback.
[7 Jun 2011 12:23]
MySQL Verification Team
I keep hitting this bug. The way I call stored routines is like this: CALL test.p1(); The current database is NULL. This means any connection running show processlist while this sp is running might cause a read of freed memory!
[7 Jun 2011 12:26]
MySQL Verification Team
calling a `database`.`stored_routine`() and show processlist yields this..
Attachment: bug58198_5.5.14_valgrind_stored_routine.txt (text/plain), 2.30 KiB.
[1 Feb 2013 16:26]
MySQL Verification Team
Still affects mysql-trunk(5.7.1) create database if not exists aaaaaaaaaaaaaaa; drop procedure if exists aaaaaaaaaaaaaaa.p1; create procedure aaaaaaaaaaaaaaa.p1() select now(); call aaaaaaaaaaaaaaa.p1(); #in a bunch of threads show processlist; #in one thread. -------------- Invalid read of size 8 at: memcpy@@GLIBC_2.14 (mc_replace_strmem.c:881) by: strmake_root (my_alloc.c:436) by: mysqld_list_processes (sql_show.cc:2081) by: mysql_execute_command (sql_parse.cc:3468) by: mysql_parse (sql_parse.cc:6020) by: dispatch_command (sql_parse.cc:1329) by: do_handle_one_connection(THD*) (sql_connect.cc:977) by: handle_one_connection (sql_connect.cc:893) by: pfs_spawn_thread (pfs.cc:1922) by: start_thread (pthread_create.c:309) by: clone (clone.S:115) Address 0x1a07ed00 is 0 bytes inside a block of size 16 free'd at: free (vg_replace_malloc.c:446) by: mysql_change_db_impl (sql_db.cc:1314) by: mysql_change_db (sql_db.cc:1605) by: sp_head::execute (sp_head.cc:801) by: sp_head::execute_procedure(THD*, List<Item>*) (sp_head.cc:1338) by: mysql_execute_command (sql_parse.cc:4334) by: mysql_parse (sql_parse.cc:6020) by: dispatch_command (sql_parse.cc:1329) by: do_handle_one_connection(THD*) (sql_connect.cc:977) by: handle_one_connection (sql_connect.cc:893) by: pfs_spawn_thread (pfs.cc:1922) by: start_thread (pthread_create.c:309) by: clone (clone.S:115)
[26 Feb 2013 8:09]
MySQL Verification Team
I confirm 5.6.10 is affected. Running mysqld in valgrind, and the following statements in 50 threads gets a problem quick: use test; use information_schema; use mysql; show processlist; ==26055== Invalid read of size 1 ==26055== at 0x4A0B639: __GI_memmove (mc_replace_strmem.c:1027) ==26055== by 0x9161B8: strmake_root (my_alloc.c:436) ==26055== by 0x74FAC9: mysqld_list_processes(THD*, char const*, bool) (sql_class.h:745) ==26055== by 0x71263A: mysql_execute_command(THD*) (sql_parse.cc:3590) ==26055== by 0x7188C7: mysql_parse(THD*, char*, unsigned int, Parser_state*) (sql_parse.cc:6149) ==26055== by 0x7191E6: dispatch_command(enum_server_command, THD*, char*, unsigned int) (sql_parse.cc:1334) ==26055== by 0x71A486: do_command(THD*) (sql_parse.cc:1036) ==26055== by 0x6E4C75: do_handle_one_connection(THD*) (sql_connect.cc:969) ==26055== by 0x6E4D54: handle_one_connection (sql_connect.cc:885) ==26055== by 0x3679C07D13: start_thread (pthread_create.c:309) ==26055== by 0x36798F168C: clone (clone.S:115) ==26055== Address 0x14fb74b2 is 2 bytes inside a block of size 6 free'd ==26055== at 0x4A07786: free (vg_replace_malloc.c:446) ==26055== by 0x6E7656: mysql_change_db_impl(THD*, st_mysql_lex_string*, unsigned long, charset_info_st const*) (sql_db.cc:1315) ==26055== by 0x6E79CC: mysql_change_db(THD*, st_mysql_lex_string const*, bool) (sql_db.cc:1603) ==26055== by 0x71429E: mysql_execute_command(THD*) (sql_parse.cc:3612) ==26055== by 0x7188C7: mysql_parse(THD*, char*, unsigned int, Parser_state*) (sql_parse.cc:6149) ==26055== by 0x7191E6: dispatch_command(enum_server_command, THD*, char*, unsigned int) (sql_parse.cc:1334) ==26055== by 0x71A486: do_command(THD*) (sql_parse.cc:1036) ==26055== by 0x6E4C75: do_handle_one_connection(THD*) (sql_connect.cc:969) ==26055== by 0x6E4D54: handle_one_connection (sql_connect.cc:885) ==26055== by 0x3679C07D13: start_thread (pthread_create.c:309) ==26055== by 0x36798F168C: clone (clone.S:115)
[22 Aug 2013 17:04]
Paul DuBois
Noted in 5.1.72, 5.5.34, 5.6.14, 5.7.3 changelogs. If one connection changed its default database and simultaneously another connection executed SHOW PROCESSLIST, the second connection could access invalid memory when attempting to display the first connection's default database. memory.
[30 Sep 2013 16:46]
Laurynas Biveinis
5.1$ bzr log -r 4037 ------------------------------------------------------------ revno: 4037 committer: Praveenkumar Hulakund <praveenkumar.hulakund@oracle.com> branch nick: mysql_5_1 timestamp: Wed 2013-08-21 10:39:40 +0530 message: Bug#11765252 - READ OF FREED MEMORY WHEN "USE DB" AND "SHOW PROCESSLIST" Analysis: ---------- The problem here is, if one connection changes its default db and at the same time another connection executes "SHOW PROCESSLIST", when it wants to read db of the another connection then there is a chance of accessing the invalid memory. The db name stored in THD is not guarded while changing user DB and while reading the user DB in "SHOW PROCESSLIST". So, if THD.db is freed by thd "owner" thread and if another thread executing "SHOW PROCESSLIST" statement tries to read and copy THD.db at the same time then we may endup in the issue reported here. Fix: ---------- Used mutex "LOCK_thd_data" to guard THD.db while freeing it and while copying it to processlist.
[7 Oct 2013 13:01]
Laurynas Biveinis
5.5$ bzr log -r 4442 -n0 ------------------------------------------------------------ revno: 4442 [merge] committer: Praveenkumar Hulakund <praveenkumar.hulakund@oracle.com> branch nick: mysql_5_5 timestamp: Wed 2013-08-21 10:44:22 +0530 message: Bug#11765252 - READ OF FREED MEMORY WHEN "USE DB" AND "SHOW PROCESSLIST" Merging from 5.1 to 5.5 ------------------------------------------------------------ revno: 2661.844.61 committer: Praveenkumar Hulakund <praveenkumar.hulakund@oracle.com> branch nick: mysql_5_1 timestamp: Wed 2013-08-21 10:39:40 +0530 message: Bug#11765252 - READ OF FREED MEMORY WHEN "USE DB" AND "SHOW PROCESSLIST" Analysis: ---------- The problem here is, if one connection changes its default db and at the same time another connection executes "SHOW PROCESSLIST", when it wants to read db of the another connection then there is a chance of accessing the invalid memory. The db name stored in THD is not guarded while changing user DB and while reading the user DB in "SHOW PROCESSLIST". So, if THD.db is freed by thd "owner" thread and if another thread executing "SHOW PROCESSLIST" statement tries to read and copy THD.db at the same time then we may endup in the issue reported here. Fix: ---------- Used mutex "LOCK_thd_data" to guard THD.db while freeing it and while copying it to processlist. 5.5$ bzr log -r 4455 ------------------------------------------------------------ revno: 4455 committer: Praveenkumar Hulakund <praveenkumar.hulakund@oracle.com> branch nick: mysql_5_5 timestamp: Fri 2013-08-23 18:56:31 +0530 message: Bug#11765252 - READ OF FREED MEMORY WHEN "USE DB" AND "SHOW PROCESSLIST" Follow up path, addressing pb2 test failure.
[9 Oct 2013 7:07]
Guangpu Feng
It is not easy to crash the server even this bug is hit because the freed memory address is invalid. I tested the following codes and concluded that the behaviour is depended on the implementation of malloc/free. #include <stdio.h> #include <stdlib.h> #include <string.h> #include <time.h> int main(int argc, char *argv[]) { const char *str = "hello world!"; int len = strlen(str)+1; srand((unsigned)time(NULL)); for (;;) { char *dump = (char*)malloc(len); memset(dump, 0, len); strcpy(dump, str); printf("len: %d, ", len); printf("before free: %p, %s, %d, ", dump, dump, strlen(dump)); free(dump); printf("after free: %p, %s, %d\n", dump, dump, strlen(dump)); len += rand() % 16; } return 0; }
[9 Oct 2013 7:09]
Guangpu Feng
It is not easy to crash the server even this bug is hit because the freed memory address is invalid. --> It is not easy to crash the server even this bug is hit because the freed memory address is valid.