Skip to content

MDEV-40656 Bypass REVOKE DENY ... FROM PUBLIC privilege check. - #5502

Open
vaintroub wants to merge 1 commit into
mainfrom
main-MDEV-40656
Open

MDEV-40656 Bypass REVOKE DENY ... FROM PUBLIC privilege check.#5502
vaintroub wants to merge 1 commit into
mainfrom
main-MDEV-40656

Conversation

@vaintroub

Copy link
Copy Markdown
Member

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

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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 allow REVOKE DENY ... FROM PUBLIC when the revoker has UPDATE on mysql.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.

Comment thread sql/sql_acl.cc Outdated
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
@vaintroub
vaintroub requested review from sanja-byelkin and a lite review from Copilot August 6, 2026 19:22

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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_list as 'PUBLIC' (it never returns false), so the bypass can proceed to the UPDATE mysql.global_priv check even when no target user was parsed. It also allows bypass when multiple entries are all PUBLIC (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;
  }

Comment thread sql/sql_acl.h
Comment thread sql/sql_acl.cc
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Development

Successfully merging this pull request may close these issues.

3 participants