Commit 511a494c authored by Dmitry Lenev's avatar Dmitry Lenev

Merged fix for bug #58499 "DEFINER-security view selecting from

INVOKER-security view access check wrong" into mysql-5.5 tree.
parents f188a6f9 d4c75324
......@@ -1248,3 +1248,129 @@ Note 1449 The user specified as a definer ('unknown'@'unknown') does not exist
LOCK TABLES v1 READ;
ERROR HY000: The user specified as a definer ('unknown'@'unknown') does not exist
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 VIEW v1;
# Wait till we reached the initial number of concurrent sessions
--source include/wait_until_count_sessions.inc
--echo #
--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
LOCK TABLES v1 READ;
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_tail= 0;
TABLE_LIST *tbl;
Security_context *security_ctx;
/*
Check rights to run commands (EXPLAIN SELECT & SHOW CREATE) which show
......@@ -1416,26 +1417,39 @@ bool mysql_make_view(THD *thd, File_parser *parser, TABLE_LIST *table,
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 *)
thd->stmt_arena->alloc(sizeof(Security_context))))
goto err;
/* 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= 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;
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
routines referenced in the view
......
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