Bug#31850 Test crashes in "embedded" server

The mysql_change_user command fails to properly update the database pointer
when no database is selected, leading to "use after free" errors. The same
happens on the user privilege pointer in the thread security context.

The solution is to properly reset and update the database name. Also update
the user_priv pointer so that it doesn't point to freed memory.
This commit is contained in:
davi@endora.local 2007-11-01 17:29:20 -02:00
parent 7ec50bd483
commit 968af72150
2 changed files with 12 additions and 16 deletions

View file

@ -316,17 +316,20 @@ int check_user(THD *thd, enum enum_server_command command,
{
DBUG_ENTER("check_user");
LEX_STRING db_str= { (char *) db, db ? strlen(db) : 0 };
/*
Clear thd->db as it points to something, that will be freed when
connection is closed. We don't want to accidentally free a wrong
pointer if connect failed. Also in case of 'CHANGE USER' failure,
current database will be switched to 'no database selected'.
*/
thd->reset_db(NULL, 0);
#ifdef NO_EMBEDDED_ACCESS_CHECKS
thd->main_security_ctx.master_access= GLOBAL_ACLS; // Full rights
/* Change database if necessary */
if (db && db[0])
{
/*
thd->db is saved in caller and needs to be freed by caller if this
function returns 0
*/
thd->reset_db(NULL, 0);
if (mysql_change_db(thd, &db_str, FALSE))
{
/* Send the error to the client */
@ -358,14 +361,6 @@ int check_user(THD *thd, enum enum_server_command command,
passwd_len != SCRAMBLE_LENGTH_323)
DBUG_RETURN(ER_HANDSHAKE_ERROR);
/*
Clear thd->db as it points to something, that will be freed when
connection is closed. We don't want to accidentally free a wrong pointer
if connect failed. Also in case of 'CHANGE USER' failure, current
database will be switched to 'no database selected'.
*/
thd->reset_db(NULL, 0);
USER_RESOURCES ur;
int res= acl_getroot(thd, &ur, passwd, passwd_len);
#ifndef EMBEDDED_LIBRARY

View file

@ -911,6 +911,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
/* Clear variables that are allocated */
thd->user_connect= 0;
thd->security_ctx->priv_user= thd->security_ctx->user;
res= check_user(thd, COM_CHANGE_USER, passwd, passwd_len, db, FALSE);
if (res)
@ -933,8 +934,8 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
if (save_user_connect)
decrease_user_connections(save_user_connect);
#endif /* NO_EMBEDDED_ACCESS_CHECKS */
x_free((uchar*) save_db);
x_free((uchar*) save_security_ctx.user);
x_free(save_db);
x_free(save_security_ctx.user);
if (cs_number)
{