mirror of
https://github.com/MariaDB/server.git
synced 2025-07-29 05:21:33 +03:00
MDEV-28367: BACKUP LOCKS on table to be accessible to those with database LOCK TABLES privileges
- Allow database level access via `LOCK TABLES` to execute statement `BACKUP [un]LOCK <object>` - `BACKUP UNLOCK` works only with `RELOAD` privilege. In case there is `LOCK TABLES` privilege without `RELOAD` privilege, we check if backup lock is taken before. If it is not we raise an error of missing `RELOAD` privilege. - We had to remove any error/warnings from calling functions because `thd->get_stmt_da()->m_status` will be set to error and will break `my_ok()`. - Added missing test coverage of `RELOAD` privilege to `main.grant.test` Reviewer: <daniel@mariadb.org>
This commit is contained in:
committed by
Daniel Black
parent
32c6849736
commit
ff0bade2f8
@ -163,5 +163,82 @@ ERROR HY000: Can't execute the query because you have a conflicting read lock
|
|||||||
BACKUP UNLOCK;
|
BACKUP UNLOCK;
|
||||||
DROP TABLE t3;
|
DROP TABLE t3;
|
||||||
#
|
#
|
||||||
|
# MDEV-28367: BACKUP LOCKS on table to be accessible to those
|
||||||
|
# with database LOCK TABLES privileges
|
||||||
|
#
|
||||||
|
create database db1;
|
||||||
|
create table db1.t1(t int);
|
||||||
|
create user user1@localhost;
|
||||||
|
select user,host from mysql.user where user='user1';
|
||||||
|
User Host
|
||||||
|
user1 localhost
|
||||||
|
connect(localhost,user1,,db1,MASTER_PORT,MASTER_SOCKET);
|
||||||
|
connect con1, localhost, user1, ,db1;
|
||||||
|
ERROR 42000: Access denied for user 'user1'@'localhost' to database 'db1'
|
||||||
|
grant reload on *.* to user1@localhost;
|
||||||
|
grant select on db1.* to user1@localhost;
|
||||||
|
show grants for user1@localhost;
|
||||||
|
Grants for user1@localhost
|
||||||
|
GRANT RELOAD ON *.* TO `user1`@`localhost`
|
||||||
|
GRANT SELECT ON `db1`.* TO `user1`@`localhost`
|
||||||
|
connect con1, localhost, user1, ,db1;
|
||||||
|
BACKUP UNLOCK;
|
||||||
|
BACKUP LOCK db1.t1;
|
||||||
|
SELECT LOCK_MODE, LOCK_TYPE, TABLE_SCHEMA, TABLE_NAME FROM information_schema.metadata_lock_info;
|
||||||
|
LOCK_MODE LOCK_TYPE TABLE_SCHEMA TABLE_NAME
|
||||||
|
MDL_SHARED_HIGH_PRIO Table metadata lock db1 t1
|
||||||
|
BACKUP UNLOCK;
|
||||||
|
SELECT LOCK_MODE, LOCK_TYPE, TABLE_SCHEMA, TABLE_NAME FROM information_schema.metadata_lock_info;
|
||||||
|
LOCK_MODE LOCK_TYPE TABLE_SCHEMA TABLE_NAME
|
||||||
|
connection default;
|
||||||
|
disconnect con1;
|
||||||
|
grant lock tables on db1.* to user1@localhost;
|
||||||
|
show grants for user1@localhost;
|
||||||
|
Grants for user1@localhost
|
||||||
|
GRANT RELOAD ON *.* TO `user1`@`localhost`
|
||||||
|
GRANT SELECT, LOCK TABLES ON `db1`.* TO `user1`@`localhost`
|
||||||
|
connect con1, localhost, user1, ,db1;
|
||||||
|
BACKUP UNLOCK;
|
||||||
|
BACKUP LOCK db1.t1;
|
||||||
|
SELECT LOCK_MODE, LOCK_TYPE, TABLE_SCHEMA, TABLE_NAME FROM information_schema.metadata_lock_info;
|
||||||
|
LOCK_MODE LOCK_TYPE TABLE_SCHEMA TABLE_NAME
|
||||||
|
MDL_SHARED_HIGH_PRIO Table metadata lock db1 t1
|
||||||
|
BACKUP UNLOCK;
|
||||||
|
SELECT LOCK_MODE, LOCK_TYPE, TABLE_SCHEMA, TABLE_NAME FROM information_schema.metadata_lock_info;
|
||||||
|
LOCK_MODE LOCK_TYPE TABLE_SCHEMA TABLE_NAME
|
||||||
|
connection default;
|
||||||
|
disconnect con1;
|
||||||
|
revoke reload on *.* from user1@localhost;
|
||||||
|
show grants for user1@localhost;
|
||||||
|
Grants for user1@localhost
|
||||||
|
GRANT USAGE ON *.* TO `user1`@`localhost`
|
||||||
|
GRANT SELECT, LOCK TABLES ON `db1`.* TO `user1`@`localhost`
|
||||||
|
connect con1, localhost, user1, ,db1;
|
||||||
|
BACKUP UNLOCK;
|
||||||
|
ERROR 42000: Access denied; you need (at least one of) the RELOAD, LOCK TABLES privilege(s) for this operation
|
||||||
|
BACKUP LOCK db1.t1;
|
||||||
|
SELECT LOCK_MODE, LOCK_TYPE, TABLE_SCHEMA, TABLE_NAME FROM information_schema.metadata_lock_info;
|
||||||
|
LOCK_MODE LOCK_TYPE TABLE_SCHEMA TABLE_NAME
|
||||||
|
MDL_SHARED_HIGH_PRIO Table metadata lock db1 t1
|
||||||
|
BACKUP UNLOCK;
|
||||||
|
SELECT LOCK_MODE, LOCK_TYPE, TABLE_SCHEMA, TABLE_NAME FROM information_schema.metadata_lock_info;
|
||||||
|
LOCK_MODE LOCK_TYPE TABLE_SCHEMA TABLE_NAME
|
||||||
|
connection default;
|
||||||
|
disconnect con1;
|
||||||
|
revoke lock tables on db1.* from user1@localhost;
|
||||||
|
show grants for user1@localhost;
|
||||||
|
Grants for user1@localhost
|
||||||
|
GRANT USAGE ON *.* TO `user1`@`localhost`
|
||||||
|
GRANT SELECT ON `db1`.* TO `user1`@`localhost`
|
||||||
|
connect con1, localhost, user1, ,db1;
|
||||||
|
BACKUP LOCK db1.t1;
|
||||||
|
ERROR 42000: Access denied; you need (at least one of) the RELOAD, LOCK TABLES privilege(s) for this operation
|
||||||
|
BACKUP UNLOCK;
|
||||||
|
ERROR 42000: Access denied; you need (at least one of) the RELOAD, LOCK TABLES privilege(s) for this operation
|
||||||
|
connection default;
|
||||||
|
disconnect con1;
|
||||||
|
drop database db1;
|
||||||
|
drop user user1@localhost;
|
||||||
|
#
|
||||||
# End of MariaDB 10.4 tests
|
# End of MariaDB 10.4 tests
|
||||||
#
|
#
|
||||||
|
@ -188,6 +188,79 @@ DROP TABLE t3;
|
|||||||
BACKUP UNLOCK;
|
BACKUP UNLOCK;
|
||||||
DROP TABLE t3;
|
DROP TABLE t3;
|
||||||
|
|
||||||
|
--echo #
|
||||||
|
--echo # MDEV-28367: BACKUP LOCKS on table to be accessible to those
|
||||||
|
--echo # with database LOCK TABLES privileges
|
||||||
|
--echo #
|
||||||
|
|
||||||
|
--source include/have_metadata_lock_info.inc
|
||||||
|
create database db1;
|
||||||
|
create table db1.t1(t int);
|
||||||
|
create user user1@localhost;
|
||||||
|
select user,host from mysql.user where user='user1';
|
||||||
|
--replace_result $MASTER_MYSOCK MASTER_SOCKET $MASTER_MYPORT MASTER_PORT
|
||||||
|
--error ER_DBACCESS_DENIED_ERROR
|
||||||
|
--connect (con1, localhost, user1, ,db1)
|
||||||
|
|
||||||
|
grant reload on *.* to user1@localhost;
|
||||||
|
# To access DB one need select privileges
|
||||||
|
grant select on db1.* to user1@localhost;
|
||||||
|
show grants for user1@localhost;
|
||||||
|
--connect (con1, localhost, user1, ,db1)
|
||||||
|
|
||||||
|
# This should work we have RELOAD privilege
|
||||||
|
BACKUP UNLOCK;
|
||||||
|
BACKUP LOCK db1.t1;
|
||||||
|
SELECT LOCK_MODE, LOCK_TYPE, TABLE_SCHEMA, TABLE_NAME FROM information_schema.metadata_lock_info;
|
||||||
|
BACKUP UNLOCK;
|
||||||
|
SELECT LOCK_MODE, LOCK_TYPE, TABLE_SCHEMA, TABLE_NAME FROM information_schema.metadata_lock_info;
|
||||||
|
|
||||||
|
# Add LOCK TABLES DB privileges (all privileges for BACKUP LOCK are there)
|
||||||
|
connection default;
|
||||||
|
disconnect con1;
|
||||||
|
grant lock tables on db1.* to user1@localhost;
|
||||||
|
show grants for user1@localhost;
|
||||||
|
--connect (con1, localhost, user1, ,db1)
|
||||||
|
# This should work we have RELOAD & LOCK privilege
|
||||||
|
BACKUP UNLOCK;
|
||||||
|
BACKUP LOCK db1.t1;
|
||||||
|
SELECT LOCK_MODE, LOCK_TYPE, TABLE_SCHEMA, TABLE_NAME FROM information_schema.metadata_lock_info;
|
||||||
|
BACKUP UNLOCK;
|
||||||
|
SELECT LOCK_MODE, LOCK_TYPE, TABLE_SCHEMA, TABLE_NAME FROM information_schema.metadata_lock_info;
|
||||||
|
|
||||||
|
# Remove reload privilege, leave only LOCK TABLES privilege
|
||||||
|
connection default;
|
||||||
|
disconnect con1;
|
||||||
|
revoke reload on *.* from user1@localhost;
|
||||||
|
show grants for user1@localhost;
|
||||||
|
--connect (con1, localhost, user1, ,db1)
|
||||||
|
# There is no reload priv needed for unlock and there is no mdl_backup_lock taken
|
||||||
|
--error ER_SPECIFIC_ACCESS_DENIED_ERROR
|
||||||
|
BACKUP UNLOCK;
|
||||||
|
# BACKUP LOCK should work, since we have LOCK privilege
|
||||||
|
BACKUP LOCK db1.t1;
|
||||||
|
SELECT LOCK_MODE, LOCK_TYPE, TABLE_SCHEMA, TABLE_NAME FROM information_schema.metadata_lock_info;
|
||||||
|
# This works since there was taken mdl_backup_lock before
|
||||||
|
BACKUP UNLOCK;
|
||||||
|
SELECT LOCK_MODE, LOCK_TYPE, TABLE_SCHEMA, TABLE_NAME FROM information_schema.metadata_lock_info;
|
||||||
|
|
||||||
|
# Remove LOCK TABLES privilege
|
||||||
|
connection default;
|
||||||
|
disconnect con1;
|
||||||
|
revoke lock tables on db1.* from user1@localhost;
|
||||||
|
show grants for user1@localhost;
|
||||||
|
--connect (con1, localhost, user1, ,db1)
|
||||||
|
--error ER_SPECIFIC_ACCESS_DENIED_ERROR
|
||||||
|
BACKUP LOCK db1.t1;
|
||||||
|
--error ER_SPECIFIC_ACCESS_DENIED_ERROR
|
||||||
|
BACKUP UNLOCK;
|
||||||
|
|
||||||
|
connection default;
|
||||||
|
disconnect con1;
|
||||||
|
|
||||||
|
drop database db1;
|
||||||
|
drop user user1@localhost;
|
||||||
|
|
||||||
--echo #
|
--echo #
|
||||||
--echo # End of MariaDB 10.4 tests
|
--echo # End of MariaDB 10.4 tests
|
||||||
--echo #
|
--echo #
|
||||||
|
@ -1951,6 +1951,11 @@ GRANT EXECUTE ON mysqltest_db1.* TO mysqltest_u1@localhost;
|
|||||||
GRANT FILE ON *.* TO mysqltest_u1@localhost;
|
GRANT FILE ON *.* TO mysqltest_u1@localhost;
|
||||||
GRANT CREATE USER ON *.* TO mysqltest_u1@localhost;
|
GRANT CREATE USER ON *.* TO mysqltest_u1@localhost;
|
||||||
GRANT PROCESS ON *.* TO mysqltest_u1@localhost;
|
GRANT PROCESS ON *.* TO mysqltest_u1@localhost;
|
||||||
|
GRANT RELOAD ON mysqltest_db1.* TO mysqltest_u1@localhost;
|
||||||
|
ERROR HY000: Incorrect usage of DB GRANT and GLOBAL PRIVILEGES
|
||||||
|
connect(localhost,mysqltest_u1,,db1,MASTER_PORT,MASTER_SOCKET);
|
||||||
|
connect con1, localhost, mysqltest_u1, ,db1;
|
||||||
|
ERROR 42000: Access denied for user 'mysqltest_u1'@'localhost' to database 'db1'
|
||||||
GRANT RELOAD ON *.* TO mysqltest_u1@localhost;
|
GRANT RELOAD ON *.* TO mysqltest_u1@localhost;
|
||||||
GRANT REPLICATION CLIENT ON *.* TO mysqltest_u1@localhost;
|
GRANT REPLICATION CLIENT ON *.* TO mysqltest_u1@localhost;
|
||||||
GRANT REPLICATION SLAVE ON *.* TO mysqltest_u1@localhost;
|
GRANT REPLICATION SLAVE ON *.* TO mysqltest_u1@localhost;
|
||||||
|
@ -1821,6 +1821,13 @@ GRANT EXECUTE ON mysqltest_db1.* TO mysqltest_u1@localhost;
|
|||||||
GRANT FILE ON *.* TO mysqltest_u1@localhost;
|
GRANT FILE ON *.* TO mysqltest_u1@localhost;
|
||||||
GRANT CREATE USER ON *.* TO mysqltest_u1@localhost;
|
GRANT CREATE USER ON *.* TO mysqltest_u1@localhost;
|
||||||
GRANT PROCESS ON *.* TO mysqltest_u1@localhost;
|
GRANT PROCESS ON *.* TO mysqltest_u1@localhost;
|
||||||
|
# Global privileges should be granted to all schemas, not individual DB
|
||||||
|
--error ER_WRONG_USAGE
|
||||||
|
GRANT RELOAD ON mysqltest_db1.* TO mysqltest_u1@localhost;
|
||||||
|
# Select privilege is needed beside RELOAD privilege
|
||||||
|
--replace_result $MASTER_MYSOCK MASTER_SOCKET $MASTER_MYPORT MASTER_PORT
|
||||||
|
--error ER_DBACCESS_DENIED_ERROR
|
||||||
|
--connect (con1, localhost, mysqltest_u1, ,db1)
|
||||||
GRANT RELOAD ON *.* TO mysqltest_u1@localhost;
|
GRANT RELOAD ON *.* TO mysqltest_u1@localhost;
|
||||||
GRANT REPLICATION CLIENT ON *.* TO mysqltest_u1@localhost;
|
GRANT REPLICATION CLIENT ON *.* TO mysqltest_u1@localhost;
|
||||||
GRANT REPLICATION SLAVE ON *.* TO mysqltest_u1@localhost;
|
GRANT REPLICATION SLAVE ON *.* TO mysqltest_u1@localhost;
|
||||||
|
@ -5153,9 +5153,55 @@ mysql_execute_command(THD *thd)
|
|||||||
my_ok(thd);
|
my_ok(thd);
|
||||||
break;
|
break;
|
||||||
case SQLCOM_BACKUP_LOCK:
|
case SQLCOM_BACKUP_LOCK:
|
||||||
if (check_global_access(thd, RELOAD_ACL))
|
if (check_global_access(thd, RELOAD_ACL, true))
|
||||||
goto error;
|
{
|
||||||
/* first table is set for lock. For unlock the list is empty */
|
#ifndef NO_EMBEDDED_ACCESS_CHECKS
|
||||||
|
/*
|
||||||
|
In case there is no global privilege, check DB privilege for LOCK TABLES.
|
||||||
|
*/
|
||||||
|
if (first_table) // BACKUP LOCK
|
||||||
|
{
|
||||||
|
if (check_single_table_access(thd, LOCK_TABLES_ACL, first_table, true))
|
||||||
|
{
|
||||||
|
char command[30];
|
||||||
|
get_privilege_desc(command, sizeof(command), RELOAD_ACL|LOCK_TABLES_ACL);
|
||||||
|
my_error(ER_SPECIFIC_ACCESS_DENIED_ERROR, MYF(0), command);
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else // BACKUP UNLOCK
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
We test mdl_backup_lock here because, if a user could obtain a lock
|
||||||
|
it would be silly to error and say `you can't BACKUP UNLOCK`
|
||||||
|
(because its obvious you did a `BACKUP LOCK`).
|
||||||
|
As `BACKUP UNLOCK` doesn't have a database reference,
|
||||||
|
there's no way we can check if the `BACKUP LOCK` privilege is missing.
|
||||||
|
Testing `thd->db` would involve faking a `TABLE_LIST` structure,
|
||||||
|
which because of the depth of inspection
|
||||||
|
in `check_single_table_access` makes the faking likely to cause crashes,
|
||||||
|
or unintended effects. The outcome of this is,
|
||||||
|
if a user does an `BACKUP UNLOCK` without a `BACKUP LOCKED` table,
|
||||||
|
there may be a` ER_SPECIFIC_ACCESS_DENIED` error even though
|
||||||
|
user has the privilege.
|
||||||
|
Its a bit different to what happens if the user has RELOAD_ACL,
|
||||||
|
where the error is silently ignored.
|
||||||
|
*/
|
||||||
|
if (!thd->mdl_backup_lock)
|
||||||
|
{
|
||||||
|
|
||||||
|
char command[30];
|
||||||
|
get_privilege_desc(command, sizeof(command), RELOAD_ACL|LOCK_TABLES_ACL);
|
||||||
|
my_error(ER_SPECIFIC_ACCESS_DENIED_ERROR, MYF(0), command);
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
There is reload privilege, first table is set for lock.
|
||||||
|
For unlock the list is empty
|
||||||
|
*/
|
||||||
if (first_table)
|
if (first_table)
|
||||||
res= backup_lock(thd, first_table);
|
res= backup_lock(thd, first_table);
|
||||||
else
|
else
|
||||||
|
Reference in New Issue
Block a user