From 210ab6edf47fa73f3b77e974ed2e9357ccdd051c Mon Sep 17 00:00:00 2001 From: Alexander Barkov Date: Tue, 11 Aug 2026 10:13:16 +0400 Subject: [PATCH] MDEV-40722 DROP PACKAGE leaves PACKAGE BODY grant in mysql.procs_priv DROP PACKAGE now removes both PACKAGE BODY and PACKAGE privileges for the given package. --- .../oracle/r/sp-package-security.result | 23 +++++ .../compat/oracle/t/sp-package-security.test | 25 ++++++ sql/sql_acl.cc | 88 +++++++++++++------ 3 files changed, 109 insertions(+), 27 deletions(-) diff --git a/mysql-test/suite/compat/oracle/r/sp-package-security.result b/mysql-test/suite/compat/oracle/r/sp-package-security.result index c08b78cb8cf..c11589a0ea4 100644 --- a/mysql-test/suite/compat/oracle/r/sp-package-security.result +++ b/mysql-test/suite/compat/oracle/r/sp-package-security.result @@ -320,3 +320,26 @@ SESSION_USER() CURRENT_USER() msg root@localhost root@localhost p1.p1 DROP PACKAGE p1; DROP USER xxx@localhost; +# +# MDEV-40722 DROP PACKAGE leaves PACKAGE BODY grant in mysql.procs_priv +# +CREATE PACKAGE pkg1 AS +FUNCTION f RETURN VARCHAR2(64); +END +$$ +CREATE PACKAGE BODY pkg1 AS +FUNCTION f RETURN VARCHAR2(64) AS +BEGIN RETURN 'f'; +END; +END$$ +CREATE USER reader@localhost; +GRANT EXECUTE ON PACKAGE test.pkg1 TO reader@localhost; +GRANT EXECUTE ON PACKAGE BODY test.pkg1 TO reader@localhost; +SELECT host,db,user,routine_name,routine_type,proc_priv FROM mysql.procs_priv ORDER BY routine_type; +host db user routine_name routine_type proc_priv +localhost test reader pkg1 PACKAGE Execute +localhost test reader pkg1 PACKAGE BODY Execute +DROP PACKAGE pkg1; +SELECT host,db,user,routine_name,routine_type,proc_priv FROM mysql.procs_priv ORDER BY routine_type; +host db user routine_name routine_type proc_priv +DROP USER reader@localhost; diff --git a/mysql-test/suite/compat/oracle/t/sp-package-security.test b/mysql-test/suite/compat/oracle/t/sp-package-security.test index 583f70afe14..20a4fddb5b4 100644 --- a/mysql-test/suite/compat/oracle/t/sp-package-security.test +++ b/mysql-test/suite/compat/oracle/t/sp-package-security.test @@ -330,3 +330,28 @@ DELIMITER ;$$ CALL p1.p1; DROP PACKAGE p1; DROP USER xxx@localhost; + + +--echo # +--echo # MDEV-40722 DROP PACKAGE leaves PACKAGE BODY grant in mysql.procs_priv +--echo # + +DELIMITER $$; +CREATE PACKAGE pkg1 AS + FUNCTION f RETURN VARCHAR2(64); +END +$$ +CREATE PACKAGE BODY pkg1 AS + FUNCTION f RETURN VARCHAR2(64) AS + BEGIN RETURN 'f'; + END; +END$$ +DELIMITER ;$$ + +CREATE USER reader@localhost; +GRANT EXECUTE ON PACKAGE test.pkg1 TO reader@localhost; +GRANT EXECUTE ON PACKAGE BODY test.pkg1 TO reader@localhost; +SELECT host,db,user,routine_name,routine_type,proc_priv FROM mysql.procs_priv ORDER BY routine_type; +DROP PACKAGE pkg1; +SELECT host,db,user,routine_name,routine_type,proc_priv FROM mysql.procs_priv ORDER BY routine_type; +DROP USER reader@localhost; diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc index 3dc5f391f9d..94d81d749d9 100644 --- a/sql/sql_acl.cc +++ b/sql/sql_acl.cc @@ -11761,6 +11761,61 @@ Silence_routine_definer_errors::handle_condition( } +/* + The low level function to revoke routine privileges for the given sp handler + @param thd the thd + @param proc_privs the table mysql.proc_privs + @param sp_db the routine database + @param sp_name the routine name + @param sph the sp handler +*/ +static void sp_revoke_privileges_for_handler(THD *thd, TABLE *proc_privs, +#if MYSQL_VERSION_ID < 110501 + const char *sp_db, + const char *sp_name, +#else +#error Remove the above conditional code + const Lex_ident_db &sp_db, + const Lex_ident_routine &sp_name, +#endif + const Sp_handler *sph) +{ + uint counter, revoked; + HASH *hash= sph->get_priv_hash(); + do + { + for (counter= 0, revoked= 0 ; counter < hash->records ; ) + { + GRANT_NAME *grant_proc= (GRANT_NAME*) my_hash_element(hash, counter); +#if MYSQL_VERSION_ID < 110501 + if (!my_strcasecmp(&my_charset_utf8mb3_bin, grant_proc->db, sp_db) && + !my_strcasecmp(system_charset_info, grant_proc->tname, sp_name)) +#else +#error Remove the above conditional code + if (sp_db.streq(Lex_cstring_strlen(grant_proc->db)) && + sp_name.streq(Lex_cstring_strlen(grant_proc->tname))) +#endif + { + LEX_USER lex_user; + lex_user.user.str= grant_proc->user; + lex_user.user.length= strlen(grant_proc->user); + lex_user.host.str= safe_str(grant_proc->host.hostname); + lex_user.host.length= strlen(lex_user.host.str); + if (replace_routine_table(thd, grant_proc, + proc_privs, lex_user, + grant_proc->db, grant_proc->tname, + sph, ALL_KNOWN_ACL, 1) == 0) + { + revoked= 1; + continue; + } + } + counter++; + } + } while (revoked); +} + + /** Revoke privileges for all users on a stored procedure. Use an error handler that converts errors about missing grants into warnings. @@ -11781,9 +11836,7 @@ Silence_routine_definer_errors::handle_condition( bool sp_revoke_privileges(THD *thd, const char *sp_db, const char *sp_name, const Sp_handler *sph) { - uint counter, revoked; int result; - HASH *hash= sph->get_priv_hash(); Silence_routine_definer_errors error_handler; DBUG_ENTER("sp_revoke_privileges"); @@ -11803,31 +11856,12 @@ bool sp_revoke_privileges(THD *thd, const char *sp_db, const char *sp_name, mysql_mutex_lock(&acl_cache->lock); /* Remove procedure access */ - do - { - for (counter= 0, revoked= 0 ; counter < hash->records ; ) - { - GRANT_NAME *grant_proc= (GRANT_NAME*) my_hash_element(hash, counter); - if (!my_strcasecmp(&my_charset_utf8mb3_bin, grant_proc->db, sp_db) && - !my_strcasecmp(system_charset_info, grant_proc->tname, sp_name)) - { - LEX_USER lex_user; - lex_user.user.str= grant_proc->user; - lex_user.user.length= strlen(grant_proc->user); - lex_user.host.str= safe_str(grant_proc->host.hostname); - lex_user.host.length= strlen(lex_user.host.str); - if (replace_routine_table(thd, grant_proc, - tables.procs_priv_table().table(), lex_user, - grant_proc->db, grant_proc->tname, - sph, ALL_KNOWN_ACL, 1) == 0) - { - revoked= 1; - continue; - } - } - counter++; - } - } while (revoked); + if (sph == &sp_handler_package_spec) + sp_revoke_privileges_for_handler(thd, tables.procs_priv_table().table(), + sp_db, sp_name, &sp_handler_package_body); + + sp_revoke_privileges_for_handler(thd, tables.procs_priv_table().table(), + sp_db, sp_name, sph); mysql_mutex_unlock(&acl_cache->lock); mysql_rwlock_unlock(&LOCK_grant);