Skip to content

Commit 6d570d7

Browse files
author
Arun Kuruvila
committed
Bug#27230925: HANDLE_FATAL_SIGNAL (SIG=11) IN
SHOW_ROUTINE_GRANTS Description :- Server crashes in show_routine_grants(). Analysis :- When "grant_reload_procs_priv" encounters an error, the grant structures (structures with column, function and procedure privileges) are freed. Server crashes when trying to access these structures later. Fix :- Grant structures are retained even when "grant_reload_procs_priv()" encounters an error while reloading column, function and procedure privileges.
1 parent a08508a commit 6d570d7

File tree

3 files changed

+65
-31
lines changed

3 files changed

+65
-31
lines changed

mysql-test/r/grant.result

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1692,6 +1692,7 @@ revoke create, insert on mysqltest.t6 from mysqltest@localhost;
16921692
drop user mysqltest@localhost;
16931693
drop database mysqltest;
16941694
use test;
1695+
call mtr.add_suppression("Can't open and lock privilege tables");
16951696
FLUSH PRIVILEGES without procs_priv table.
16961697
RENAME TABLE mysql.procs_priv TO mysql.procs_gone;
16971698
FLUSH PRIVILEGES;

mysql-test/t/grant.test

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1667,6 +1667,9 @@ use test;
16671667
#
16681668
# Bug#16470 crash on grant if old grant tables
16691669
#
1670+
1671+
call mtr.add_suppression("Can't open and lock privilege tables");
1672+
16701673
--echo FLUSH PRIVILEGES without procs_priv table.
16711674
RENAME TABLE mysql.procs_priv TO mysql.procs_gone;
16721675
--error ER_NO_SUCH_TABLE

sql/sql_acl.cc

Lines changed: 61 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -4871,6 +4871,7 @@ static my_bool grant_load(THD *thd, TABLE_LIST *tables)
48714871
exists.
48724872
48734873
@param thd A pointer to the thread handler object.
4874+
@param table A pointer to the table list.
48744875
48754876
@see grant_reload
48764877
@@ -4879,31 +4880,22 @@ static my_bool grant_load(THD *thd, TABLE_LIST *tables)
48794880
@retval TRUE An error has occurred.
48804881
*/
48814882

4882-
static my_bool grant_reload_procs_priv(THD *thd)
4883+
static my_bool grant_reload_procs_priv(THD *thd, TABLE_LIST *table)
48834884
{
48844885
HASH old_proc_priv_hash, old_func_priv_hash;
4885-
TABLE_LIST table;
48864886
my_bool return_val= FALSE;
48874887
DBUG_ENTER("grant_reload_procs_priv");
48884888

4889-
table.init_one_table("mysql", 5, "procs_priv",
4890-
strlen("procs_priv"), "procs_priv",
4891-
TL_READ);
4892-
table.open_type= OT_BASE_ONLY;
4893-
4894-
if (open_and_lock_tables(thd, &table, FALSE, MYSQL_LOCK_IGNORE_TIMEOUT))
4895-
DBUG_RETURN(TRUE);
4896-
4897-
mysql_rwlock_wrlock(&LOCK_grant);
48984889
/* Save a copy of the current hash if we need to undo the grant load */
48994890
old_proc_priv_hash= proc_priv_hash;
49004891
old_func_priv_hash= func_priv_hash;
49014892

4902-
if ((return_val= grant_load_procs_priv(table.table)))
4893+
if ((return_val= grant_load_procs_priv(table->table)))
49034894
{
49044895
/* Error; Reverting to old hash */
49054896
DBUG_PRINT("error",("Reverting to old privileges"));
4906-
grant_free();
4897+
my_hash_free(&proc_priv_hash);
4898+
my_hash_free(&func_priv_hash);
49074899
proc_priv_hash= old_proc_priv_hash;
49084900
func_priv_hash= old_func_priv_hash;
49094901
}
@@ -4912,9 +4904,7 @@ static my_bool grant_reload_procs_priv(THD *thd)
49124904
my_hash_free(&old_proc_priv_hash);
49134905
my_hash_free(&old_func_priv_hash);
49144906
}
4915-
mysql_rwlock_unlock(&LOCK_grant);
49164907

4917-
close_mysql_tables(thd);
49184908
DBUG_RETURN(return_val);
49194909
}
49204910

@@ -4936,7 +4926,7 @@ static my_bool grant_reload_procs_priv(THD *thd)
49364926

49374927
my_bool grant_reload(THD *thd)
49384928
{
4939-
TABLE_LIST tables[2];
4929+
TABLE_LIST tables[3];
49404930
HASH old_column_priv_hash;
49414931
MEM_ROOT old_mem;
49424932
my_bool return_val= 1;
@@ -4952,15 +4942,57 @@ my_bool grant_reload(THD *thd)
49524942
tables[1].init_one_table(C_STRING_WITH_LEN("mysql"),
49534943
C_STRING_WITH_LEN("columns_priv"),
49544944
"columns_priv", TL_READ);
4945+
tables[2].init_one_table(C_STRING_WITH_LEN("mysql"),
4946+
C_STRING_WITH_LEN("procs_priv"),
4947+
"procs_priv", TL_READ);
4948+
49554949
tables[0].next_local= tables[0].next_global= tables+1;
4956-
tables[0].open_type= tables[1].open_type= OT_BASE_ONLY;
4950+
tables[1].next_local= tables[1].next_global= tables+2;
4951+
tables[0].open_type= tables[1].open_type= tables[2].open_type= OT_BASE_ONLY;
4952+
4953+
/*
4954+
Reload will work in the following manner:-
4955+
4956+
proc_priv_hash structure
4957+
/ \
4958+
not initialized initialized
4959+
/ \ |
4960+
mysql.procs_priv table Server Startup |
4961+
is missing \ |
4962+
| open_and_lock_tables()
4963+
Assume we are working on /success \failure
4964+
pre 4.1 system tables. Normal Scenario. An error is thrown.
4965+
A warning is printed Reload column privilege. Retain the old hash.
4966+
and continue with Reload function and
4967+
reloading the column procedure privileges,
4968+
privileges. if available.
4969+
*/
4970+
4971+
if (!(my_hash_inited(&proc_priv_hash)))
4972+
tables[2].open_strategy= TABLE_LIST::OPEN_IF_EXISTS;
49574973

49584974
/*
49594975
To avoid deadlocks we should obtain table locks before
49604976
obtaining LOCK_grant rwlock.
49614977
*/
49624978
if (open_and_lock_tables(thd, tables, FALSE, MYSQL_LOCK_IGNORE_TIMEOUT))
4979+
{
4980+
if (thd->stmt_da->is_error())
4981+
{
4982+
sql_print_error("Fatal error: Can't open and lock privilege tables: %s",
4983+
thd->stmt_da->message());
4984+
}
49634985
goto end;
4986+
}
4987+
4988+
if (tables[2].table == NULL)
4989+
{
4990+
sql_print_warning("Table 'mysql.procs_priv' does not exist. "
4991+
"Please run mysql_upgrade.");
4992+
push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN, ER_NO_SUCH_TABLE,
4993+
ER(ER_NO_SUCH_TABLE), tables[2].db,
4994+
tables[2].table_name);
4995+
}
49644996

49654997
mysql_rwlock_wrlock(&LOCK_grant);
49664998
old_column_priv_hash= column_priv_hash;
@@ -4972,33 +5004,31 @@ my_bool grant_reload(THD *thd)
49725004
old_mem= memex;
49735005
init_sql_alloc(&memex, ACL_ALLOC_BLOCK_SIZE, 0);
49745006

4975-
if ((return_val= grant_load(thd, tables)))
5007+
/*
5008+
tables[2].table i.e. procs_priv can be null if we are working with
5009+
pre 4.1 privilage tables
5010+
*/
5011+
if ((return_val= (grant_load(thd, tables) ||
5012+
(tables[2].table != NULL &&
5013+
grant_reload_procs_priv(thd, &tables[2])))
5014+
))
49765015
{ // Error. Revert to old hash
49775016
DBUG_PRINT("error",("Reverting to old privileges"));
4978-
grant_free(); /* purecov: deadcode */
5017+
my_hash_free(&column_priv_hash);
5018+
free_root(&memex,MYF(0));
49795019
column_priv_hash= old_column_priv_hash; /* purecov: deadcode */
49805020
memex= old_mem; /* purecov: deadcode */
49815021
}
49825022
else
49835023
{
49845024
my_hash_free(&old_column_priv_hash);
49855025
free_root(&old_mem,MYF(0));
5026+
grant_version++;
49865027
}
49875028
mysql_rwlock_unlock(&LOCK_grant);
4988-
close_mysql_tables(thd);
4989-
4990-
/*
4991-
It is OK failing to load procs_priv table because we may be
4992-
working with 4.1 privilege tables.
4993-
*/
4994-
if (grant_reload_procs_priv(thd))
4995-
return_val= 1;
4996-
4997-
mysql_rwlock_wrlock(&LOCK_grant);
4998-
grant_version++;
4999-
mysql_rwlock_unlock(&LOCK_grant);
50005029

50015030
end:
5031+
close_mysql_tables(thd);
50025032
DBUG_RETURN(return_val);
50035033
}
50045034

0 commit comments

Comments
 (0)