mirror of
https://github.com/MariaDB/server.git
synced 2026-02-12 05:38:42 +01:00
When GRANT EXECUTE ON PROCEDURE fails on the master, it will erroneously be replicated and executed successfully on the slave. This both breaks replication and is a security violation. The underlying issue is that a failed GRANT EXECUTE ON PROCEDURE will still be replicated when sql_mode does not have NO_AUTO_CREATE_USER. This is because the function mysql_routine_grant() does not check if an error occured while performing the GRANT before binlogging, it simply always binlogs. This patch fixes this problem by checking if an error happened previously before binlogging, and if so, then skip binlogging. Note there is still a broader issue in this area leading to replication divergence. Reported in MDEV-29848, a partially-completed GRANT statment (where some earlier GRANTS succeed and a later fails) will not binlog. Note this affects all grant types, whereas the issue addressed in this patch is limited to GRANT EXECUTE ON PROCEDURE. This patch makes GRANT EXECUTE ON PROCEDURE binlogging behavior consistent with the other grant types. A separate follow-up patch will address the broader MDEV-29848 issue. Also note that a test case in rpl_do_grant.test took advantage of MDEV-38506 so a partially-failing REVOKE EXECUTE ON PROCEDURE would still replicate. This test case is disabled with a TODO note to re-enable it once MDEV-29848 is fixed Reviewed-by: Sergei Golubchik <serg@mariadb.org> Signed-off-by: Brandon Nesterenko <brandon.nesterenko@mariadb.com>
80 lines
2.4 KiB
Text
80 lines
2.4 KiB
Text
# Tests of grants and users
|
|
|
|
source include/not_embedded.inc;
|
|
source include/master-slave.inc;
|
|
|
|
connection master;
|
|
|
|
CREATE USER dummy@localhost;
|
|
CREATE USER dummy1@localhost, dummy2@localhost;
|
|
|
|
SELECT user, host FROM mysql.user WHERE user like 'dummy%';
|
|
SELECT COUNT(*) FROM mysql.user WHERE user like 'dummy%';
|
|
sync_slave_with_master;
|
|
--echo **** On Slave ****
|
|
SELECT user,host FROM mysql.user WHERE user like 'dummy%';
|
|
SELECT COUNT(*) FROM mysql.user WHERE user like 'dummy%';
|
|
|
|
connection master;
|
|
|
|
# No user exists
|
|
error ER_CANNOT_USER;
|
|
DROP USER nonexisting@localhost;
|
|
|
|
# At least one user exists, but not all
|
|
error ER_CANNOT_USER;
|
|
DROP USER nonexisting@localhost, dummy@localhost;
|
|
|
|
# All users exist
|
|
DROP USER dummy1@localhost, dummy2@localhost;
|
|
|
|
SELECT user, host FROM mysql.user WHERE user like 'dummy%';
|
|
SELECT COUNT(*) FROM mysql.user WHERE user like 'dummy%';
|
|
sync_slave_with_master;
|
|
SELECT user,host FROM mysql.user WHERE user like 'dummy%';
|
|
SELECT COUNT(*) FROM mysql.user WHERE user like 'dummy%';
|
|
|
|
--echo #
|
|
--echo # MDEV-38506: Failed GRANT on a procedure breaks replication
|
|
--echo #
|
|
|
|
--echo # Disable NO_AUTO_CREATE_USER so grant will auto-create users
|
|
connection master;
|
|
SET @old_sql_mode= @@GLOBAL.sql_mode;
|
|
SET GLOBAL sql_mode='';
|
|
|
|
--echo # Create new stored procedure for GRANT EXECUTE ON PROCEDURE
|
|
CREATE PROCEDURE test.sp() SELECT 1;
|
|
|
|
--echo # Create a new user with limited privileges to grant sp execution
|
|
CREATE USER 'test_user'@'%' IDENTIFIED BY 'somepass';
|
|
GRANT EXECUTE ON test.* TO 'test_user'@'%' WITH GRANT OPTION;
|
|
connect (con_test_user,localhost,test_user,somepass);
|
|
let $old_binlog_gtid= `SELECT @@global.gtid_binlog_pos`; # Tag the GTID before the failed GRANT
|
|
error ER_CANT_CREATE_USER_WITH_GRANT;
|
|
GRANT EXECUTE ON PROCEDURE test.sp TO 'nonexistentuser'@'';
|
|
|
|
--echo # Ensuring the failed GRANT is not replicated..
|
|
source include/rpl_sync.inc;
|
|
connection master;
|
|
let $new_binlog_gtid= `SELECT @@global.gtid_binlog_pos`;
|
|
if (`SELECT strcmp('$old_binlog_gtid', '$new_binlog_gtid') != 0`)
|
|
{
|
|
--echo # binlog_gtid_pos before GRANT: $old_binlog_gtid
|
|
--echo # binlog_gtid_pos after GRANT: $new_binlog_gtid
|
|
--die Failed GRANT was binlogged
|
|
}
|
|
connection slave;
|
|
error ER_NONEXISTING_GRANT;
|
|
SHOW GRANTS for 'nonexistentuser'@'';
|
|
--echo # ..PASS
|
|
|
|
connection master;
|
|
disconnect con_test_user;
|
|
SET GLOBAL sql_mode= @old_sql_mode;
|
|
DROP USER test_user@'%';
|
|
DROP PROCEDURE test.sp;
|
|
--echo # End of MDEV-38506 test case
|
|
|
|
--source include/rpl_end.inc
|
|
--echo # End of rpl_grant.test
|