Commit 7b1b744f authored by Sergei Golubchik's avatar Sergei Golubchik

MDEV-5849 MySQL bug#12602983 - User without privilege on routine can discover...

MDEV-5849 MySQL bug#12602983 - User without privilege on routine can discover its existence by executing "select non_existing_func();" or by "call non_existing_proc()"

add or move privilege checks before existence checks
parent 9ff0c9f7
...@@ -44,7 +44,7 @@ f1(1) ...@@ -44,7 +44,7 @@ f1(1)
call p1(); call p1();
ERROR 42000: execute command denied to user 'USER_1'@'localhost' for routine 'db1.p1' ERROR 42000: execute command denied to user 'USER_1'@'localhost' for routine 'db1.p1'
call P1(); call P1();
ERROR 42000: execute command denied to user 'USER_1'@'localhost' for routine 'db1.p1' ERROR 42000: execute command denied to user 'USER_1'@'localhost' for routine 'db1.P1'
select f1(1); select f1(1);
ERROR 42000: execute command denied to user 'USER_1'@'localhost' for routine 'db1.f1' ERROR 42000: execute command denied to user 'USER_1'@'localhost' for routine 'db1.f1'
REVOKE ALL PRIVILEGES, GRANT OPTION FROM user_1@localhost; REVOKE ALL PRIVILEGES, GRANT OPTION FROM user_1@localhost;
......
...@@ -617,3 +617,33 @@ SELECT 1 latin1 latin1_swedish_ci latin1_swedish_ci ...@@ -617,3 +617,33 @@ SELECT 1 latin1 latin1_swedish_ci latin1_swedish_ci
# Connection default # Connection default
DROP USER user2@localhost; DROP USER user2@localhost;
DROP DATABASE db1; DROP DATABASE db1;
#
# Test for bug#12602983 - User without privilege on routine can discover
# its existence by executing "select non_existing_func();" or by
# "call non_existing_proc()";
#
drop database if exists mysqltest_db;
create database mysqltest_db;
create function mysqltest_db.f1() returns int return 0;
create procedure mysqltest_db.p1() begin end;
# Create user with no privileges on mysqltest_db database.
create user bug12602983_user@localhost;
# Connect as user 'bug12602983_user@localhost'
# Attempt to execute routine on which user doesn't have privileges
# should result in the same 'access denied' error whether
# routine exists or not.
select mysqltest_db.f_does_not_exist();
ERROR 42000: execute command denied to user 'bug12602983_user'@'localhost' for routine 'mysqltest_db.f_does_not_exist'
call mysqltest_db.p_does_not_exist();
ERROR 42000: execute command denied to user 'bug12602983_user'@'localhost' for routine 'mysqltest_db.p_does_not_exist'
select mysqltest_db.f1();
ERROR 42000: execute command denied to user 'bug12602983_user'@'localhost' for routine 'mysqltest_db.f1'
call mysqltest_db.p1();
ERROR 42000: execute command denied to user 'bug12602983_user'@'localhost' for routine 'mysqltest_db.p1'
create view bug12602983_v1 as select mysqltest_db.f_does_not_exist();
ERROR 42000: execute command denied to user 'bug12602983_user'@'localhost' for routine 'mysqltest_db.f_does_not_exist'
create view bug12602983_v1 as select mysqltest_db.f1();
ERROR 42000: execute command denied to user 'bug12602983_user'@'localhost' for routine 'mysqltest_db.f1'
# Connection 'default'.
drop user bug12602983_user@localhost;
drop database mysqltest_db;
...@@ -995,6 +995,47 @@ disconnect con2; ...@@ -995,6 +995,47 @@ disconnect con2;
DROP USER user2@localhost; DROP USER user2@localhost;
DROP DATABASE db1; DROP DATABASE db1;
--echo #
--echo # Test for bug#12602983 - User without privilege on routine can discover
--echo # its existence by executing "select non_existing_func();" or by
--echo # "call non_existing_proc()";
--echo #
--disable_warnings
drop database if exists mysqltest_db;
--enable_warnings
create database mysqltest_db;
create function mysqltest_db.f1() returns int return 0;
create procedure mysqltest_db.p1() begin end;
--echo # Create user with no privileges on mysqltest_db database.
create user bug12602983_user@localhost;
--echo # Connect as user 'bug12602983_user@localhost'
connect (conn1, localhost, bug12602983_user,,);
--echo # Attempt to execute routine on which user doesn't have privileges
--echo # should result in the same 'access denied' error whether
--echo # routine exists or not.
--error ER_PROCACCESS_DENIED_ERROR
select mysqltest_db.f_does_not_exist();
--error ER_PROCACCESS_DENIED_ERROR
call mysqltest_db.p_does_not_exist();
--error ER_PROCACCESS_DENIED_ERROR
select mysqltest_db.f1();
--error ER_PROCACCESS_DENIED_ERROR
call mysqltest_db.p1();
--error ER_PROCACCESS_DENIED_ERROR
create view bug12602983_v1 as select mysqltest_db.f_does_not_exist();
--error ER_PROCACCESS_DENIED_ERROR
create view bug12602983_v1 as select mysqltest_db.f1();
--echo # Connection 'default'.
connection default;
disconnect conn1;
drop user bug12602983_user@localhost;
drop database mysqltest_db;
# Wait till all disconnects are completed # Wait till all disconnects are completed
--source include/wait_until_count_sessions.inc --source include/wait_until_count_sessions.inc
......
...@@ -6741,22 +6741,18 @@ Item_func_sp::execute_impl(THD *thd) ...@@ -6741,22 +6741,18 @@ Item_func_sp::execute_impl(THD *thd)
{ {
bool err_status= TRUE; bool err_status= TRUE;
Sub_statement_state statement_state; Sub_statement_state statement_state;
#ifndef NO_EMBEDDED_ACCESS_CHECKS
Security_context *save_security_ctx= thd->security_ctx; Security_context *save_security_ctx= thd->security_ctx;
#endif
enum enum_sp_data_access access= enum enum_sp_data_access access=
(m_sp->m_chistics->daccess == SP_DEFAULT_ACCESS) ? (m_sp->m_chistics->daccess == SP_DEFAULT_ACCESS) ?
SP_DEFAULT_ACCESS_MAPPING : m_sp->m_chistics->daccess; SP_DEFAULT_ACCESS_MAPPING : m_sp->m_chistics->daccess;
DBUG_ENTER("Item_func_sp::execute_impl"); DBUG_ENTER("Item_func_sp::execute_impl");
#ifndef NO_EMBEDDED_ACCESS_CHECKS
if (context->security_ctx) if (context->security_ctx)
{ {
/* Set view definer security context */ /* Set view definer security context */
thd->security_ctx= context->security_ctx; thd->security_ctx= context->security_ctx;
} }
#endif
if (sp_check_access(thd)) if (sp_check_access(thd))
goto error; goto error;
...@@ -6784,9 +6780,7 @@ Item_func_sp::execute_impl(THD *thd) ...@@ -6784,9 +6780,7 @@ Item_func_sp::execute_impl(THD *thd)
thd->restore_sub_statement_state(&statement_state); thd->restore_sub_statement_state(&statement_state);
error: error:
#ifndef NO_EMBEDDED_ACCESS_CHECKS
thd->security_ctx= save_security_ctx; thd->security_ctx= save_security_ctx;
#endif
DBUG_RETURN(err_status); DBUG_RETURN(err_status);
} }
...@@ -6857,11 +6851,9 @@ Item_func_sp::sp_check_access(THD *thd) ...@@ -6857,11 +6851,9 @@ Item_func_sp::sp_check_access(THD *thd)
{ {
DBUG_ENTER("Item_func_sp::sp_check_access"); DBUG_ENTER("Item_func_sp::sp_check_access");
DBUG_ASSERT(m_sp); DBUG_ASSERT(m_sp);
#ifndef NO_EMBEDDED_ACCESS_CHECKS
if (check_routine_access(thd, EXECUTE_ACL, if (check_routine_access(thd, EXECUTE_ACL,
m_sp->m_db.str, m_sp->m_name.str, 0, FALSE)) m_sp->m_db.str, m_sp->m_name.str, 0, FALSE))
DBUG_RETURN(TRUE); DBUG_RETURN(TRUE);
#endif
DBUG_RETURN(FALSE); DBUG_RETURN(FALSE);
} }
...@@ -6874,6 +6866,28 @@ Item_func_sp::fix_fields(THD *thd, Item **ref) ...@@ -6874,6 +6866,28 @@ Item_func_sp::fix_fields(THD *thd, Item **ref)
DBUG_ENTER("Item_func_sp::fix_fields"); DBUG_ENTER("Item_func_sp::fix_fields");
DBUG_ASSERT(fixed == 0); DBUG_ASSERT(fixed == 0);
/*
Checking privileges to execute the function while creating view and
executing the function of select.
*/
if (!(thd->lex->context_analysis_only & CONTEXT_ANALYSIS_ONLY_VIEW) ||
(thd->lex->sql_command == SQLCOM_CREATE_VIEW))
{
Security_context *save_security_ctx= thd->security_ctx;
if (context->security_ctx)
thd->security_ctx= context->security_ctx;
res= check_routine_access(thd, EXECUTE_ACL, m_name->m_db.str,
m_name->m_name.str, 0, FALSE);
thd->security_ctx= save_security_ctx;
if (res)
{
context->process_error(thd);
DBUG_RETURN(res);
}
}
/* /*
We must call init_result_field before Item_func::fix_fields() We must call init_result_field before Item_func::fix_fields()
to make m_sp and result_field members available to fix_length_and_dec(), to make m_sp and result_field members available to fix_length_and_dec(),
......
...@@ -4642,6 +4642,10 @@ case SQLCOM_PREPARE: ...@@ -4642,6 +4642,10 @@ case SQLCOM_PREPARE:
open_and_lock_tables(thd, all_tables, TRUE, 0)) open_and_lock_tables(thd, all_tables, TRUE, 0))
goto error; goto error;
if (check_routine_access(thd, EXECUTE_ACL, lex->spname->m_db.str,
lex->spname->m_name.str, TRUE, FALSE))
goto error;
/* /*
By this moment all needed SPs should be in cache so no need to look By this moment all needed SPs should be in cache so no need to look
into DB. into DB.
...@@ -4691,11 +4695,6 @@ case SQLCOM_PREPARE: ...@@ -4691,11 +4695,6 @@ case SQLCOM_PREPARE:
thd->server_status|= SERVER_MORE_RESULTS_EXISTS; thd->server_status|= SERVER_MORE_RESULTS_EXISTS;
} }
if (check_routine_access(thd, EXECUTE_ACL,
sp->m_db.str, sp->m_name.str, TRUE, FALSE))
{
goto error;
}
select_limit= thd->variables.select_limit; select_limit= thd->variables.select_limit;
thd->variables.select_limit= HA_POS_ERROR; thd->variables.select_limit= HA_POS_ERROR;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment