From 6c55e52b108d43dead9aef82e791f3de7a2dd93f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vicen=C8=9Biu=20Ciorbaru?= Date: Fri, 13 Mar 2015 20:12:22 +0200 Subject: [PATCH] MDEV-7774: Crash when dropping user within rebuild_role_grants The issue comes from not taking all possibilities to match an entry within the roles_mapping HASH, when updating the data structure. --- .../suite/roles/create_and_drop_role.result | 18 ++++++++++++ .../suite/roles/create_and_drop_role.test | 19 +++++++++++++ sql/sql_acl.cc | 28 ++++++++++++++++--- 3 files changed, 61 insertions(+), 4 deletions(-) diff --git a/mysql-test/suite/roles/create_and_drop_role.result b/mysql-test/suite/roles/create_and_drop_role.result index 2974dd20e22..79c6f412111 100644 --- a/mysql-test/suite/roles/create_and_drop_role.result +++ b/mysql-test/suite/roles/create_and_drop_role.result @@ -46,3 +46,21 @@ Note 1449 The user specified as a definer ('u1'@'%') does not exist create user foo@bar; drop user foo@bar; drop role r1; +CREATE USER u1; +CREATE ROLE r1; +CREATE USER r1@localhost; +CREATE ROLE r2; +GRANT r2 to r1; +GRANT r2 to r1@localhost; +DROP ROLE r1; +SELECT * FROM mysql.roles_mapping; +Host User Role Admin_option +localhost r1 r2 N +localhost root r2 Y +SHOW GRANTS FOR r1@localhost; +Grants for r1@localhost +GRANT r2 TO 'r1'@'localhost' +GRANT USAGE ON *.* TO 'r1'@'localhost' +DROP USER u1; +DROP ROLE r2; +DROP USER r1@localhost; diff --git a/mysql-test/suite/roles/create_and_drop_role.test b/mysql-test/suite/roles/create_and_drop_role.test index 38f040789e0..0bf5b744e6b 100644 --- a/mysql-test/suite/roles/create_and_drop_role.test +++ b/mysql-test/suite/roles/create_and_drop_role.test @@ -68,3 +68,22 @@ create user foo@bar; drop user foo@bar; drop role r1; +# +# MDEV-7774 Assertion `status == 0' fails when dropping in this order: +# +CREATE USER u1; +CREATE ROLE r1; +CREATE USER r1@localhost; +CREATE ROLE r2; +GRANT r2 to r1; +GRANT r2 to r1@localhost; +# MDEV-7774: Dropping in this order caused the crash. +DROP ROLE r1; +--sorted_result +SELECT * FROM mysql.roles_mapping; +SHOW GRANTS FOR r1@localhost; # Related to MDEV-7774, also caused a crash, by + # not updating the internal acl_roles_mapping + # data structure correctly; +DROP USER u1; +DROP ROLE r2; +DROP USER r1@localhost; diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc index e4975acfb55..f46a923bddf 100644 --- a/sql/sql_acl.cc +++ b/sql/sql_acl.cc @@ -8802,10 +8802,30 @@ static int handle_grant_struct(enum enum_acl_lists struct_no, bool drop, if (struct_no == ROLES_MAPPINGS_HASH) { const char* role= role_grant_pair->r_uname? role_grant_pair->r_uname: ""; - if (user_from->is_role() ? strcmp(user_from->user.str, role) : - (strcmp(user_from->user.str, user) || - my_strcasecmp(system_charset_info, user_from->host.str, host))) - continue; + if (user_from->is_role()) + { + /* When searching for roles within the ROLES_MAPPINGS_HASH, we have + to check both the user field as well as the role field for a match. + + It is possible to have a role granted to a role. If we are going + to modify the mapping entry, it needs to be done on either on the + "user" end (here represented by a role) or the "role" end. At least + one part must match. + + If the "user" end has a not-empty host string, it can never match + as we are searching for a role here. A role always has an empty host + string. + */ + if ((*host || strcmp(user_from->user.str, user)) && + strcmp(user_from->user.str, role)) + continue; + } + else + { + if (strcmp(user_from->user.str, user) || + my_strcasecmp(system_charset_info, user_from->host.str, host)) + continue; + } } else {