Merge moonlight.intranet:/home/tomash/src/mysql_ab/mysql-5.0
into moonlight.intranet:/home/tomash/src/mysql_ab/mysql-5.0-bug18630
This commit is contained in:
commit
a3ea06db41
@ -451,3 +451,55 @@ SELECT Host,User,Password FROM mysql.user WHERE User='user19857';
|
|||||||
Host User Password
|
Host User Password
|
||||||
localhost user19857 *82DC221D557298F6CE9961037DB1C90604792F5C
|
localhost user19857 *82DC221D557298F6CE9961037DB1C90604792F5C
|
||||||
DROP USER user19857@localhost;
|
DROP USER user19857@localhost;
|
||||||
|
DROP TABLE IF EXISTS t1;
|
||||||
|
DROP VIEW IF EXISTS v1;
|
||||||
|
DROP FUNCTION IF EXISTS f_suid;
|
||||||
|
DROP PROCEDURE IF EXISTS p_suid;
|
||||||
|
DROP FUNCTION IF EXISTS f_evil;
|
||||||
|
DELETE FROM mysql.user WHERE user LIKE 'mysqltest\_%';
|
||||||
|
DELETE FROM mysql.db WHERE user LIKE 'mysqltest\_%';
|
||||||
|
DELETE FROM mysql.tables_priv WHERE user LIKE 'mysqltest\_%';
|
||||||
|
DELETE FROM mysql.columns_priv WHERE user LIKE 'mysqltest\_%';
|
||||||
|
FLUSH PRIVILEGES;
|
||||||
|
CREATE TABLE t1 (i INT);
|
||||||
|
CREATE FUNCTION f_suid(i INT) RETURNS INT SQL SECURITY DEFINER RETURN 0;
|
||||||
|
CREATE PROCEDURE p_suid(IN i INT) SQL SECURITY DEFINER SET @c:= 0;
|
||||||
|
CREATE USER mysqltest_u1@localhost;
|
||||||
|
GRANT EXECUTE ON test.* TO mysqltest_u1@localhost;
|
||||||
|
CREATE DEFINER=mysqltest_u1@localhost FUNCTION f_evil () RETURNS INT
|
||||||
|
SQL SECURITY INVOKER
|
||||||
|
BEGIN
|
||||||
|
SET @a:= CURRENT_USER();
|
||||||
|
SET @b:= (SELECT COUNT(*) FROM t1);
|
||||||
|
RETURN @b;
|
||||||
|
END|
|
||||||
|
CREATE SQL SECURITY INVOKER VIEW v1 AS SELECT f_evil();
|
||||||
|
SELECT COUNT(*) FROM t1;
|
||||||
|
ERROR 42000: SELECT command denied to user 'mysqltest_u1'@'localhost' for table 't1'
|
||||||
|
SELECT f_evil();
|
||||||
|
ERROR 42000: SELECT command denied to user 'mysqltest_u1'@'localhost' for table 't1'
|
||||||
|
SELECT @a, @b;
|
||||||
|
@a @b
|
||||||
|
mysqltest_u1@localhost NULL
|
||||||
|
SELECT f_suid(f_evil());
|
||||||
|
ERROR 42000: SELECT command denied to user 'mysqltest_u1'@'localhost' for table 't1'
|
||||||
|
SELECT @a, @b;
|
||||||
|
@a @b
|
||||||
|
mysqltest_u1@localhost NULL
|
||||||
|
CALL p_suid(f_evil());
|
||||||
|
ERROR 42000: SELECT command denied to user 'mysqltest_u1'@'localhost' for table 't1'
|
||||||
|
SELECT @a, @b;
|
||||||
|
@a @b
|
||||||
|
mysqltest_u1@localhost NULL
|
||||||
|
SELECT * FROM v1;
|
||||||
|
ERROR 42000: SELECT command denied to user 'mysqltest_u1'@'localhost' for table 'v1'
|
||||||
|
SELECT @a, @b;
|
||||||
|
@a @b
|
||||||
|
mysqltest_u1@localhost NULL
|
||||||
|
DROP VIEW v1;
|
||||||
|
DROP FUNCTION f_evil;
|
||||||
|
DROP USER mysqltest_u1@localhost;
|
||||||
|
DROP PROCEDURE p_suid;
|
||||||
|
DROP FUNCTION f_suid;
|
||||||
|
DROP TABLE t1;
|
||||||
|
End of 5.0 tests.
|
||||||
|
@ -790,4 +790,80 @@ SELECT Host,User,Password FROM mysql.user WHERE User='user19857';
|
|||||||
|
|
||||||
DROP USER user19857@localhost;
|
DROP USER user19857@localhost;
|
||||||
|
|
||||||
# End of 5.0 bugs.
|
--disconnect con1root
|
||||||
|
--connection default
|
||||||
|
|
||||||
|
|
||||||
|
#
|
||||||
|
# BUG#18630: Arguments of suid routine calculated in wrong security
|
||||||
|
# context
|
||||||
|
#
|
||||||
|
# Arguments of suid routines were calculated in definer's security
|
||||||
|
# context instead of caller's context thus creating security hole.
|
||||||
|
#
|
||||||
|
--disable_warnings
|
||||||
|
DROP TABLE IF EXISTS t1;
|
||||||
|
DROP VIEW IF EXISTS v1;
|
||||||
|
DROP FUNCTION IF EXISTS f_suid;
|
||||||
|
DROP PROCEDURE IF EXISTS p_suid;
|
||||||
|
DROP FUNCTION IF EXISTS f_evil;
|
||||||
|
--enable_warnings
|
||||||
|
DELETE FROM mysql.user WHERE user LIKE 'mysqltest\_%';
|
||||||
|
DELETE FROM mysql.db WHERE user LIKE 'mysqltest\_%';
|
||||||
|
DELETE FROM mysql.tables_priv WHERE user LIKE 'mysqltest\_%';
|
||||||
|
DELETE FROM mysql.columns_priv WHERE user LIKE 'mysqltest\_%';
|
||||||
|
FLUSH PRIVILEGES;
|
||||||
|
|
||||||
|
CREATE TABLE t1 (i INT);
|
||||||
|
CREATE FUNCTION f_suid(i INT) RETURNS INT SQL SECURITY DEFINER RETURN 0;
|
||||||
|
CREATE PROCEDURE p_suid(IN i INT) SQL SECURITY DEFINER SET @c:= 0;
|
||||||
|
|
||||||
|
CREATE USER mysqltest_u1@localhost;
|
||||||
|
# Thanks to this grant statement privileges of anonymous users on
|
||||||
|
# 'test' database are not applicable for mysqltest_u1@localhost.
|
||||||
|
GRANT EXECUTE ON test.* TO mysqltest_u1@localhost;
|
||||||
|
|
||||||
|
delimiter |;
|
||||||
|
CREATE DEFINER=mysqltest_u1@localhost FUNCTION f_evil () RETURNS INT
|
||||||
|
SQL SECURITY INVOKER
|
||||||
|
BEGIN
|
||||||
|
SET @a:= CURRENT_USER();
|
||||||
|
SET @b:= (SELECT COUNT(*) FROM t1);
|
||||||
|
RETURN @b;
|
||||||
|
END|
|
||||||
|
delimiter ;|
|
||||||
|
|
||||||
|
CREATE SQL SECURITY INVOKER VIEW v1 AS SELECT f_evil();
|
||||||
|
|
||||||
|
connect (conn1, localhost, mysqltest_u1,,);
|
||||||
|
|
||||||
|
--error ER_TABLEACCESS_DENIED_ERROR
|
||||||
|
SELECT COUNT(*) FROM t1;
|
||||||
|
|
||||||
|
--error ER_TABLEACCESS_DENIED_ERROR
|
||||||
|
SELECT f_evil();
|
||||||
|
SELECT @a, @b;
|
||||||
|
|
||||||
|
--error ER_TABLEACCESS_DENIED_ERROR
|
||||||
|
SELECT f_suid(f_evil());
|
||||||
|
SELECT @a, @b;
|
||||||
|
|
||||||
|
--error ER_TABLEACCESS_DENIED_ERROR
|
||||||
|
CALL p_suid(f_evil());
|
||||||
|
SELECT @a, @b;
|
||||||
|
|
||||||
|
--error ER_TABLEACCESS_DENIED_ERROR
|
||||||
|
SELECT * FROM v1;
|
||||||
|
SELECT @a, @b;
|
||||||
|
|
||||||
|
disconnect conn1;
|
||||||
|
connection default;
|
||||||
|
|
||||||
|
DROP VIEW v1;
|
||||||
|
DROP FUNCTION f_evil;
|
||||||
|
DROP USER mysqltest_u1@localhost;
|
||||||
|
DROP PROCEDURE p_suid;
|
||||||
|
DROP FUNCTION f_suid;
|
||||||
|
DROP TABLE t1;
|
||||||
|
|
||||||
|
--echo End of 5.0 tests.
|
||||||
|
@ -4830,7 +4830,9 @@ Item_func_sp::execute_impl(THD *thd, Field *return_value_fld)
|
|||||||
{
|
{
|
||||||
bool err_status= TRUE;
|
bool err_status= TRUE;
|
||||||
Sub_statement_state statement_state;
|
Sub_statement_state statement_state;
|
||||||
Security_context *save_security_ctx= thd->security_ctx, *save_ctx_func;
|
#ifndef NO_EMBEDDED_ACCESS_CHECKS
|
||||||
|
Security_context *save_security_ctx= thd->security_ctx;
|
||||||
|
#endif
|
||||||
|
|
||||||
DBUG_ENTER("Item_func_sp::execute_impl");
|
DBUG_ENTER("Item_func_sp::execute_impl");
|
||||||
|
|
||||||
@ -4841,7 +4843,7 @@ Item_func_sp::execute_impl(THD *thd, Field *return_value_fld)
|
|||||||
thd->security_ctx= context->security_ctx;
|
thd->security_ctx= context->security_ctx;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
if (find_and_check_access(thd, EXECUTE_ACL, &save_ctx_func))
|
if (find_and_check_access(thd))
|
||||||
goto error;
|
goto error;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -4853,13 +4855,11 @@ Item_func_sp::execute_impl(THD *thd, Field *return_value_fld)
|
|||||||
err_status= m_sp->execute_function(thd, args, arg_count, return_value_fld);
|
err_status= m_sp->execute_function(thd, args, arg_count, return_value_fld);
|
||||||
thd->restore_sub_statement_state(&statement_state);
|
thd->restore_sub_statement_state(&statement_state);
|
||||||
|
|
||||||
|
error:
|
||||||
#ifndef NO_EMBEDDED_ACCESS_CHECKS
|
#ifndef NO_EMBEDDED_ACCESS_CHECKS
|
||||||
sp_restore_security_context(thd, save_ctx_func);
|
|
||||||
error:
|
|
||||||
thd->security_ctx= save_security_ctx;
|
thd->security_ctx= save_security_ctx;
|
||||||
#else
|
|
||||||
error:
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
DBUG_RETURN(err_status);
|
DBUG_RETURN(err_status);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -4976,70 +4976,38 @@ Item_func_sp::tmp_table_field(TABLE *t_arg)
|
|||||||
SYNOPSIS
|
SYNOPSIS
|
||||||
find_and_check_access()
|
find_and_check_access()
|
||||||
thd thread handler
|
thd thread handler
|
||||||
want_access requested access
|
|
||||||
save backup of security context
|
|
||||||
|
|
||||||
RETURN
|
RETURN
|
||||||
FALSE Access granted
|
FALSE Access granted
|
||||||
TRUE Requested access can't be granted or function doesn't exists
|
TRUE Requested access can't be granted or function doesn't exists
|
||||||
In this case security context is not changed and *save = 0
|
|
||||||
|
|
||||||
NOTES
|
NOTES
|
||||||
Checks if requested access to function can be granted to user.
|
Checks if requested access to function can be granted to user.
|
||||||
If function isn't found yet, it searches function first.
|
If function isn't found yet, it searches function first.
|
||||||
If function can't be found or user don't have requested access
|
If function can't be found or user don't have requested access
|
||||||
error is raised.
|
error is raised.
|
||||||
If security context sp_ctx is provided and access can be granted then
|
|
||||||
switch back to previous context isn't performed.
|
|
||||||
In case of access error or if context is not provided then
|
|
||||||
find_and_check_access() switches back to previous security context.
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
bool
|
bool
|
||||||
Item_func_sp::find_and_check_access(THD *thd, ulong want_access,
|
Item_func_sp::find_and_check_access(THD *thd)
|
||||||
Security_context **save)
|
|
||||||
{
|
{
|
||||||
bool res= TRUE;
|
|
||||||
|
|
||||||
*save= 0; // Safety if error
|
|
||||||
if (! m_sp && ! (m_sp= sp_find_routine(thd, TYPE_ENUM_FUNCTION, m_name,
|
if (! m_sp && ! (m_sp= sp_find_routine(thd, TYPE_ENUM_FUNCTION, m_name,
|
||||||
&thd->sp_func_cache, TRUE)))
|
&thd->sp_func_cache, TRUE)))
|
||||||
{
|
{
|
||||||
my_error(ER_SP_DOES_NOT_EXIST, MYF(0), "FUNCTION", m_name->m_qname.str);
|
my_error(ER_SP_DOES_NOT_EXIST, MYF(0), "FUNCTION", m_name->m_qname.str);
|
||||||
goto error;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef NO_EMBEDDED_ACCESS_CHECKS
|
#ifndef NO_EMBEDDED_ACCESS_CHECKS
|
||||||
if (check_routine_access(thd, want_access,
|
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))
|
||||||
goto error;
|
return TRUE;
|
||||||
|
|
||||||
sp_change_security_context(thd, m_sp, save);
|
|
||||||
/*
|
|
||||||
If we changed context to run as another user, we need to check the
|
|
||||||
access right for the new context again as someone may have deleted
|
|
||||||
this person the right to use the procedure
|
|
||||||
|
|
||||||
TODO:
|
|
||||||
Cache if the definer has the right to use the object on the first
|
|
||||||
usage and only reset the cache if someone does a GRANT statement
|
|
||||||
that 'may' affect this.
|
|
||||||
*/
|
|
||||||
if (*save &&
|
|
||||||
check_routine_access(thd, want_access,
|
|
||||||
m_sp->m_db.str, m_sp->m_name.str, 0, FALSE))
|
|
||||||
{
|
|
||||||
sp_restore_security_context(thd, *save);
|
|
||||||
*save= 0; // Safety
|
|
||||||
goto error;
|
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
res= FALSE; // no error
|
|
||||||
|
|
||||||
error:
|
return FALSE;
|
||||||
return res;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool
|
bool
|
||||||
Item_func_sp::fix_fields(THD *thd, Item **ref)
|
Item_func_sp::fix_fields(THD *thd, Item **ref)
|
||||||
{
|
{
|
||||||
@ -5050,19 +5018,23 @@ Item_func_sp::fix_fields(THD *thd, Item **ref)
|
|||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
Here we check privileges of the stored routine only during view
|
Here we check privileges of the stored routine only during view
|
||||||
creation, in order to validate the view. A runtime check is perfomed
|
creation, in order to validate the view. A runtime check is
|
||||||
in Item_func_sp::execute(), and this method is not called during
|
perfomed in Item_func_sp::execute(), and this method is not
|
||||||
context analysis. We do not need to restore the security context
|
called during context analysis. Notice, that during view
|
||||||
changed in find_and_check_access because all view structures created
|
creation we do not infer into stored routine bodies and do not
|
||||||
in CREATE VIEW are not used for execution. Notice, that during view
|
check privileges of its statements, which would probably be a
|
||||||
creation we do not infer into stored routine bodies and do not check
|
good idea especially if the view has SQL SECURITY DEFINER and
|
||||||
privileges of its statements, which would probably be a good idea
|
the used stored procedure has SQL SECURITY DEFINER.
|
||||||
especially if the view has SQL SECURITY DEFINER and the used stored
|
|
||||||
procedure has SQL SECURITY DEFINER
|
|
||||||
*/
|
*/
|
||||||
Security_context *save_ctx;
|
res= find_and_check_access(thd);
|
||||||
if (!(res= find_and_check_access(thd, EXECUTE_ACL, &save_ctx)))
|
#ifndef NO_EMBEDDED_ACCESS_CHECKS
|
||||||
sp_restore_security_context(thd, save_ctx);
|
Security_context *save_secutiry_ctx;
|
||||||
|
if (!res && !(res= set_routine_security_ctx(thd, m_sp, false,
|
||||||
|
&save_secutiry_ctx)))
|
||||||
|
{
|
||||||
|
sp_restore_security_context(thd, save_secutiry_ctx);
|
||||||
|
}
|
||||||
|
#endif /* ! NO_EMBEDDED_ACCESS_CHECKS */
|
||||||
}
|
}
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
@ -1465,8 +1465,7 @@ public:
|
|||||||
{ context= (Name_resolution_context *)cntx; return FALSE; }
|
{ context= (Name_resolution_context *)cntx; return FALSE; }
|
||||||
|
|
||||||
void fix_length_and_dec();
|
void fix_length_and_dec();
|
||||||
bool find_and_check_access(THD * thd, ulong want_access,
|
bool find_and_check_access(THD * thd);
|
||||||
Security_context **backup);
|
|
||||||
virtual enum Functype functype() const { return FUNC_SP; }
|
virtual enum Functype functype() const { return FUNC_SP; }
|
||||||
|
|
||||||
bool fix_fields(THD *thd, Item **ref);
|
bool fix_fields(THD *thd, Item **ref);
|
||||||
|
190
sql/sp_head.cc
190
sql/sp_head.cc
@ -1097,6 +1097,7 @@ sp_head::execute(THD *thd)
|
|||||||
|
|
||||||
thd->restore_active_arena(&execute_arena, &backup_arena);
|
thd->restore_active_arena(&execute_arena, &backup_arena);
|
||||||
|
|
||||||
|
thd->spcont->pop_all_cursors(); // To avoid memory leaks after an error
|
||||||
|
|
||||||
/* Restore all saved */
|
/* Restore all saved */
|
||||||
old_packet.swap(thd->packet);
|
old_packet.swap(thd->packet);
|
||||||
@ -1158,6 +1159,161 @@ sp_head::execute(THD *thd)
|
|||||||
m_first_instance->m_first_free_instance->m_recursion_level ==
|
m_first_instance->m_first_free_instance->m_recursion_level ==
|
||||||
m_recursion_level + 1));
|
m_recursion_level + 1));
|
||||||
m_first_instance->m_first_free_instance= this;
|
m_first_instance->m_first_free_instance= this;
|
||||||
|
|
||||||
|
DBUG_RETURN(err_status);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef NO_EMBEDDED_ACCESS_CHECKS
|
||||||
|
/*
|
||||||
|
set_routine_security_ctx() changes routine security context, and
|
||||||
|
checks if there is an EXECUTE privilege in new context. If there is
|
||||||
|
no EXECUTE privilege, it changes the context back and returns a
|
||||||
|
error.
|
||||||
|
|
||||||
|
SYNOPSIS
|
||||||
|
set_routine_security_ctx()
|
||||||
|
thd thread handle
|
||||||
|
sp stored routine to change the context for
|
||||||
|
is_proc TRUE is procedure, FALSE if function
|
||||||
|
save_ctx pointer to an old security context
|
||||||
|
|
||||||
|
RETURN
|
||||||
|
TRUE if there was a error, and the context wasn't changed.
|
||||||
|
FALSE if the context was changed.
|
||||||
|
*/
|
||||||
|
|
||||||
|
bool
|
||||||
|
set_routine_security_ctx(THD *thd, sp_head *sp, bool is_proc,
|
||||||
|
Security_context **save_ctx)
|
||||||
|
{
|
||||||
|
*save_ctx= 0;
|
||||||
|
if (sp_change_security_context(thd, sp, save_ctx))
|
||||||
|
return TRUE;
|
||||||
|
|
||||||
|
/*
|
||||||
|
If we changed context to run as another user, we need to check the
|
||||||
|
access right for the new context again as someone may have revoked
|
||||||
|
the right to use the procedure from this user.
|
||||||
|
|
||||||
|
TODO:
|
||||||
|
Cache if the definer has the right to use the object on the
|
||||||
|
first usage and only reset the cache if someone does a GRANT
|
||||||
|
statement that 'may' affect this.
|
||||||
|
*/
|
||||||
|
if (*save_ctx &&
|
||||||
|
check_routine_access(thd, EXECUTE_ACL,
|
||||||
|
sp->m_db.str, sp->m_name.str, is_proc, FALSE))
|
||||||
|
{
|
||||||
|
sp_restore_security_context(thd, *save_ctx);
|
||||||
|
*save_ctx= 0;
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
#endif // ! NO_EMBEDDED_ACCESS_CHECKS
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
Execute a trigger:
|
||||||
|
- changes security context for triggers
|
||||||
|
- switch to new memroot
|
||||||
|
- call sp_head::execute
|
||||||
|
- restore old memroot
|
||||||
|
- restores security context
|
||||||
|
|
||||||
|
SYNOPSIS
|
||||||
|
sp_head::execute_trigger()
|
||||||
|
thd Thread handle
|
||||||
|
db database name
|
||||||
|
table table name
|
||||||
|
grant_info GRANT_INFO structure to be filled with
|
||||||
|
information about definer's privileges
|
||||||
|
on subject table
|
||||||
|
|
||||||
|
RETURN
|
||||||
|
FALSE on success
|
||||||
|
TRUE on error
|
||||||
|
*/
|
||||||
|
|
||||||
|
bool
|
||||||
|
sp_head::execute_trigger(THD *thd, const char *db, const char *table,
|
||||||
|
GRANT_INFO *grant_info)
|
||||||
|
{
|
||||||
|
sp_rcontext *octx = thd->spcont;
|
||||||
|
sp_rcontext *nctx = NULL;
|
||||||
|
bool err_status= FALSE;
|
||||||
|
MEM_ROOT call_mem_root;
|
||||||
|
Query_arena call_arena(&call_mem_root, Query_arena::INITIALIZED_FOR_SP);
|
||||||
|
Query_arena backup_arena;
|
||||||
|
|
||||||
|
DBUG_ENTER("sp_head::execute_trigger");
|
||||||
|
DBUG_PRINT("info", ("trigger %s", m_name.str));
|
||||||
|
|
||||||
|
#ifndef NO_EMBEDDED_ACCESS_CHECKS
|
||||||
|
Security_context *save_ctx;
|
||||||
|
if (sp_change_security_context(thd, this, &save_ctx))
|
||||||
|
DBUG_RETURN(TRUE);
|
||||||
|
|
||||||
|
/*
|
||||||
|
NOTE: TRIGGER_ACL should be used here.
|
||||||
|
*/
|
||||||
|
if (check_global_access(thd, SUPER_ACL))
|
||||||
|
{
|
||||||
|
sp_restore_security_context(thd, save_ctx);
|
||||||
|
DBUG_RETURN(TRUE);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Fetch information about table-level privileges to GRANT_INFO
|
||||||
|
structure for subject table. Check of privileges that will use it
|
||||||
|
and information about column-level privileges will happen in
|
||||||
|
Item_trigger_field::fix_fields().
|
||||||
|
*/
|
||||||
|
fill_effective_table_privileges(thd, grant_info, db, table);
|
||||||
|
#endif // NO_EMBEDDED_ACCESS_CHECKS
|
||||||
|
|
||||||
|
/*
|
||||||
|
Prepare arena and memroot for objects which lifetime is whole
|
||||||
|
duration of trigger call (sp_rcontext, it's tables and items,
|
||||||
|
sp_cursor and Item_cache holders for case expressions). We can't
|
||||||
|
use caller's arena/memroot for those objects because in this case
|
||||||
|
some fixed amount of memory will be consumed for each trigger
|
||||||
|
invocation and so statements which involve lot of them will hog
|
||||||
|
memory.
|
||||||
|
|
||||||
|
TODO: we should create sp_rcontext once per command and reuse it
|
||||||
|
on subsequent executions of a trigger.
|
||||||
|
*/
|
||||||
|
init_sql_alloc(&call_mem_root, MEM_ROOT_BLOCK_SIZE, 0);
|
||||||
|
thd->set_n_backup_active_arena(&call_arena, &backup_arena);
|
||||||
|
|
||||||
|
if (!(nctx= new sp_rcontext(m_pcont, 0, octx)) ||
|
||||||
|
nctx->init(thd))
|
||||||
|
{
|
||||||
|
err_status= TRUE;
|
||||||
|
goto err_with_cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifndef DBUG_OFF
|
||||||
|
nctx->sp= this;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
thd->spcont= nctx;
|
||||||
|
|
||||||
|
err_status= execute(thd);
|
||||||
|
|
||||||
|
err_with_cleanup:
|
||||||
|
thd->restore_active_arena(&call_arena, &backup_arena);
|
||||||
|
#ifndef NO_EMBEDDED_ACCESS_CHECKS
|
||||||
|
sp_restore_security_context(thd, save_ctx);
|
||||||
|
#endif // NO_EMBEDDED_ACCESS_CHECKS
|
||||||
|
delete nctx;
|
||||||
|
call_arena.free_items();
|
||||||
|
free_root(&call_mem_root, MYF(0));
|
||||||
|
thd->spcont= octx;
|
||||||
|
|
||||||
DBUG_RETURN(err_status);
|
DBUG_RETURN(err_status);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1165,8 +1321,12 @@ sp_head::execute(THD *thd)
|
|||||||
/*
|
/*
|
||||||
Execute a function:
|
Execute a function:
|
||||||
- evaluate parameters
|
- evaluate parameters
|
||||||
|
- changes security context for SUID routines
|
||||||
|
- switch to new memroot
|
||||||
- call sp_head::execute
|
- call sp_head::execute
|
||||||
|
- restore old memroot
|
||||||
- evaluate the return value
|
- evaluate the return value
|
||||||
|
- restores security context
|
||||||
|
|
||||||
SYNOPSIS
|
SYNOPSIS
|
||||||
sp_head::execute_function()
|
sp_head::execute_function()
|
||||||
@ -1293,6 +1453,15 @@ sp_head::execute_function(THD *thd, Item **argp, uint argcount,
|
|||||||
}
|
}
|
||||||
thd->spcont= nctx;
|
thd->spcont= nctx;
|
||||||
|
|
||||||
|
#ifndef NO_EMBEDDED_ACCESS_CHECKS
|
||||||
|
Security_context *save_security_ctx;
|
||||||
|
if (set_routine_security_ctx(thd, this, FALSE, &save_security_ctx))
|
||||||
|
{
|
||||||
|
err_status= TRUE;
|
||||||
|
goto err_with_cleanup;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
binlog_save_options= thd->options;
|
binlog_save_options= thd->options;
|
||||||
if (need_binlog_call)
|
if (need_binlog_call)
|
||||||
{
|
{
|
||||||
@ -1333,7 +1502,7 @@ sp_head::execute_function(THD *thd, Item **argp, uint argcount,
|
|||||||
reset_dynamic(&thd->user_var_events);
|
reset_dynamic(&thd->user_var_events);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m_type == TYPE_ENUM_FUNCTION && !err_status)
|
if (!err_status)
|
||||||
{
|
{
|
||||||
/* We need result only in function but not in trigger */
|
/* We need result only in function but not in trigger */
|
||||||
|
|
||||||
@ -1344,8 +1513,9 @@ sp_head::execute_function(THD *thd, Item **argp, uint argcount,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifndef NO_EMBEDDED_ACCESS_CHECKS
|
||||||
nctx->pop_all_cursors(); // To avoid memory leaks after an error
|
sp_restore_security_context(thd, save_security_ctx);
|
||||||
|
#endif
|
||||||
|
|
||||||
err_with_cleanup:
|
err_with_cleanup:
|
||||||
delete nctx;
|
delete nctx;
|
||||||
@ -1368,8 +1538,10 @@ err_with_cleanup:
|
|||||||
|
|
||||||
The function does the following steps:
|
The function does the following steps:
|
||||||
- Set all parameters
|
- Set all parameters
|
||||||
|
- changes security context for SUID routines
|
||||||
- call sp_head::execute
|
- call sp_head::execute
|
||||||
- copy back values of INOUT and OUT parameters
|
- copy back values of INOUT and OUT parameters
|
||||||
|
- restores security context
|
||||||
|
|
||||||
RETURN
|
RETURN
|
||||||
FALSE on success
|
FALSE on success
|
||||||
@ -1490,6 +1662,12 @@ sp_head::execute_procedure(THD *thd, List<Item> *args)
|
|||||||
|
|
||||||
thd->spcont= nctx;
|
thd->spcont= nctx;
|
||||||
|
|
||||||
|
#ifndef NO_EMBEDDED_ACCESS_CHECKS
|
||||||
|
Security_context *save_security_ctx= 0;
|
||||||
|
if (!err_status)
|
||||||
|
err_status= set_routine_security_ctx(thd, this, TRUE, &save_security_ctx);
|
||||||
|
#endif
|
||||||
|
|
||||||
if (!err_status)
|
if (!err_status)
|
||||||
err_status= execute(thd);
|
err_status= execute(thd);
|
||||||
|
|
||||||
@ -1534,10 +1712,14 @@ sp_head::execute_procedure(THD *thd, List<Item> *args)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifndef NO_EMBEDDED_ACCESS_CHECKS
|
||||||
|
if (save_security_ctx)
|
||||||
|
sp_restore_security_context(thd, save_security_ctx);
|
||||||
|
#endif
|
||||||
|
|
||||||
if (!save_spcont)
|
if (!save_spcont)
|
||||||
delete octx;
|
delete octx;
|
||||||
|
|
||||||
nctx->pop_all_cursors(); // To avoid memory leaks after an error
|
|
||||||
delete nctx;
|
delete nctx;
|
||||||
thd->spcont= save_spcont;
|
thd->spcont= save_spcont;
|
||||||
|
|
||||||
|
@ -206,6 +206,10 @@ public:
|
|||||||
void
|
void
|
||||||
destroy();
|
destroy();
|
||||||
|
|
||||||
|
bool
|
||||||
|
execute_trigger(THD *thd, const char *db, const char *table,
|
||||||
|
GRANT_INFO *grant_onfo);
|
||||||
|
|
||||||
bool
|
bool
|
||||||
execute_function(THD *thd, Item **args, uint argcount, Field *return_fld);
|
execute_function(THD *thd, Item **args, uint argcount, Field *return_fld);
|
||||||
|
|
||||||
@ -1149,6 +1153,10 @@ sp_change_security_context(THD *thd, sp_head *sp,
|
|||||||
Security_context **backup);
|
Security_context **backup);
|
||||||
void
|
void
|
||||||
sp_restore_security_context(THD *thd, Security_context *backup);
|
sp_restore_security_context(THD *thd, Security_context *backup);
|
||||||
|
|
||||||
|
bool
|
||||||
|
set_routine_security_ctx(THD *thd, sp_head *sp, bool is_proc,
|
||||||
|
Security_context **save_ctx);
|
||||||
#endif /* NO_EMBEDDED_ACCESS_CHECKS */
|
#endif /* NO_EMBEDDED_ACCESS_CHECKS */
|
||||||
|
|
||||||
TABLE_LIST *
|
TABLE_LIST *
|
||||||
|
@ -4405,9 +4405,6 @@ end_with_restore_list:
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
#ifndef NO_EMBEDDED_ACCESS_CHECKS
|
|
||||||
Security_context *save_ctx;
|
|
||||||
#endif
|
|
||||||
ha_rows select_limit;
|
ha_rows select_limit;
|
||||||
/* bits that should be cleared in thd->server_status */
|
/* bits that should be cleared in thd->server_status */
|
||||||
uint bits_to_be_cleared= 0;
|
uint bits_to_be_cleared= 0;
|
||||||
@ -4449,21 +4446,11 @@ end_with_restore_list:
|
|||||||
|
|
||||||
#ifndef NO_EMBEDDED_ACCESS_CHECKS
|
#ifndef NO_EMBEDDED_ACCESS_CHECKS
|
||||||
if (check_routine_access(thd, EXECUTE_ACL,
|
if (check_routine_access(thd, EXECUTE_ACL,
|
||||||
sp->m_db.str, sp->m_name.str, TRUE, 0) ||
|
sp->m_db.str, sp->m_name.str, TRUE, FALSE))
|
||||||
sp_change_security_context(thd, sp, &save_ctx))
|
|
||||||
{
|
{
|
||||||
thd->net.no_send_ok= nsok;
|
thd->net.no_send_ok= nsok;
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
if (save_ctx &&
|
|
||||||
check_routine_access(thd, EXECUTE_ACL,
|
|
||||||
sp->m_db.str, sp->m_name.str, TRUE, 0))
|
|
||||||
{
|
|
||||||
thd->net.no_send_ok= nsok;
|
|
||||||
sp_restore_security_context(thd, save_ctx);
|
|
||||||
goto error;
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
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;
|
||||||
@ -4487,9 +4474,6 @@ end_with_restore_list:
|
|||||||
thd->total_warn_count= 0;
|
thd->total_warn_count= 0;
|
||||||
|
|
||||||
thd->variables.select_limit= select_limit;
|
thd->variables.select_limit= select_limit;
|
||||||
#ifndef NO_EMBEDDED_ACCESS_CHECKS
|
|
||||||
sp_restore_security_context(thd, save_ctx);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
thd->net.no_send_ok= nsok;
|
thd->net.no_send_ok= nsok;
|
||||||
thd->server_status&= ~bits_to_be_cleared;
|
thd->server_status&= ~bits_to_be_cleared;
|
||||||
|
@ -1503,40 +1503,11 @@ bool Table_triggers_list::process_triggers(THD *thd, trg_event_type event,
|
|||||||
old_field= table->field;
|
old_field= table->field;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef NO_EMBEDDED_ACCESS_CHECKS
|
|
||||||
Security_context *save_ctx;
|
|
||||||
|
|
||||||
if (sp_change_security_context(thd, sp_trigger, &save_ctx))
|
|
||||||
return TRUE;
|
|
||||||
|
|
||||||
/*
|
|
||||||
NOTE: TRIGGER_ACL should be used below.
|
|
||||||
*/
|
|
||||||
|
|
||||||
if (check_global_access(thd, SUPER_ACL))
|
|
||||||
{
|
|
||||||
sp_restore_security_context(thd, save_ctx);
|
|
||||||
return TRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
Fetch information about table-level privileges to GRANT_INFO structure for
|
|
||||||
subject table. Check of privileges that will use it and information about
|
|
||||||
column-level privileges will happen in Item_trigger_field::fix_fields().
|
|
||||||
*/
|
|
||||||
|
|
||||||
fill_effective_table_privileges(thd,
|
|
||||||
&subject_table_grants[event][time_type],
|
|
||||||
table->s->db, table->s->table_name);
|
|
||||||
#endif // NO_EMBEDDED_ACCESS_CHECKS
|
|
||||||
|
|
||||||
thd->reset_sub_statement_state(&statement_state, SUB_STMT_TRIGGER);
|
thd->reset_sub_statement_state(&statement_state, SUB_STMT_TRIGGER);
|
||||||
err_status= sp_trigger->execute_function(thd, 0, 0, 0);
|
err_status= sp_trigger->execute_trigger
|
||||||
|
(thd, table->s->db, table->s->table_name,
|
||||||
|
&subject_table_grants[event][time_type]);
|
||||||
thd->restore_sub_statement_state(&statement_state);
|
thd->restore_sub_statement_state(&statement_state);
|
||||||
|
|
||||||
#ifndef NO_EMBEDDED_ACCESS_CHECKS
|
|
||||||
sp_restore_security_context(thd, save_ctx);
|
|
||||||
#endif // NO_EMBEDDED_ACCESS_CHECKS
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return err_status;
|
return err_status;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user