mirror of
https://github.com/MariaDB/server.git
synced 2025-07-30 16:24:05 +03:00
Merged fix for bug #58499 "DEFINER-security view selecting from
INVOKER-security view access check wrong" into mysql-5.5 tree.
This commit is contained in:
@ -1248,3 +1248,129 @@ Note 1449 The user specified as a definer ('unknown'@'unknown') does not exist
|
|||||||
LOCK TABLES v1 READ;
|
LOCK TABLES v1 READ;
|
||||||
ERROR HY000: The user specified as a definer ('unknown'@'unknown') does not exist
|
ERROR HY000: The user specified as a definer ('unknown'@'unknown') does not exist
|
||||||
DROP VIEW v1;
|
DROP VIEW v1;
|
||||||
|
#
|
||||||
|
# Bug #58499 "DEFINER-security view selecting from INVOKER-security view
|
||||||
|
# access check wrong".
|
||||||
|
#
|
||||||
|
# Check that we correctly handle privileges for various combinations
|
||||||
|
# of INVOKER and DEFINER-security views using each other.
|
||||||
|
DROP DATABASE IF EXISTS mysqltest1;
|
||||||
|
CREATE DATABASE mysqltest1;
|
||||||
|
USE mysqltest1;
|
||||||
|
CREATE TABLE t1 (i INT);
|
||||||
|
CREATE TABLE t2 (j INT);
|
||||||
|
INSERT INTO t1 VALUES (1);
|
||||||
|
INSERT INTO t2 VALUES (2);
|
||||||
|
#
|
||||||
|
# 1) DEFINER-security view uses INVOKER-security view (covers
|
||||||
|
# scenario originally described in the bug report).
|
||||||
|
CREATE SQL SECURITY INVOKER VIEW v1_uses_t1 AS SELECT * FROM t1;
|
||||||
|
CREATE SQL SECURITY INVOKER VIEW v1_uses_t2 AS SELECT * FROM t2;
|
||||||
|
CREATE USER 'mysqluser1'@'%';
|
||||||
|
GRANT CREATE VIEW ON mysqltest1.* TO 'mysqluser1'@'%';
|
||||||
|
GRANT SELECT ON t1 TO 'mysqluser1'@'%';
|
||||||
|
# To be able create 'v2_uses_t2' we also need select on t2.
|
||||||
|
GRANT SELECT ON t2 TO 'mysqluser1'@'%';
|
||||||
|
GRANT SELECT ON v1_uses_t1 TO 'mysqluser1'@'%';
|
||||||
|
GRANT SELECT ON v1_uses_t2 TO 'mysqluser1'@'%';
|
||||||
|
#
|
||||||
|
# Connection 'mysqluser1'.
|
||||||
|
CREATE SQL SECURITY DEFINER VIEW v2_uses_t1 AS SELECT * FROM v1_uses_t1;
|
||||||
|
CREATE SQL SECURITY DEFINER VIEW v2_uses_t2 AS SELECT * FROM v1_uses_t2;
|
||||||
|
#
|
||||||
|
# Connection 'default'.
|
||||||
|
CREATE USER 'mysqluser2'@'%';
|
||||||
|
GRANT SELECT ON v2_uses_t1 TO 'mysqluser2'@'%';
|
||||||
|
GRANT SELECT ON v2_uses_t2 TO 'mysqluser2'@'%';
|
||||||
|
GRANT SELECT ON t2 TO 'mysqluser2'@'%';
|
||||||
|
GRANT CREATE VIEW ON mysqltest1.* TO 'mysqluser2'@'%';
|
||||||
|
# Make 'mysqluser1' unable to access t2.
|
||||||
|
REVOKE SELECT ON t2 FROM 'mysqluser1'@'%';
|
||||||
|
#
|
||||||
|
# Connection 'mysqluser2'.
|
||||||
|
# The below statement should succeed thanks to suid nature of v2_uses_t1.
|
||||||
|
SELECT * FROM v2_uses_t1;
|
||||||
|
i
|
||||||
|
1
|
||||||
|
# The below statement should fail due to suid nature of v2_uses_t2.
|
||||||
|
SELECT * FROM v2_uses_t2;
|
||||||
|
ERROR HY000: View 'mysqltest1.v2_uses_t2' references invalid table(s) or column(s) or function(s) or definer/invoker of view lack rights to use them
|
||||||
|
#
|
||||||
|
# 2) INVOKER-security view uses INVOKER-security view.
|
||||||
|
#
|
||||||
|
# Connection 'default'.
|
||||||
|
DROP VIEW v2_uses_t1, v2_uses_t2;
|
||||||
|
CREATE SQL SECURITY INVOKER VIEW v2_uses_t1 AS SELECT * FROM v1_uses_t1;
|
||||||
|
CREATE SQL SECURITY INVOKER VIEW v2_uses_t2 AS SELECT * FROM v1_uses_t2;
|
||||||
|
GRANT SELECT ON v2_uses_t1 TO 'mysqluser1'@'%';
|
||||||
|
GRANT SELECT ON v2_uses_t2 TO 'mysqluser1'@'%';
|
||||||
|
GRANT SELECT ON v1_uses_t1 TO 'mysqluser2'@'%';
|
||||||
|
GRANT SELECT ON v1_uses_t2 TO 'mysqluser2'@'%';
|
||||||
|
#
|
||||||
|
# Connection 'mysqluser1'.
|
||||||
|
# For both versions of 'v2' 'mysqluser1' privileges should be used.
|
||||||
|
SELECT * FROM v2_uses_t1;
|
||||||
|
i
|
||||||
|
1
|
||||||
|
SELECT * FROM v2_uses_t2;
|
||||||
|
ERROR HY000: View 'mysqltest1.v2_uses_t2' references invalid table(s) or column(s) or function(s) or definer/invoker of view lack rights to use them
|
||||||
|
#
|
||||||
|
# Connection 'mysqluser2'.
|
||||||
|
# And now for both versions of 'v2' 'mysqluser2' privileges should
|
||||||
|
# be used.
|
||||||
|
SELECT * FROM v2_uses_t1;
|
||||||
|
ERROR HY000: View 'mysqltest1.v2_uses_t1' references invalid table(s) or column(s) or function(s) or definer/invoker of view lack rights to use them
|
||||||
|
SELECT * FROM v2_uses_t2;
|
||||||
|
j
|
||||||
|
2
|
||||||
|
#
|
||||||
|
# 3) INVOKER-security view uses DEFINER-security view.
|
||||||
|
#
|
||||||
|
# Connection 'default'.
|
||||||
|
DROP VIEW v1_uses_t1, v1_uses_t2;
|
||||||
|
# To be able create 'v1_uses_t2' we also need select on t2.
|
||||||
|
GRANT SELECT ON t2 TO 'mysqluser1'@'%';
|
||||||
|
#
|
||||||
|
# Connection 'mysqluser1'.
|
||||||
|
CREATE SQL SECURITY DEFINER VIEW v1_uses_t1 AS SELECT * FROM t1;
|
||||||
|
CREATE SQL SECURITY DEFINER VIEW v1_uses_t2 AS SELECT * FROM t2;
|
||||||
|
#
|
||||||
|
# Connection 'default'.
|
||||||
|
# Make 'mysqluser1' unable to access t2.
|
||||||
|
REVOKE SELECT ON t2 FROM 'mysqluser1'@'%';
|
||||||
|
#
|
||||||
|
# Connection 'mysqluser2'.
|
||||||
|
# Due to suid nature of v1_uses_t1 and v1_uses_t2 the first
|
||||||
|
# select should succeed and the second select should fail.
|
||||||
|
SELECT * FROM v2_uses_t1;
|
||||||
|
i
|
||||||
|
1
|
||||||
|
SELECT * FROM v2_uses_t2;
|
||||||
|
ERROR HY000: View 'mysqltest1.v2_uses_t2' references invalid table(s) or column(s) or function(s) or definer/invoker of view lack rights to use them
|
||||||
|
#
|
||||||
|
# 4) DEFINER-security view uses DEFINER-security view.
|
||||||
|
#
|
||||||
|
# Connection 'default'.
|
||||||
|
DROP VIEW v2_uses_t1, v2_uses_t2;
|
||||||
|
# To be able create 'v2_uses_t2' we also need select on t2.
|
||||||
|
GRANT SELECT ON t2 TO 'mysqluser1'@'%';
|
||||||
|
#
|
||||||
|
# Connection 'mysqluser2'.
|
||||||
|
CREATE SQL SECURITY DEFINER VIEW v2_uses_t1 AS SELECT * FROM v1_uses_t1;
|
||||||
|
CREATE SQL SECURITY DEFINER VIEW v2_uses_t2 AS SELECT * FROM v1_uses_t2;
|
||||||
|
#
|
||||||
|
# Connection 'default'.
|
||||||
|
# Make 'mysqluser1' unable to access t2.
|
||||||
|
REVOKE SELECT ON t2 FROM 'mysqluser1'@'%';
|
||||||
|
#
|
||||||
|
# Connection 'mysqluser2'.
|
||||||
|
# Again privileges of creator of innermost views should apply.
|
||||||
|
SELECT * FROM v2_uses_t1;
|
||||||
|
i
|
||||||
|
1
|
||||||
|
SELECT * FROM v2_uses_t2;
|
||||||
|
ERROR HY000: View 'mysqltest1.v2_uses_t2' references invalid table(s) or column(s) or function(s) or definer/invoker of view lack rights to use them
|
||||||
|
USE test;
|
||||||
|
DROP DATABASE mysqltest1;
|
||||||
|
DROP USER 'mysqluser1'@'%';
|
||||||
|
DROP USER 'mysqluser2'@'%';
|
||||||
|
@ -1503,8 +1503,6 @@ SHOW CREATE VIEW v1;
|
|||||||
DROP TABLE t1;
|
DROP TABLE t1;
|
||||||
DROP VIEW v1;
|
DROP VIEW v1;
|
||||||
|
|
||||||
# Wait till we reached the initial number of concurrent sessions
|
|
||||||
--source include/wait_until_count_sessions.inc
|
|
||||||
|
|
||||||
--echo #
|
--echo #
|
||||||
--echo # Bug #46019: ERROR 1356 When selecting from within another
|
--echo # Bug #46019: ERROR 1356 When selecting from within another
|
||||||
@ -1546,3 +1544,145 @@ CREATE DEFINER=`unknown`@`unknown` SQL SECURITY DEFINER VIEW v1 AS SELECT 1;
|
|||||||
--error ER_NO_SUCH_USER
|
--error ER_NO_SUCH_USER
|
||||||
LOCK TABLES v1 READ;
|
LOCK TABLES v1 READ;
|
||||||
DROP VIEW v1;
|
DROP VIEW v1;
|
||||||
|
|
||||||
|
|
||||||
|
--echo #
|
||||||
|
--echo # Bug #58499 "DEFINER-security view selecting from INVOKER-security view
|
||||||
|
--echo # access check wrong".
|
||||||
|
--echo #
|
||||||
|
--echo # Check that we correctly handle privileges for various combinations
|
||||||
|
--echo # of INVOKER and DEFINER-security views using each other.
|
||||||
|
--disable_warnings
|
||||||
|
DROP DATABASE IF EXISTS mysqltest1;
|
||||||
|
--enable_warnings
|
||||||
|
CREATE DATABASE mysqltest1;
|
||||||
|
USE mysqltest1;
|
||||||
|
CREATE TABLE t1 (i INT);
|
||||||
|
CREATE TABLE t2 (j INT);
|
||||||
|
INSERT INTO t1 VALUES (1);
|
||||||
|
INSERT INTO t2 VALUES (2);
|
||||||
|
--echo #
|
||||||
|
--echo # 1) DEFINER-security view uses INVOKER-security view (covers
|
||||||
|
--echo # scenario originally described in the bug report).
|
||||||
|
CREATE SQL SECURITY INVOKER VIEW v1_uses_t1 AS SELECT * FROM t1;
|
||||||
|
CREATE SQL SECURITY INVOKER VIEW v1_uses_t2 AS SELECT * FROM t2;
|
||||||
|
CREATE USER 'mysqluser1'@'%';
|
||||||
|
GRANT CREATE VIEW ON mysqltest1.* TO 'mysqluser1'@'%';
|
||||||
|
GRANT SELECT ON t1 TO 'mysqluser1'@'%';
|
||||||
|
--echo # To be able create 'v2_uses_t2' we also need select on t2.
|
||||||
|
GRANT SELECT ON t2 TO 'mysqluser1'@'%';
|
||||||
|
GRANT SELECT ON v1_uses_t1 TO 'mysqluser1'@'%';
|
||||||
|
GRANT SELECT ON v1_uses_t2 TO 'mysqluser1'@'%';
|
||||||
|
--echo #
|
||||||
|
--echo # Connection 'mysqluser1'.
|
||||||
|
--connect (mysqluser1, localhost, mysqluser1,,mysqltest1)
|
||||||
|
CREATE SQL SECURITY DEFINER VIEW v2_uses_t1 AS SELECT * FROM v1_uses_t1;
|
||||||
|
CREATE SQL SECURITY DEFINER VIEW v2_uses_t2 AS SELECT * FROM v1_uses_t2;
|
||||||
|
--echo #
|
||||||
|
--echo # Connection 'default'.
|
||||||
|
--connection default
|
||||||
|
CREATE USER 'mysqluser2'@'%';
|
||||||
|
GRANT SELECT ON v2_uses_t1 TO 'mysqluser2'@'%';
|
||||||
|
GRANT SELECT ON v2_uses_t2 TO 'mysqluser2'@'%';
|
||||||
|
GRANT SELECT ON t2 TO 'mysqluser2'@'%';
|
||||||
|
GRANT CREATE VIEW ON mysqltest1.* TO 'mysqluser2'@'%';
|
||||||
|
--echo # Make 'mysqluser1' unable to access t2.
|
||||||
|
REVOKE SELECT ON t2 FROM 'mysqluser1'@'%';
|
||||||
|
--echo #
|
||||||
|
--echo # Connection 'mysqluser2'.
|
||||||
|
--connect (mysqluser2, localhost, mysqluser2,,mysqltest1)
|
||||||
|
--echo # The below statement should succeed thanks to suid nature of v2_uses_t1.
|
||||||
|
SELECT * FROM v2_uses_t1;
|
||||||
|
--echo # The below statement should fail due to suid nature of v2_uses_t2.
|
||||||
|
--error ER_VIEW_INVALID
|
||||||
|
SELECT * FROM v2_uses_t2;
|
||||||
|
--echo #
|
||||||
|
--echo # 2) INVOKER-security view uses INVOKER-security view.
|
||||||
|
--echo #
|
||||||
|
--echo # Connection 'default'.
|
||||||
|
--connection default
|
||||||
|
DROP VIEW v2_uses_t1, v2_uses_t2;
|
||||||
|
CREATE SQL SECURITY INVOKER VIEW v2_uses_t1 AS SELECT * FROM v1_uses_t1;
|
||||||
|
CREATE SQL SECURITY INVOKER VIEW v2_uses_t2 AS SELECT * FROM v1_uses_t2;
|
||||||
|
GRANT SELECT ON v2_uses_t1 TO 'mysqluser1'@'%';
|
||||||
|
GRANT SELECT ON v2_uses_t2 TO 'mysqluser1'@'%';
|
||||||
|
GRANT SELECT ON v1_uses_t1 TO 'mysqluser2'@'%';
|
||||||
|
GRANT SELECT ON v1_uses_t2 TO 'mysqluser2'@'%';
|
||||||
|
--echo #
|
||||||
|
--echo # Connection 'mysqluser1'.
|
||||||
|
--connection mysqluser1
|
||||||
|
--echo # For both versions of 'v2' 'mysqluser1' privileges should be used.
|
||||||
|
SELECT * FROM v2_uses_t1;
|
||||||
|
--error ER_VIEW_INVALID
|
||||||
|
SELECT * FROM v2_uses_t2;
|
||||||
|
--echo #
|
||||||
|
--echo # Connection 'mysqluser2'.
|
||||||
|
--connection mysqluser2
|
||||||
|
--echo # And now for both versions of 'v2' 'mysqluser2' privileges should
|
||||||
|
--echo # be used.
|
||||||
|
--error ER_VIEW_INVALID
|
||||||
|
SELECT * FROM v2_uses_t1;
|
||||||
|
SELECT * FROM v2_uses_t2;
|
||||||
|
--echo #
|
||||||
|
--echo # 3) INVOKER-security view uses DEFINER-security view.
|
||||||
|
--echo #
|
||||||
|
--echo # Connection 'default'.
|
||||||
|
--connection default
|
||||||
|
DROP VIEW v1_uses_t1, v1_uses_t2;
|
||||||
|
--echo # To be able create 'v1_uses_t2' we also need select on t2.
|
||||||
|
GRANT SELECT ON t2 TO 'mysqluser1'@'%';
|
||||||
|
--echo #
|
||||||
|
--echo # Connection 'mysqluser1'.
|
||||||
|
--connection mysqluser1
|
||||||
|
CREATE SQL SECURITY DEFINER VIEW v1_uses_t1 AS SELECT * FROM t1;
|
||||||
|
CREATE SQL SECURITY DEFINER VIEW v1_uses_t2 AS SELECT * FROM t2;
|
||||||
|
--echo #
|
||||||
|
--echo # Connection 'default'.
|
||||||
|
--connection default
|
||||||
|
--echo # Make 'mysqluser1' unable to access t2.
|
||||||
|
REVOKE SELECT ON t2 FROM 'mysqluser1'@'%';
|
||||||
|
--echo #
|
||||||
|
--echo # Connection 'mysqluser2'.
|
||||||
|
--connection mysqluser2
|
||||||
|
--echo # Due to suid nature of v1_uses_t1 and v1_uses_t2 the first
|
||||||
|
--echo # select should succeed and the second select should fail.
|
||||||
|
SELECT * FROM v2_uses_t1;
|
||||||
|
--error ER_VIEW_INVALID
|
||||||
|
SELECT * FROM v2_uses_t2;
|
||||||
|
--echo #
|
||||||
|
--echo # 4) DEFINER-security view uses DEFINER-security view.
|
||||||
|
--echo #
|
||||||
|
--echo # Connection 'default'.
|
||||||
|
--connection default
|
||||||
|
DROP VIEW v2_uses_t1, v2_uses_t2;
|
||||||
|
--echo # To be able create 'v2_uses_t2' we also need select on t2.
|
||||||
|
GRANT SELECT ON t2 TO 'mysqluser1'@'%';
|
||||||
|
--echo #
|
||||||
|
--echo # Connection 'mysqluser2'.
|
||||||
|
--connection mysqluser2
|
||||||
|
CREATE SQL SECURITY DEFINER VIEW v2_uses_t1 AS SELECT * FROM v1_uses_t1;
|
||||||
|
CREATE SQL SECURITY DEFINER VIEW v2_uses_t2 AS SELECT * FROM v1_uses_t2;
|
||||||
|
--echo #
|
||||||
|
--echo # Connection 'default'.
|
||||||
|
--connection default
|
||||||
|
--echo # Make 'mysqluser1' unable to access t2.
|
||||||
|
REVOKE SELECT ON t2 FROM 'mysqluser1'@'%';
|
||||||
|
--echo #
|
||||||
|
--echo # Connection 'mysqluser2'.
|
||||||
|
--connection mysqluser2
|
||||||
|
--echo # Again privileges of creator of innermost views should apply.
|
||||||
|
SELECT * FROM v2_uses_t1;
|
||||||
|
--error ER_VIEW_INVALID
|
||||||
|
SELECT * FROM v2_uses_t2;
|
||||||
|
|
||||||
|
--disconnect mysqluser1
|
||||||
|
--disconnect mysqluser2
|
||||||
|
--connection default
|
||||||
|
USE test;
|
||||||
|
DROP DATABASE mysqltest1;
|
||||||
|
DROP USER 'mysqluser1'@'%';
|
||||||
|
DROP USER 'mysqluser2'@'%';
|
||||||
|
|
||||||
|
|
||||||
|
# Wait till we reached the initial number of concurrent sessions
|
||||||
|
--source include/wait_until_count_sessions.inc
|
||||||
|
@ -1270,6 +1270,7 @@ bool mysql_make_view(THD *thd, File_parser *parser, TABLE_LIST *table,
|
|||||||
TABLE_LIST *view_tables= lex->query_tables;
|
TABLE_LIST *view_tables= lex->query_tables;
|
||||||
TABLE_LIST *view_tables_tail= 0;
|
TABLE_LIST *view_tables_tail= 0;
|
||||||
TABLE_LIST *tbl;
|
TABLE_LIST *tbl;
|
||||||
|
Security_context *security_ctx;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Check rights to run commands (EXPLAIN SELECT & SHOW CREATE) which show
|
Check rights to run commands (EXPLAIN SELECT & SHOW CREATE) which show
|
||||||
@ -1416,25 +1417,38 @@ bool mysql_make_view(THD *thd, File_parser *parser, TABLE_LIST *table,
|
|||||||
if (table->view_suid)
|
if (table->view_suid)
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
Prepare a security context to check underlying objects of the view
|
For suid views prepare a security context for checking underlying
|
||||||
|
objects of the view.
|
||||||
*/
|
*/
|
||||||
if (!(table->view_sctx= (Security_context *)
|
if (!(table->view_sctx= (Security_context *)
|
||||||
thd->stmt_arena->alloc(sizeof(Security_context))))
|
thd->stmt_arena->alloc(sizeof(Security_context))))
|
||||||
goto err;
|
goto err;
|
||||||
/* Assign the context to the tables referenced in the view */
|
security_ctx= table->view_sctx;
|
||||||
if (view_tables)
|
|
||||||
{
|
|
||||||
DBUG_ASSERT(view_tables_tail);
|
|
||||||
for (tbl= view_tables; tbl != view_tables_tail->next_global;
|
|
||||||
tbl= tbl->next_global)
|
|
||||||
tbl->security_ctx= table->view_sctx;
|
|
||||||
}
|
|
||||||
/* assign security context to SELECT name resolution contexts of view */
|
|
||||||
for(SELECT_LEX *sl= lex->all_selects_list;
|
|
||||||
sl;
|
|
||||||
sl= sl->next_select_in_list())
|
|
||||||
sl->context.security_ctx= table->view_sctx;
|
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
For non-suid views inherit security context from view's table list.
|
||||||
|
This allows properly handle situation when non-suid view is used
|
||||||
|
from within suid view.
|
||||||
|
*/
|
||||||
|
security_ctx= table->security_ctx;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Assign the context to the tables referenced in the view */
|
||||||
|
if (view_tables)
|
||||||
|
{
|
||||||
|
DBUG_ASSERT(view_tables_tail);
|
||||||
|
for (tbl= view_tables; tbl != view_tables_tail->next_global;
|
||||||
|
tbl= tbl->next_global)
|
||||||
|
tbl->security_ctx= security_ctx;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* assign security context to SELECT name resolution contexts of view */
|
||||||
|
for(SELECT_LEX *sl= lex->all_selects_list;
|
||||||
|
sl;
|
||||||
|
sl= sl->next_select_in_list())
|
||||||
|
sl->context.security_ctx= security_ctx;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Setup an error processor to hide error messages issued by stored
|
Setup an error processor to hide error messages issued by stored
|
||||||
|
Reference in New Issue
Block a user