diff --git a/mysql-test/suite/rpl/r/rpl_do_grant.result b/mysql-test/suite/rpl/r/rpl_do_grant.result index 0d2908809b9eb..0e3b578addad6 100644 --- a/mysql-test/suite/rpl/r/rpl_do_grant.result +++ b/mysql-test/suite/rpl/r/rpl_do_grant.result @@ -211,71 +211,9 @@ connection master; DROP TABLE t1; DROP PROCEDURE p1; connection slave; -### ii) Test case in which REVOKE partially succeeds -connection master; -include/rpl_reset.inc -connection master; -CREATE TABLE t1(c1 INT); -CREATE PROCEDURE p1() SELECT * FROM t1 | -CREATE USER 'user49119'@'localhost'; -GRANT EXECUTE ON PROCEDURE p1 TO 'user49119'@'localhost'; -############################################################## -### Showing grants for both users: root and user49119 (master) -SHOW GRANTS FOR 'user49119'@'localhost'; -Grants for user49119@localhost -GRANT USAGE ON *.* TO `user49119`@`localhost` -GRANT EXECUTE ON PROCEDURE `test`.`p1` TO `user49119`@`localhost` -SHOW GRANTS FOR CURRENT_USER; -Grants for root@localhost -GRANT ALL PRIVILEGES ON *.* TO `root`@`localhost` WITH GRANT OPTION -GRANT PROXY ON ''@'%' TO 'root'@'localhost' WITH GRANT OPTION -############################################################## -connection slave; -############################################################## -### Showing grants for both users: root and user49119 (master) -SHOW GRANTS FOR 'user49119'@'localhost'; -Grants for user49119@localhost -GRANT USAGE ON *.* TO `user49119`@`localhost` -GRANT EXECUTE ON PROCEDURE `test`.`p1` TO `user49119`@`localhost` -SHOW GRANTS FOR CURRENT_USER; -Grants for root@localhost -GRANT ALL PRIVILEGES ON *.* TO `root`@`localhost` WITH GRANT OPTION -GRANT PROXY ON ''@'%' TO 'root'@'localhost' WITH GRANT OPTION -############################################################## -connection master; -## This statement will make the revoke fail because root has no -## execute grant. However, it will still revoke the grant for -## user49119. -REVOKE EXECUTE ON PROCEDURE p1 FROM 'user49119'@'localhost', 'root'@'localhost'; -ERROR 42000: There is no such grant defined for user 'root' on host 'localhost' on routine 'p1' -############################################################## -### Showing grants for both users: root and user49119 (master) -### after revoke statement failure -SHOW GRANTS FOR 'user49119'@'localhost'; -Grants for user49119@localhost -GRANT USAGE ON *.* TO `user49119`@`localhost` -SHOW GRANTS FOR CURRENT_USER; -Grants for root@localhost -GRANT ALL PRIVILEGES ON *.* TO `root`@`localhost` WITH GRANT OPTION -GRANT PROXY ON ''@'%' TO 'root'@'localhost' WITH GRANT OPTION -############################################################## -connection slave; -############################################################# -### Showing grants for both users: root and user49119 (slave) -### after revoke statement failure (should match -SHOW GRANTS FOR 'user49119'@'localhost'; -Grants for user49119@localhost -GRANT USAGE ON *.* TO `user49119`@`localhost` -SHOW GRANTS FOR CURRENT_USER; -Grants for root@localhost -GRANT ALL PRIVILEGES ON *.* TO `root`@`localhost` WITH GRANT OPTION -GRANT PROXY ON ''@'%' TO 'root'@'localhost' WITH GRANT OPTION -############################################################## -connection master; -DROP TABLE t1; -DROP PROCEDURE p1; -DROP USER 'user49119'@'localhost'; -connection slave; +# +# TODO: Re-enable test-case after fixing MDEV-29848 +# include/rpl_reset.inc connection master; grant all on *.* to foo@"1.2.3.4"; diff --git a/mysql-test/suite/rpl/r/rpl_grant.result b/mysql-test/suite/rpl/r/rpl_grant.result index 274a8505fb8a4..9fc752cef9fe8 100644 --- a/mysql-test/suite/rpl/r/rpl_grant.result +++ b/mysql-test/suite/rpl/r/rpl_grant.result @@ -38,4 +38,33 @@ User Host SELECT COUNT(*) FROM mysql.user WHERE user like 'dummy%'; COUNT(*) 0 +# +# MDEV-38506: Failed GRANT on a procedure breaks replication +# +# Disable NO_AUTO_CREATE_USER so grant will auto-create users +connection master; +SET @old_sql_mode= @@GLOBAL.sql_mode; +SET GLOBAL sql_mode=''; +# Create new stored procedure sp to be granted to new role test_role +CREATE PROCEDURE test.sp() SELECT 1; +# Create a new user with limited privileges to grant sp execution to test_role +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; +GRANT EXECUTE ON PROCEDURE test.sp TO 'nonexistentuser'@''; +ERROR 42000: You are not allowed to create a user with GRANT +# Ensuring the failed GRANT is not replicated.. +include/rpl_sync.inc +connection master; +connection slave; +SHOW GRANTS for 'nonexistentuser'@''; +ERROR 42000: There is no such grant defined for user 'nonexistentuser' on host '%' +# ..PASS +connection master; +disconnect con_test_user; +SET GLOBAL sql_mode= @old_sql_mode; +DROP USER test_user@'%'; +DROP PROCEDURE test.sp; +# End of MDEV-38506 test case include/rpl_end.inc +# End of rpl_grant.test diff --git a/mysql-test/suite/rpl/t/rpl_do_grant.test b/mysql-test/suite/rpl/t/rpl_do_grant.test index 2b757f57692d9..323ef9be9e13b 100644 --- a/mysql-test/suite/rpl/t/rpl_do_grant.test +++ b/mysql-test/suite/rpl/t/rpl_do_grant.test @@ -212,8 +212,11 @@ USE test; # when binlogging is active, the master will not hit an # assertion. # -# ii) a test case that partially succeeds on the master will also -# partially succeed on the slave. +# ii) (DISABLED) To pass, this test case took advantage of a vulnerability, +# MDEV-38506. Please uncomment this test case when MDEV-29848 is fixed. +# +# test case that partially succeeds on the master will also +# partially succeed on the slave. # # - The revoke statement that partially succeeds tries to revoke # an EXECUTE grant for two users, and only one of the user has @@ -242,64 +245,67 @@ DROP PROCEDURE p1; -- sync_slave_with_master --- echo ### ii) Test case in which REVOKE partially succeeds - --- connection master --- source include/rpl_reset.inc --- connection master - -CREATE TABLE t1(c1 INT); -DELIMITER |; -CREATE PROCEDURE p1() SELECT * FROM t1 | -DELIMITER ;| - -CREATE USER 'user49119'@'localhost'; -GRANT EXECUTE ON PROCEDURE p1 TO 'user49119'@'localhost'; - --- echo ############################################################## --- echo ### Showing grants for both users: root and user49119 (master) -SHOW GRANTS FOR 'user49119'@'localhost'; -SHOW GRANTS FOR CURRENT_USER; --- echo ############################################################## - --- sync_slave_with_master - --- echo ############################################################## --- echo ### Showing grants for both users: root and user49119 (master) -SHOW GRANTS FOR 'user49119'@'localhost'; -SHOW GRANTS FOR CURRENT_USER; --- echo ############################################################## - --- connection master - --- echo ## This statement will make the revoke fail because root has no --- echo ## execute grant. However, it will still revoke the grant for --- echo ## user49119. --- error ER_NONEXISTING_PROC_GRANT -REVOKE EXECUTE ON PROCEDURE p1 FROM 'user49119'@'localhost', 'root'@'localhost'; - --- echo ############################################################## --- echo ### Showing grants for both users: root and user49119 (master) --- echo ### after revoke statement failure -SHOW GRANTS FOR 'user49119'@'localhost'; -SHOW GRANTS FOR CURRENT_USER; --- echo ############################################################## - --- sync_slave_with_master - --- echo ############################################################# --- echo ### Showing grants for both users: root and user49119 (slave) --- echo ### after revoke statement failure (should match -SHOW GRANTS FOR 'user49119'@'localhost'; -SHOW GRANTS FOR CURRENT_USER; --- echo ############################################################## - --- connection master -DROP TABLE t1; -DROP PROCEDURE p1; -DROP USER 'user49119'@'localhost'; - --- sync_slave_with_master +--echo # +--echo # TODO: Re-enable test-case after fixing MDEV-29848 +--echo # +#-- echo ### ii) Test case in which REVOKE partially succeeds +# +#-- connection master +#-- source include/rpl_reset.inc +#-- connection master +# +#CREATE TABLE t1(c1 INT); +#DELIMITER |; +#CREATE PROCEDURE p1() SELECT * FROM t1 | +#DELIMITER ;| +# +#CREATE USER 'user49119'@'localhost'; +#GRANT EXECUTE ON PROCEDURE p1 TO 'user49119'@'localhost'; +# +#-- echo ############################################################## +#-- echo ### Showing grants for both users: root and user49119 (master) +#SHOW GRANTS FOR 'user49119'@'localhost'; +#SHOW GRANTS FOR CURRENT_USER; +#-- echo ############################################################## +# +#-- sync_slave_with_master +# +#-- echo ############################################################## +#-- echo ### Showing grants for both users: root and user49119 (master) +#SHOW GRANTS FOR 'user49119'@'localhost'; +#SHOW GRANTS FOR CURRENT_USER; +#-- echo ############################################################## +# +#-- connection master +# +#-- echo ## This statement will make the revoke fail because root has no +#-- echo ## execute grant. However, it will still revoke the grant for +#-- echo ## user49119. +#-- error ER_NONEXISTING_PROC_GRANT +#REVOKE EXECUTE ON PROCEDURE p1 FROM 'user49119'@'localhost', 'root'@'localhost'; +# +#-- echo ############################################################## +#-- echo ### Showing grants for both users: root and user49119 (master) +#-- echo ### after revoke statement failure +#SHOW GRANTS FOR 'user49119'@'localhost'; +#SHOW GRANTS FOR CURRENT_USER; +#-- echo ############################################################## +# +#-- sync_slave_with_master +# +#-- echo ############################################################# +#-- echo ### Showing grants for both users: root and user49119 (slave) +#-- echo ### after revoke statement failure (should match) +#SHOW GRANTS FOR 'user49119'@'localhost'; +#SHOW GRANTS FOR CURRENT_USER; +#-- echo ############################################################## +# +#-- connection master +#DROP TABLE t1; +#DROP PROCEDURE p1; +#DROP USER 'user49119'@'localhost'; +# +#-- sync_slave_with_master # # Bug #51987 revoke privileges logs wrong error code diff --git a/mysql-test/suite/rpl/t/rpl_grant.test b/mysql-test/suite/rpl/t/rpl_grant.test index 0220645380ab7..cd3ed4ec2a684 100644 --- a/mysql-test/suite/rpl/t/rpl_grant.test +++ b/mysql-test/suite/rpl/t/rpl_grant.test @@ -34,4 +34,47 @@ 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 diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc index 422ea6b008b36..4fdc6656b9e6d 100644 --- a/sql/sql_acl.cc +++ b/sql/sql_acl.cc @@ -7519,7 +7519,7 @@ bool mysql_routine_grant(THD *thd, TABLE_LIST *table_list, thd->mem_root= old_root; mysql_mutex_unlock(&acl_cache->lock); - if (write_to_binlog) + if (write_to_binlog && !result) { if (write_bin_log(thd, FALSE, thd->query(), thd->query_length())) result= TRUE;