From: Dmitry Lenev Date: September 28 2010 4:11pm Subject: bzr commit into mysql-5.5-runtime branch (Dmitry.Lenev:3146) Bug#57061 List-Archive: http://lists.mysql.com/commits/119304 X-Bug: 57061 Message-Id: <20100928161129.1ED0B1E5452@mockturtle> MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="===============1050561087==" --===============1050561087== MIME-Version: 1.0 Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit Content-Disposition: inline #At file:///home/dlenev/src/bzr/mysql-5.5-rt-57061/ based on revid:jon.hauglid@stripped 3146 Dmitry Lenev 2010-09-28 Fix for bug#57061 "User without privilege on routine can discover its existence". The problem was that user without any privileges on routine was able to find out whether it existed or not. DROP FUNCTION and DROP PROCEDURE statements were checking if routine being dropped existed and reported ER_SP_DOES_NOT_EXIST error/warning before checking if user had enough privileges to drop it. This patch solves this problem by changing code not to check if routine exists before checking if user has enough privileges to drop it. Moreover we no longer perform this check using a separate call instead we rely on sp_drop_routine() returning SP_KEY_NOT_FOUND if routine doesn't exist. This change also simplifies one of upcoming patches refactoring global read lock implementation. @ mysql-test/r/grant.result Updated test case after fixing bug#57061 "User without privilege on routine can discover its existence". Removed DROP PROCEDURE/FUNCTION statements which have started to fail after this fix (correctly). There is no need in dropping routines in freshly created database anyway. @ mysql-test/r/sp-security.result Added new test case for bug#57061 "User without privilege on routine can discover its existence". Updated existing tests according to new behaviour. @ mysql-test/suite/funcs_1/r/innodb_storedproc_06.result Updated test case after fixing bug#57061 "User without privilege on routine can discover its existence". Now we drop routines under user which has enough privileges to do so. @ mysql-test/suite/funcs_1/r/memory_storedproc_06.result Updated test case after fixing bug#57061 "User without privilege on routine can discover its existence". Now we drop routines under user which has enough privileges to do so. @ mysql-test/suite/funcs_1/r/myisam_storedproc_06.result Updated test case after fixing bug#57061 "User without privilege on routine can discover its existence". Now we drop routines under user which has enough privileges to do so. @ mysql-test/suite/funcs_1/storedproc/storedproc_06.inc Updated test case after fixing bug#57061 "User without privilege on routine can discover its existence". Now we drop routines under user which has enough privileges to do so. @ mysql-test/t/grant.test Updated test case after fixing bug#57061 "User without privilege on routine can discover its existence". Removed DROP PROCEDURE/FUNCTION statements which have started to fail after this fix (correctly). There is no need in dropping routines in freshly created database anyway. @ mysql-test/t/sp-security.test Added new test case for bug#57061 "User without privilege on routine can discover its existence". Updated existing tests according to new behaviour. @ sql/sp.cc Removed sp_routine_exists_in_table() which is no longer used. @ sql/sp.h Removed sp_routine_exists_in_table() which is no longer used. @ sql/sql_parse.cc When dropping routine we no longer check if routine exists before checking if user has enough privileges to do so. Moreover we no longer perform this check using a separate call instead we rely on sp_drop_routine() returning SP_KEY_NOT_FOUND if routine doesn't exist. modified: mysql-test/r/grant.result mysql-test/r/sp-security.result mysql-test/suite/funcs_1/r/innodb_storedproc_06.result mysql-test/suite/funcs_1/r/memory_storedproc_06.result mysql-test/suite/funcs_1/r/myisam_storedproc_06.result mysql-test/suite/funcs_1/storedproc/storedproc_06.inc mysql-test/t/grant.test mysql-test/t/sp-security.test sql/sp.cc sql/sp.h sql/sql_parse.cc === modified file 'mysql-test/r/grant.result' --- a/mysql-test/r/grant.result 2010-08-05 12:53:09 +0000 +++ b/mysql-test/r/grant.result 2010-09-28 16:11:08 +0000 @@ -1324,8 +1324,6 @@ CREATE USER 'userbug33464'@'localhost'; GRANT CREATE ROUTINE ON dbbug33464.* TO 'userbug33464'@'localhost'; userbug33464@localhost dbbug33464 -DROP PROCEDURE IF EXISTS sp3; -DROP FUNCTION IF EXISTS fn1; CREATE PROCEDURE sp3(v1 char(20)) BEGIN SELECT * from dbbug33464.t6 where t6.f2= 'xyz'; === modified file 'mysql-test/r/sp-security.result' --- a/mysql-test/r/sp-security.result 2010-03-01 09:45:36 +0000 +++ b/mysql-test/r/sp-security.result 2010-09-28 16:11:08 +0000 @@ -44,7 +44,7 @@ ERROR 42000: SELECT command denied to us create procedure db1_secret.dummy() begin end; ERROR 42000: Access denied for user 'user1'@'localhost' to database 'db1_secret' drop procedure db1_secret.dummy; -ERROR 42000: PROCEDURE db1_secret.dummy does not exist +ERROR 42000: alter routine command denied to user 'user1'@'localhost' for routine 'db1_secret.dummy' drop procedure db1_secret.stamp; ERROR 42000: alter routine command denied to user 'user1'@'localhost' for routine 'db1_secret.stamp' drop function db1_secret.db; @@ -58,7 +58,7 @@ ERROR 42000: SELECT command denied to us create procedure db1_secret.dummy() begin end; ERROR 42000: Access denied for user ''@'%' to database 'db1_secret' drop procedure db1_secret.dummy; -ERROR 42000: PROCEDURE db1_secret.dummy does not exist +ERROR 42000: alter routine command denied to user ''@'%' for routine 'db1_secret.dummy' drop procedure db1_secret.stamp; ERROR 42000: alter routine command denied to user ''@'%' for routine 'db1_secret.stamp' drop function db1_secret.db; @@ -567,3 +567,28 @@ DROP USER 'tester'; DROP USER 'Tester'; DROP DATABASE B48872; End of 5.0 tests. +# +# Test for bug#57061 "User without privilege on routine can discover +# its existence." +# +drop database if exists mysqltest_db; +create database mysqltest_db; +# Create user with no privileges on mysqltest_db database. +create user bug57061_user@localhost; +create function mysqltest_db.f1() returns int return 0; +create procedure mysqltest_db.p1() begin end; +# Connect as user 'bug57061_user@localhost' +# Attempt to drop routine on which user doesn't have privileges +# should result in the same 'access denied' type of error whether +# routine exists or not. +drop function if exists mysqltest_db.f_does_not_exist; +ERROR 42000: alter routine command denied to user 'bug57061_user'@'localhost' for routine 'mysqltest_db.f_does_not_exist' +drop procedure if exists mysqltest_db.p_does_not_exist; +ERROR 42000: alter routine command denied to user 'bug57061_user'@'localhost' for routine 'mysqltest_db.p_does_not_exist' +drop function if exists mysqltest_db.f1; +ERROR 42000: alter routine command denied to user 'bug57061_user'@'localhost' for routine 'mysqltest_db.f1' +drop procedure if exists mysqltest_db.p1; +ERROR 42000: alter routine command denied to user 'bug57061_user'@'localhost' for routine 'mysqltest_db.p1' +# Connection 'default'. +drop user bug57061_user@localhost; +drop database mysqltest_db; === modified file 'mysql-test/suite/funcs_1/r/innodb_storedproc_06.result' --- a/mysql-test/suite/funcs_1/r/innodb_storedproc_06.result 2010-03-19 08:56:26 +0000 +++ b/mysql-test/suite/funcs_1/r/innodb_storedproc_06.result 2010-09-28 16:11:08 +0000 @@ -110,10 +110,10 @@ Ensure that root always has the GRANT CR -------------------------------------------------------------------------------- grant create routine on db_storedproc_1.* to 'user_1'@'localhost'; flush privileges; +DROP PROCEDURE IF EXISTS db_storedproc_1.sp3; +DROP FUNCTION IF EXISTS db_storedproc_1.fn1; user_1@localhost db_storedproc_1 -DROP PROCEDURE IF EXISTS sp3; -DROP FUNCTION IF EXISTS fn1; CREATE PROCEDURE sp3(v1 char(20)) BEGIN SELECT * from db_storedproc_1.t6 where t6.f2= 'xyz'; === modified file 'mysql-test/suite/funcs_1/r/memory_storedproc_06.result' --- a/mysql-test/suite/funcs_1/r/memory_storedproc_06.result 2010-03-19 08:56:26 +0000 +++ b/mysql-test/suite/funcs_1/r/memory_storedproc_06.result 2010-09-28 16:11:08 +0000 @@ -111,10 +111,10 @@ Ensure that root always has the GRANT CR -------------------------------------------------------------------------------- grant create routine on db_storedproc_1.* to 'user_1'@'localhost'; flush privileges; +DROP PROCEDURE IF EXISTS db_storedproc_1.sp3; +DROP FUNCTION IF EXISTS db_storedproc_1.fn1; user_1@localhost db_storedproc_1 -DROP PROCEDURE IF EXISTS sp3; -DROP FUNCTION IF EXISTS fn1; CREATE PROCEDURE sp3(v1 char(20)) BEGIN SELECT * from db_storedproc_1.t6 where t6.f2= 'xyz'; === modified file 'mysql-test/suite/funcs_1/r/myisam_storedproc_06.result' --- a/mysql-test/suite/funcs_1/r/myisam_storedproc_06.result 2010-03-19 08:56:26 +0000 +++ b/mysql-test/suite/funcs_1/r/myisam_storedproc_06.result 2010-09-28 16:11:08 +0000 @@ -111,10 +111,10 @@ Ensure that root always has the GRANT CR -------------------------------------------------------------------------------- grant create routine on db_storedproc_1.* to 'user_1'@'localhost'; flush privileges; +DROP PROCEDURE IF EXISTS db_storedproc_1.sp3; +DROP FUNCTION IF EXISTS db_storedproc_1.fn1; user_1@localhost db_storedproc_1 -DROP PROCEDURE IF EXISTS sp3; -DROP FUNCTION IF EXISTS fn1; CREATE PROCEDURE sp3(v1 char(20)) BEGIN SELECT * from db_storedproc_1.t6 where t6.f2= 'xyz'; === modified file 'mysql-test/suite/funcs_1/storedproc/storedproc_06.inc' --- a/mysql-test/suite/funcs_1/storedproc/storedproc_06.inc 2010-03-19 08:56:26 +0000 +++ b/mysql-test/suite/funcs_1/storedproc/storedproc_06.inc 2010-09-28 16:11:08 +0000 @@ -117,15 +117,15 @@ create user 'user_1'@'localhost'; grant create routine on db_storedproc_1.* to 'user_1'@'localhost'; flush privileges; +--disable_warnings +DROP PROCEDURE IF EXISTS db_storedproc_1.sp3; +DROP FUNCTION IF EXISTS db_storedproc_1.fn1; +--enable_warnings + # disconnect default; connect (user2, localhost, user_1, , db_storedproc_1); --source suite/funcs_1/include/show_connection.inc ---disable_warnings -DROP PROCEDURE IF EXISTS sp3; -DROP FUNCTION IF EXISTS fn1; ---enable_warnings - delimiter //; CREATE PROCEDURE sp3(v1 char(20)) BEGIN === modified file 'mysql-test/t/grant.test' --- a/mysql-test/t/grant.test 2010-08-05 12:53:09 +0000 +++ b/mysql-test/t/grant.test 2010-09-28 16:11:08 +0000 @@ -1419,11 +1419,6 @@ GRANT CREATE ROUTINE ON dbbug33464.* TO connect (connbug33464, localhost, userbug33464, , dbbug33464); --source suite/funcs_1/include/show_connection.inc ---disable_warnings -DROP PROCEDURE IF EXISTS sp3; -DROP FUNCTION IF EXISTS fn1; ---enable_warnings - delimiter //; CREATE PROCEDURE sp3(v1 char(20)) BEGIN === modified file 'mysql-test/t/sp-security.test' --- a/mysql-test/t/sp-security.test 2010-02-26 13:16:46 +0000 +++ b/mysql-test/t/sp-security.test 2010-09-28 16:11:08 +0000 @@ -82,7 +82,7 @@ select * from db1_secret.t1; # ...and not this --error ER_DBACCESS_DENIED_ERROR create procedure db1_secret.dummy() begin end; ---error ER_SP_DOES_NOT_EXIST +--error ER_PROCACCESS_DENIED_ERROR drop procedure db1_secret.dummy; --error ER_PROCACCESS_DENIED_ERROR drop procedure db1_secret.stamp; @@ -106,7 +106,7 @@ select * from db1_secret.t1; # ...and not this --error ER_DBACCESS_DENIED_ERROR create procedure db1_secret.dummy() begin end; ---error ER_SP_DOES_NOT_EXIST +--error ER_PROCACCESS_DENIED_ERROR drop procedure db1_secret.dummy; --error ER_PROCACCESS_DENIED_ERROR drop procedure db1_secret.stamp; @@ -926,6 +926,39 @@ DROP DATABASE B48872; --echo End of 5.0 tests. + +--echo # +--echo # Test for bug#57061 "User without privilege on routine can discover +--echo # its existence." +--echo # +--disable_warnings +drop database if exists mysqltest_db; +--enable_warnings +create database mysqltest_db; +--echo # Create user with no privileges on mysqltest_db database. +create user bug57061_user@localhost; +create function mysqltest_db.f1() returns int return 0; +create procedure mysqltest_db.p1() begin end; +--echo # Connect as user 'bug57061_user@localhost' +connect (conn1, localhost, bug57061_user,,); +--echo # Attempt to drop routine on which user doesn't have privileges +--echo # should result in the same 'access denied' type of error whether +--echo # routine exists or not. +--error ER_PROCACCESS_DENIED_ERROR +drop function if exists mysqltest_db.f_does_not_exist; +--error ER_PROCACCESS_DENIED_ERROR +drop procedure if exists mysqltest_db.p_does_not_exist; +--error ER_PROCACCESS_DENIED_ERROR +drop function if exists mysqltest_db.f1; +--error ER_PROCACCESS_DENIED_ERROR +drop procedure if exists mysqltest_db.p1; +--echo # Connection 'default'. +connection default; +disconnect conn1; +drop user bug57061_user@localhost; +drop database mysqltest_db; + + # Wait till all disconnects are completed --source include/wait_until_count_sessions.inc === modified file 'sql/sp.cc' --- a/sql/sp.cc 2010-08-31 09:04:19 +0000 +++ b/sql/sp.cc 2010-09-28 16:11:08 +0000 @@ -1636,38 +1636,6 @@ sp_exist_routines(THD *thd, TABLE_LIST * } -/** - Check if a routine exists in the mysql.proc table, without actually - parsing the definition. (Used for dropping). - - @param thd thread context - @param name name of procedure - - @retval - 0 Success - @retval - non-0 Error; SP_OPEN_TABLE_FAILED or SP_KEY_NOT_FOUND -*/ - -int -sp_routine_exists_in_table(THD *thd, int type, sp_name *name) -{ - TABLE *table; - int ret; - Open_tables_backup open_tables_state_backup; - - if (!(table= open_proc_table_for_read(thd, &open_tables_state_backup))) - ret= SP_OPEN_TABLE_FAILED; - else - { - if ((ret= db_find_routine_aux(thd, type, name, table)) != SP_OK) - ret= SP_KEY_NOT_FOUND; - close_system_tables(thd, &open_tables_state_backup); - } - return ret; -} - - extern "C" uchar* sp_sroutine_key(const uchar *ptr, size_t *plen, my_bool first) { === modified file 'sql/sp.h' --- a/sql/sp.h 2010-06-11 01:30:49 +0000 +++ b/sql/sp.h 2010-09-28 16:11:08 +0000 @@ -100,9 +100,6 @@ sp_cache_routine(THD *thd, int type, sp_ bool sp_exist_routines(THD *thd, TABLE_LIST *procs, bool any); -int -sp_routine_exists_in_table(THD *thd, int type, sp_name *name); - bool sp_show_create_routine(THD *thd, int type, sp_name *name); === modified file 'sql/sql_parse.cc' --- a/sql/sql_parse.cc 2010-09-22 08:15:41 +0000 +++ b/sql/sql_parse.cc 2010-09-28 16:11:08 +0000 @@ -4085,49 +4085,39 @@ create_sp_error: int sp_result; int type= (lex->sql_command == SQLCOM_DROP_PROCEDURE ? TYPE_ENUM_PROCEDURE : TYPE_ENUM_FUNCTION); + char *db= lex->spname->m_db.str; + char *name= lex->spname->m_name.str; - /* - @todo: here we break the metadata locking protocol by - looking up the information about the routine without - a metadata lock. Rewrite this piece to make sp_drop_routine - return whether the routine existed or not. - */ - sp_result= sp_routine_exists_in_table(thd, type, lex->spname); - thd->warning_info->opt_clear_warning_info(thd->query_id); - if (sp_result == SP_OK) - { - char *db= lex->spname->m_db.str; - char *name= lex->spname->m_name.str; - - if (check_routine_access(thd, ALTER_PROC_ACL, db, name, - lex->sql_command == SQLCOM_DROP_PROCEDURE, 0)) - goto error; + if (check_routine_access(thd, ALTER_PROC_ACL, db, name, + lex->sql_command == SQLCOM_DROP_PROCEDURE, 0)) + goto error; - /* Conditionally writes to binlog */ - sp_result= sp_drop_routine(thd, type, lex->spname); + /* Conditionally writes to binlog */ + sp_result= sp_drop_routine(thd, type, lex->spname); #ifndef NO_EMBEDDED_ACCESS_CHECKS - /* - We're going to issue an implicit REVOKE statement. - It takes metadata locks and updates system tables. - Make sure that sp_create_routine() did not leave any - locks in the MDL context, so there is no risk to - deadlock. - */ - close_mysql_tables(thd); + /* + We're going to issue an implicit REVOKE statement. + It takes metadata locks and updates system tables. + Make sure that sp_create_routine() did not leave any + locks in the MDL context, so there is no risk to + deadlock. + */ + close_mysql_tables(thd); - if (sp_automatic_privileges && !opt_noacl && - sp_revoke_privileges(thd, db, name, - lex->sql_command == SQLCOM_DROP_PROCEDURE)) - { - push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN, - ER_PROC_AUTO_REVOKE_FAIL, - ER(ER_PROC_AUTO_REVOKE_FAIL)); - /* If this happens, an error should have been reported. */ - goto error; - } -#endif + if (sp_result != SP_KEY_NOT_FOUND && + sp_automatic_privileges && !opt_noacl && + sp_revoke_privileges(thd, db, name, + lex->sql_command == SQLCOM_DROP_PROCEDURE)) + { + push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN, + ER_PROC_AUTO_REVOKE_FAIL, + ER(ER_PROC_AUTO_REVOKE_FAIL)); + /* If this happens, an error should have been reported. */ + goto error; } +#endif + res= sp_result; switch (sp_result) { case SP_OK: --===============1050561087== MIME-Version: 1.0 Content-Type: text/bzr-bundle; charset="us-ascii"; name="bzr/dmitry.lenev@stripped" Content-Transfer-Encoding: 7bit Content-Disposition: inline # Bazaar merge directive format 2 (Bazaar 0.90) # revision_id: dmitry.lenev@stripped # target_branch: file:///home/dlenev/src/bzr/mysql-5.5-rt-57061/ # testament_sha1: dd3182036d09a5b2be0075c55e1b3f8a3a867be3 # timestamp: 2010-09-28 20:11:28 +0400 # base_revision_id: jon.hauglid@stripped\ # e1b5fpajkv23cab3 # # Begin bundle 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 3ELZSItJV0DqxVw1irzdgu5IpwoSBpXC7qA= --===============1050561087==--