MDEV-40656 Bypass REVOKE DENY ... FROM PUBLIC privilege check. - #5502
MDEV-40656 Bypass REVOKE DENY ... FROM PUBLIC privilege check.#5502vaintroub wants to merge 1 commit into
Conversation
There was a problem hiding this comment.
Pull request overview
This PR addresses a privilege “lockout” scenario where DENY ... TO PUBLIC can prevent anyone (including privileged accounts) from successfully running REVOKE DENY ... FROM PUBLIC due to the “deny-wins” privilege merge behavior. It introduces a narrowly scoped bypass that allows the revoke when the revoker has sufficient authority to directly modify the underlying storage of DENY rules (mysql.global_priv).
Changes:
- Add
Sql_cmd_grant::should_bypass_revoke_deny()to allowREVOKE DENY ... FROM PUBLICwhen the revoker hasUPDATEonmysql.global_priv. - Apply the bypass to privilege checks across multiple grant/revoke scopes (db/table/column/routine paths).
- Add a new MTR test (
deny_revoke_public) covering the bypass behavior at global/db/table/column/routine scopes and a non-PUBLIC role case.
Reviewed changes
Copilot reviewed 4 out of 4 changed files in this pull request and generated 1 comment.
| File | Description |
|---|---|
| sql/sql_acl.h | Declares the new helper used to decide whether to bypass the usual REVOKE DENY privilege checks. |
| sql/sql_acl.cc | Implements the bypass decision logic and integrates it into the existing grant/revoke privilege-check flow. |
| mysql-test/main/deny_revoke_public.test | Adds a regression test covering the lockout scenario and the intended bypass behavior across scopes. |
| mysql-test/main/deny_revoke_public.result | Expected output for the new regression test. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
DENY ... TO PUBLIC denies everyone, including whoever tries to revoke it, via the "deny wins" merge at every scope (global, db, table, column, routine). Allow REVOKE DENY ... FROM PUBLIC when the revoker can UPDATE mysql.global_priv (same as hand-editing). Assisted-by: Claude:claude-5-sonnet
5d56b94 to
0ed5acb
Compare
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 4 out of 4 changed files in this pull request and generated 2 comments.
Suppressed comments (1)
sql/sql_acl.cc:14389
- This loop treats an empty
users_listas 'PUBLIC' (it never returns false), so the bypass can proceed to theUPDATE mysql.global_privcheck even when no target user was parsed. It also allows bypass when multiple entries are allPUBLIC(e.g.,FROM PUBLIC, PUBLIC). To keep the bypass narrowly scoped, add an explicit check that the list contains exactly one user entry and that it is PUBLIC; otherwise return false.
/* Is it for PUBLIC ? */
List_iterator_fast<LEX_USER> it(thd->lex->users_list);
LEX_USER *user;
while ((user= it++))
{
if (user->host.length ||
!my_charset_utf8mb3_general1400_as_ci.streq(user->user, public_name))
return false;
}
DENY ... TO PUBLIC denies everyone, including whoever tries to revoke it, via the "deny wins" merge at every scope (global, db, table, column, routine). Allow REVOKE DENY ... FROM PUBLIC when the revoker can UPDATE mysql.global_priv (same as hand-editing).
Assisted-by: Claude:claude-5-sonnet