List:Commits« Previous MessageNext Message »
From:Dmitry Lenev Date:January 12 2011 1:43pm
Subject:bzr push into mysql-5.5 branch (Dmitry.Lenev:3238 to 3239) Bug#58499
View as plain text  
 3239 Dmitry Lenev	2011-01-12 [merge]
      Merged fix for bug #58499 "DEFINER-security view selecting from
      INVOKER-security view access check wrong" into mysql-5.5 tree.

    modified:
      mysql-test/r/view_grant.result
      mysql-test/t/view_grant.test
      sql/sql_view.cc
 3238 Ole John Aske	2011-01-12
      Fix for bug#58818: Incorrect result for IN/ANY subquery
      
      If the ::single_value_transformer() find an existing HAVING condition it used
      to do the transformation:
                  
        1) HAVING cond -> (HAVING Cond) AND (cond_guard (Item_ref_null_helper(...))
            
      As the AND condition in 1) is Mc'Carty evaluated, the
      right side of the AND cond should be executed only if the 
      original 'HAVING evaluated' to true.
            
      However, as we failed to set 'top_level' for the tranformed HAVING condition,
      'abort_on_null' was FALSE after transformation. An
      UNKNOWN having condition will then not terminate evaluation of the
      transformed having condition, and we incorrectly continued
      into the Item_ref_null_helper() part.

    modified:
      mysql-test/r/subselect.result
      mysql-test/t/subselect.test
      sql/item_subselect.cc
=== modified file 'mysql-test/r/view_grant.result'
--- a/mysql-test/r/view_grant.result	2010-02-24 13:52:27 +0000
+++ b/mysql-test/r/view_grant.result	2011-01-12 13:28:33 +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-24 13:52:27 +0000
+++ b/mysql-test/t/view_grant.test	2011-01-12 13:28:33 +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 10:46:00 +0000
+++ b/sql/sql_view.cc	2011-01-12 13:28:33 +0000
@@ -1270,6 +1270,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
@@ -1416,26 +1417,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

No bundle (reason: useless for push emails).
Thread
bzr push into mysql-5.5 branch (Dmitry.Lenev:3238 to 3239) Bug#58499Dmitry Lenev12 Jan