From: Dmitry Lenev Date: January 12 2011 1:08pm Subject: bzr commit into mysql-5.1 branch (Dmitry.Lenev:3544) Bug#58499 List-Archive: http://lists.mysql.com/commits/128509 X-Bug: 58499 Message-Id: <20110112130835.19C6E7402F1@bandersnatch> MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="===============0047649755==" --===============0047649755== 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.1-58499-2/ based on revid:martin.hansson@stripped 3544 Dmitry Lenev 2011-01-12 Fix for bug #58499 "DEFINER-security view selecting from INVOKER-security view access check wrong". When privilege checks were done for tables used from an INVOKER-security view which in its turn was used from a DEFINER-security view connection's active security context was incorrectly used instead of security context with privileges of the second view's creator. This meant that users which had enough rights to access the DEFINER-security view and as result were supposed to be able successfully access it were unable to do so in cases when they didn't have privileges on underlying tables of the INVOKER-security view. This problem was caused by the fact that for INVOKER-security views TABLE_LIST::security_ctx member for underlying tables were set to 0 even in cases when particular view was used from another DEFINER-security view. This meant that when checks of privileges on these underlying tables was done in setup_tables_and_check_access() active connection security context was used instead of context corresponding to the creator of caller view. This fix addresses the problem by ensuring that underlying tables of an INVOKER-security view inherit security context from the view and thus correct security context is used for privilege checks on underlying tables in cases when such view is used from another view with DEFINER-security. @ mysql-test/r/view_grant.result Added coverage for various combinations of DEFINER and INVOKER-security views, including test for bug #58499 "DEFINER-security view selecting from INVOKER-security view access check wrong". @ mysql-test/t/view_grant.test Added coverage for various combinations of DEFINER and INVOKER-security views, including test for bug #58499 "DEFINER-security view selecting from INVOKER-security view access check wrong". @ sql/sql_view.cc When opening a non-suid view ensure that its underlying tables will get the same security context as use for checking privileges on the view, i.e. security context of view invoker. This context can be different from the security context which is currently active for connection in cases when this non-suid view is used from a view with suid security. Inheriting security context in such situation allows correctly apply privileges of creator of suid view in checks for tables of non-suid view (since in this situation creator/definer of suid view serves as invoker for non-suid view). modified: mysql-test/r/view_grant.result mysql-test/t/view_grant.test sql/sql_view.cc === modified file 'mysql-test/r/view_grant.result' --- a/mysql-test/r/view_grant.result 2010-02-12 02:54:14 +0000 +++ b/mysql-test/r/view_grant.result 2011-01-12 13:08:30 +0000 @@ -1248,3 +1248,129 @@ Note 1449 The user specified as a define 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'@'%'; === modified file 'mysql-test/t/view_grant.test' --- a/mysql-test/t/view_grant.test 2010-02-12 02:54:14 +0000 +++ b/mysql-test/t/view_grant.test 2011-01-12 13:08:30 +0000 @@ -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 S --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 === modified file 'sql/sql_view.cc' --- a/sql/sql_view.cc 2010-12-14 09:33:03 +0000 +++ b/sql/sql_view.cc 2011-01-12 13:08:30 +0000 @@ -1255,6 +1255,7 @@ bool mysql_make_view(THD *thd, File_pars 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 @@ -1396,26 +1397,39 @@ bool mysql_make_view(THD *thd, File_pars 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 --===============0047649755== 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.1-58499-2/ # testament_sha1: a2f5b76557298ae4c71d74afff97f2164d7451ba # timestamp: 2011-01-12 16:08:34 +0300 # base_revision_id: martin.hansson@stripped\ # bj93mupb5dndw41r # # Begin bundle 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 --===============0047649755==--