Bug #110582 After executing 'set role', cannot access the database with "_" in the db name
Submitted: 31 Mar 2023 16:52 Modified: 23 May 2023 16:51
Reporter: LING-SEN PENG Email Updates:
Status: Can't repeat Impact on me:
None 
Category:MySQL Server: General Severity:S3 (Non-critical)
Version:8.0.32 OS:Any
Assigned to: CPU Architecture:Any

[31 Mar 2023 16:52] LING-SEN PENG
Description:
he user is granted the privileges to access the database and the database name includes the special character `_`. Per https://dev.mysql.com/doc/refman/8.0/en/grant.html,

The _ and % wildcards are permitted when specifying database names in GRANT statements that grant privileges at the database level (GRANT ... ON db_name.*). This means, for example, that to use a _ character as part of a database name, specify it using the \ escape character as \_ in the GRANT statement, to prevent the user from being able to access additional databases matching the wildcard pattern (for example, GRANT ... ON `foo\_bar`.* TO ...). 

The issue is that a user cannot access the database with wildcard name after executing 'set role' statement.

How to repeat:
Log on as the admin user:
mysql> create database test;
Query OK, 1 row affected (0.00 sec)
mysql> create role test_role;
Query OK, 0 rows affected (0.00 sec)
mysql> grant all on test.* to test_role;
Query OK, 0 rows affected (0.01 sec)
mysql> create database my_test;
Query OK, 1 row affected (0.00 sec)
mysql> create user user1 identified by 'password';
Query OK, 0 rows affected (0.01 sec)
mysql> grant test_role to user1;
Query OK, 0 rows affected (0.00 sec)
mysql> grant SELECT, INSERT, UPDATE, DELETE, CREATE, ALTER ON `my\_test`.* to user1;
Query OK, 0 rows affected (0.00 sec)
mysql> select * from mysql.db where User='user1'\G
*************************** 1. row ***************************
                 Host: %
                   Db: my\_test
                 User: user1
          Select_priv: Y
          Insert_priv: Y
          Update_priv: Y
          Delete_priv: Y
          Create_priv: Y
            Drop_priv: N
           Grant_priv: N
      References_priv: N
           Index_priv: N
           Alter_priv: Y
Create_tmp_table_priv: N
     Lock_tables_priv: N
     Create_view_priv: N
       Show_view_priv: N
  Create_routine_priv: N
   Alter_routine_priv: N
         Execute_priv: N
           Event_priv: N
         Trigger_priv: N
1 row in set (0.00 sec)

Log on as 'user1':
mysql> use my_test;
Database changed
mysql> set role test_role;
Query OK, 0 rows affected (0.00 sec)
mysql> use my_test;
ERROR 1044 (42000): Access denied for user 'user1'@'%' to database 'my_test'
mysql> set role none;
Query OK, 0 rows affected (0.00 sec)
mysql> use my_test;
Database changed

Suggested fix:
I was able to fix the bug by changing the default value for "use_pattern_scan" to "false"

https://code.amazon.com/packages/OscarMysql80/blobs/0d43a0b52f36ff6b15cc22e96279b801948832...

The fix is verified by updating the existing mysql-test/t/roles_bugs_wildcard.test

--source include/not_partial_revokes.inc
# Save the initial number of concurrent sessions
--source include/count_sessions.inc

--echo #
--echo # Bug#31013538 ALL PRIVILEGES ON A DATABASE FOR
--echo #              ROLE DOESN'T ALLOW USER TO CREATE
--echo #

CREATE USER u1;
CREATE DATABASE admin_db_name;
CREATE TABLE admin_db_name.test(a int);
INSERT INTO admin_db_name.test VALUES (1), (2), (3), (4), (5);

GRANT SELECT, INSERT, UPDATE, DELETE, CREATE, ALTER, DROP ON `admin\_db\_name`.* to u1;

CREATE ROLE r1;
GRANT CREATE, DROP ON db_name.* TO r1;
GRANT r1 TO u1;

--connect(conn_u1, localhost, u1,,,,)
--echo # Grants without role activation
SHOW GRANTS;
USE admin_db_name;
SELECT COUNT(*) FROM test;
SELECT COUNT(*) FROM admin_db_name.test;

# Activate r1
SET ROLE r1;
--echo # Grants after role activation: Must show privileges from r1
SHOW GRANTS;
INSERT INTO test VALUES (11), (12);
SELECT COUNT(*) FROM test;
SELECT COUNT(*) FROM admin_db_name.test;

DROP TABLE test;
DROP DATABASE admin_db_name;

CREATE DATABASE db_name;
USE db_name;
CREATE TABLE test(a int);
DROP TABLE test;
DROP DATABASE db_name;

CREATE DATABASE db1name;
DROP DATABASE db1name;

--connection default
--disconnect conn_u1
DROP ROLE r1;
DROP USER u1;

--echo
--echo # End of 8.0 tests
--echo

# Wait till we reached the initial number of concurrent sessions
--source include/wait_until_count_sessions.inc
[31 Mar 2023 17:00] LING-SEN PENG
I was able to fix the bug by changing the default value for "use_pattern_scan" to "false" in https://github.com/mysql/mysql-server/blob/8.0/sql/auth/sql_security_ctx.h#L93
[31 Mar 2023 20:26] LING-SEN PENG
After executing 'set role', cannot access the database with "_" in the db name
[11 May 2023 13:08] MySQL Verification Team
Hello LING-SEN PENG,

Thank you for the bug report.
I tried to reproduce your issue on windows 10 with workbench 8.0.32 using above procedure but I am not seeing any issues at my end.
Please try below statement
grant SELECT, INSERT, UPDATE, DELETE, CREATE, ALTER ON `my_test`.* to 'user1';

Regards,
Ashwini Patil
[23 May 2023 16:51] LING-SEN PENG
Per https://dev.mysql.com/doc/refman/8.0/en/grant.html,

"The _ and % wildcards are permitted when specifying database names in GRANT statements that grant privileges at the database level (GRANT ... ON db_name.*). This means, for example, that to use a _ character as part of a database name, specify it using the \ escape character as \_ in the GRANT statement, to prevent the user from being able to access additional databases matching the wildcard pattern (for example, GRANT ... ON `foo\_bar`.* TO ...). "

The SQL statement "grant SELECT, INSERT, UPDATE, DELETE, CREATE, ALTER ON `my_test`.* to 'user1';" will grant the permissions to myXtest and myYtest databases as well and this is not what the user wants.