Skip to content

Commit e4b07ce

Browse files
harinvadodariadahlerlend
authored andcommitted
Bug#24447771: ACL_INIT() RETURNS TRUE ON 5.7 DATA DIRECTORY
Description: If MySQL server is started with 5.7 data directory, we fail in acl_init() because role_edges and default_roles tables are missing. Fixed this issue by moving roles initialization to a separate function and print a warning on server log in case required tables are missing.
1 parent 399179b commit e4b07ce

File tree

3 files changed

+247
-18
lines changed

3 files changed

+247
-18
lines changed

mysql-test/r/roles-upgrade.result

Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
1+
Run mysql_upgrade once
2+
mysql.column_stats OK
3+
mysql.columns_priv OK
4+
mysql.component OK
5+
mysql.db OK
6+
mysql.default_roles OK
7+
mysql.engine_cost OK
8+
mysql.func OK
9+
mysql.general_log OK
10+
mysql.gtid_executed OK
11+
mysql.help_category OK
12+
mysql.help_keyword OK
13+
mysql.help_relation OK
14+
mysql.help_topic OK
15+
mysql.innodb_index_stats OK
16+
mysql.innodb_table_stats OK
17+
mysql.plugin OK
18+
mysql.procs_priv OK
19+
mysql.proxies_priv OK
20+
mysql.role_edges OK
21+
mysql.server_cost OK
22+
mysql.servers OK
23+
mysql.slave_master_info OK
24+
mysql.slave_relay_log_info OK
25+
mysql.slave_worker_info OK
26+
mysql.slow_log OK
27+
mysql.tables_priv OK
28+
mysql.time_zone OK
29+
mysql.time_zone_leap_second OK
30+
mysql.time_zone_name OK
31+
mysql.time_zone_transition OK
32+
mysql.time_zone_transition_type OK
33+
mysql.user OK
34+
mtr.global_suppressions OK
35+
mtr.test_suppressions OK
36+
sys.sys_config OK
37+
#
38+
# Bug#24447771 ACL_INIT() RETURNS TRUE ON 5.7 DATA DIRECTORY
39+
#
40+
CALL mtr.add_suppression("Could not load mysql.role_edges and mysql.default_roles tables. ACL DDLs will not work unless mysql_upgrade is executed.");
41+
DROP TABLE mysql.role_edges;
42+
DROP TABLE mysql.default_roles;
43+
#Restart the server
44+
# restart
45+
# let's check for the presense of the warning
46+
# ACL DDLs should not work
47+
CREATE USER u1;
48+
ERROR 42S02: Table 'mysql.role_edges' doesn't exist
49+
CREATE ROLE r1;
50+
ERROR 42S02: Table 'mysql.role_edges' doesn't exist
51+
GRANT SELECT ON *.* TO u1;
52+
ERROR 42S02: Table 'mysql.role_edges' doesn't exist
53+
# Run mysql_upgrade
54+
mysql.column_stats OK
55+
mysql.columns_priv OK
56+
mysql.component OK
57+
mysql.db OK
58+
mysql.default_roles OK
59+
mysql.engine_cost OK
60+
mysql.func OK
61+
mysql.general_log OK
62+
mysql.gtid_executed OK
63+
mysql.help_category OK
64+
mysql.help_keyword OK
65+
mysql.help_relation OK
66+
mysql.help_topic OK
67+
mysql.innodb_index_stats OK
68+
mysql.innodb_table_stats OK
69+
mysql.plugin OK
70+
mysql.procs_priv OK
71+
mysql.proxies_priv OK
72+
mysql.role_edges OK
73+
mysql.server_cost OK
74+
mysql.servers OK
75+
mysql.slave_master_info OK
76+
mysql.slave_relay_log_info OK
77+
mysql.slave_worker_info OK
78+
mysql.slow_log OK
79+
mysql.tables_priv OK
80+
mysql.time_zone OK
81+
mysql.time_zone_leap_second OK
82+
mysql.time_zone_name OK
83+
mysql.time_zone_transition OK
84+
mysql.time_zone_transition_type OK
85+
mysql.user OK
86+
mtr.global_suppressions OK
87+
mtr.test_suppressions OK
88+
sys.sys_config OK
89+
SHOW CREATE TABLE mysql.role_edges;
90+
Table Create Table
91+
role_edges CREATE TABLE `role_edges` (
92+
`FROM_HOST` char(60) COLLATE utf8_bin NOT NULL DEFAULT '',
93+
`FROM_USER` char(32) COLLATE utf8_bin NOT NULL DEFAULT '',
94+
`TO_HOST` char(60) COLLATE utf8_bin NOT NULL DEFAULT '',
95+
`TO_USER` char(32) COLLATE utf8_bin NOT NULL DEFAULT '',
96+
`WITH_ADMIN_OPTION` enum('N','Y') CHARACTER SET utf8 NOT NULL DEFAULT 'N',
97+
PRIMARY KEY (`FROM_HOST`,`FROM_USER`,`TO_HOST`,`TO_USER`)
98+
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin STATS_PERSISTENT=0 COMMENT='Role hierarchy and role grants'
99+
SHOW CREATE TABLE mysql.default_roles;
100+
Table Create Table
101+
default_roles CREATE TABLE `default_roles` (
102+
`HOST` char(60) COLLATE utf8_bin NOT NULL DEFAULT '',
103+
`USER` char(32) COLLATE utf8_bin NOT NULL DEFAULT '',
104+
`DEFAULT_ROLE_HOST` char(60) COLLATE utf8_bin NOT NULL DEFAULT '%',
105+
`DEFAULT_ROLE_USER` char(32) COLLATE utf8_bin NOT NULL DEFAULT '',
106+
PRIMARY KEY (`HOST`,`USER`,`DEFAULT_ROLE_HOST`,`DEFAULT_ROLE_USER`)
107+
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin STATS_PERSISTENT=0 COMMENT='Default roles'
108+
CREATE USER u1;
109+
CREATE ROLE r1;
110+
GRANT SELECT ON *.* TO r1;
111+
GRANT r1 to u1;
112+
CREATE TABLE test.t1(c1 int);
113+
INSERT INTO test.t1 VALUES(1);
114+
SET ROLE r1;
115+
SELECT * from t1;
116+
c1
117+
1
118+
DROP TABLE test.t1;
119+
DROP ROLE r1;
120+
DROP USER u1;
121+
122+
End of tests

mysql-test/t/roles-upgrade.test

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
-- source include/no_valgrind_without_big.inc
2+
-- source include/mysql_upgrade_preparation.inc
3+
4+
#
5+
# Basic test that we can run mysql_upgrde and that it finds the
6+
# expected binaries it uses.
7+
#
8+
--echo Run mysql_upgrade once
9+
--exec $MYSQL_UPGRADE --skip-verbose --force 2>&1
10+
11+
# It should have created a file in the MySQL Servers datadir
12+
let $MYSQLD_DATADIR= `select @@datadir`;
13+
file_exists $MYSQLD_DATADIR/mysql_upgrade_info;
14+
15+
--echo #
16+
--echo # Bug#24447771 ACL_INIT() RETURNS TRUE ON 5.7 DATA DIRECTORY
17+
--echo #
18+
19+
CALL mtr.add_suppression("Could not load mysql.role_edges and mysql.default_roles tables. ACL DDLs will not work unless mysql_upgrade is executed.");
20+
21+
DROP TABLE mysql.role_edges;
22+
DROP TABLE mysql.default_roles;
23+
24+
--echo #Restart the server
25+
--source include/restart_mysqld.inc
26+
27+
--echo # let's check for the presense of the warning
28+
let server_log= $MYSQLTEST_VARDIR/log/mysqld.1.err;
29+
# $server_log has to be processed by include/search_pattern_in_file.inc which
30+
# contains Perl code requiring that the environment variable SEARCH_FILE points
31+
# to this file.
32+
let SEARCH_FILE= $server_log;
33+
34+
--let SEARCH_PATTERN= Could not load mysql.role_edges and mysql.default_roles tables. ACL DDLs will not work unless mysql_upgrade is executed.
35+
--source include/search_pattern_in_file.inc
36+
37+
--echo # ACL DDLs should not work
38+
--error ER_NO_SUCH_TABLE
39+
CREATE USER u1;
40+
41+
--error ER_NO_SUCH_TABLE
42+
CREATE ROLE r1;
43+
44+
--error ER_NO_SUCH_TABLE
45+
GRANT SELECT ON *.* TO u1;
46+
47+
--echo # Run mysql_upgrade
48+
--exec $MYSQL_UPGRADE --skip-verbose --force 2>&1
49+
50+
SHOW CREATE TABLE mysql.role_edges;
51+
SHOW CREATE TABLE mysql.default_roles;
52+
53+
CREATE USER u1;
54+
CREATE ROLE r1;
55+
GRANT SELECT ON *.* TO r1;
56+
GRANT r1 to u1;
57+
CREATE TABLE test.t1(c1 int);
58+
INSERT INTO test.t1 VALUES(1);
59+
60+
connect(conn_u1, localhost, u1,,);
61+
SET ROLE r1;
62+
SELECT * from t1;
63+
64+
connection default;
65+
disconnect conn_u1;
66+
DROP TABLE test.t1;
67+
DROP ROLE r1;
68+
DROP USER u1;
69+
70+
--source include/mysql_upgrade_cleanup.inc
71+
72+
--echo
73+
--echo End of tests
74+

sql/auth/sql_auth_cache.cc

Lines changed: 51 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1468,6 +1468,53 @@ validate_user_plugin_records()
14681468
}
14691469

14701470

1471+
/**
1472+
Initialize roles structures from tables.
1473+
1474+
This function is called by acl_init and may fail to
1475+
initialize role structures if role_edges and/or
1476+
default_roles are not present.
1477+
1478+
@param thd [in] Handle to THD
1479+
*/
1480+
1481+
static
1482+
void roles_init(THD *thd)
1483+
{
1484+
TABLE_LIST tables[2];
1485+
tables[0].init_one_table(C_STRING_WITH_LEN("mysql"),
1486+
C_STRING_WITH_LEN("role_edges"),
1487+
"role_edges", TL_READ, MDL_SHARED_READ_ONLY);
1488+
1489+
tables[1].init_one_table(C_STRING_WITH_LEN("mysql"),
1490+
C_STRING_WITH_LEN("default_roles"),
1491+
"default_roles", TL_READ, MDL_SHARED_READ_ONLY);
1492+
1493+
tables[0].next_local=
1494+
tables[0].next_global= tables + 1;
1495+
tables[1].next_local=
1496+
tables[1].next_global= 0;
1497+
tables[0].open_type=
1498+
tables[1].open_type= OT_BASE_ONLY;
1499+
1500+
bool result= open_and_lock_tables(thd, tables, MYSQL_LOCK_IGNORE_TIMEOUT);
1501+
if (!result)
1502+
{
1503+
check_acl_tables(tables, false);
1504+
commit_and_close_mysql_tables(thd);
1505+
result= roles_init_from_tables(thd);
1506+
}
1507+
1508+
if (result)
1509+
{
1510+
sql_print_warning("Could not load mysql.role_edges and "
1511+
"mysql.default_roles tables. ACL DDLs "
1512+
"will not work unless mysql_upgrade is "
1513+
"executed.");
1514+
}
1515+
}
1516+
1517+
14711518
/*
14721519
Initialize structures responsible for user/db-level privilege checking and
14731520
load privilege information for them from tables in the 'mysql' database.
@@ -1540,7 +1587,7 @@ my_bool acl_init(bool dont_read_acl_tables)
15401587
by zeros at startup.
15411588
*/
15421589
return_val|= acl_reload(thd);
1543-
return_val|= roles_init_from_tables(thd);
1590+
roles_init(thd);
15441591
thd->release_resources();
15451592
delete thd;
15461593

@@ -2160,7 +2207,7 @@ void acl_free(bool end)
21602207

21612208
bool check_engine_type_for_acl_table(THD *thd)
21622209
{
2163-
TABLE_LIST tables[8];
2210+
TABLE_LIST tables[6];
21642211

21652212
/*
21662213
Open the following ACL tables to check their consistency.
@@ -2193,14 +2240,6 @@ bool check_engine_type_for_acl_table(THD *thd)
21932240
C_STRING_WITH_LEN("procs_priv"),
21942241
"procs_priv", TL_READ, MDL_SHARED_READ_ONLY);
21952242

2196-
tables[ACL_TABLES::TABLE_ROLE_EDGES].init_one_table(C_STRING_WITH_LEN("mysql"),
2197-
C_STRING_WITH_LEN("role_edges"),
2198-
"role_edges", TL_READ, MDL_SHARED_READ_ONLY);
2199-
2200-
tables[ACL_TABLES::TABLE_DEFAULT_ROLES].init_one_table(C_STRING_WITH_LEN("mysql"),
2201-
C_STRING_WITH_LEN("default_roles"),
2202-
"default_roles", TL_READ, MDL_SHARED_READ_ONLY);
2203-
22042243
tables[ACL_TABLES::TABLE_USER].next_local=
22052244
tables[ACL_TABLES::TABLE_USER].next_global= tables + 1;
22062245
tables[ACL_TABLES::TABLE_DB].next_local=
@@ -2212,20 +2251,14 @@ bool check_engine_type_for_acl_table(THD *thd)
22122251
tables[ACL_TABLES::TABLE_PROCS_PRIV].next_local=
22132252
tables[ACL_TABLES::TABLE_PROCS_PRIV].next_global= tables + 5;
22142253
tables[ACL_TABLES::TABLE_PROXIES_PRIV].next_local=
2215-
tables[ACL_TABLES::TABLE_PROXIES_PRIV].next_global= tables + 6;
2216-
tables[ACL_TABLES::TABLE_ROLE_EDGES].next_local=
2217-
tables[ACL_TABLES::TABLE_ROLE_EDGES].next_global= tables + 7;
2218-
tables[ACL_TABLES::TABLE_DEFAULT_ROLES].next_local=
2219-
tables[ACL_TABLES::TABLE_DEFAULT_ROLES].next_global= 0;
2254+
tables[ACL_TABLES::TABLE_PROXIES_PRIV].next_global= 0;
22202255

22212256
tables[ACL_TABLES::TABLE_USER].open_type=
22222257
tables[ACL_TABLES::TABLE_DB].open_type=
22232258
tables[ACL_TABLES::TABLE_TABLES_PRIV].open_type=
22242259
tables[ACL_TABLES::TABLE_COLUMNS_PRIV].open_type=
22252260
tables[ACL_TABLES::TABLE_PROCS_PRIV].open_type=
2226-
tables[ACL_TABLES::TABLE_PROXIES_PRIV].open_type=
2227-
tables[ACL_TABLES::TABLE_ROLE_EDGES].open_type=
2228-
tables[ACL_TABLES::TABLE_DEFAULT_ROLES].open_type= OT_BASE_ONLY;
2261+
tables[ACL_TABLES::TABLE_PROXIES_PRIV].open_type= OT_BASE_ONLY;
22292262

22302263
bool result= open_and_lock_tables(thd, tables, MYSQL_LOCK_IGNORE_TIMEOUT);
22312264
if (!result)

0 commit comments

Comments
 (0)