From: Martin Hansson Date: September 11 2009 12:49pm Subject: bzr commit into mysql-5.1-bugteam branch (martin.hansson:3120) Bug#35996 List-Archive: http://lists.mysql.com/commits/83051 X-Bug: 35996 Message-Id: <200909111250.n8BCoFW8024039@riff-raff> MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="===============0327009724==" --===============0327009724== MIME-Version: 1.0 Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit Content-Disposition: inline #At file:///data0/martin/bzr/bug35996/5.1bt/ based on revid:alik@stripped 3120 Martin Hansson 2009-09-11 Bug#35996: Security Breach In Smashed TEMPTABLE Views When looking in the code for SHOW CREATE VIEW, it would seem as if there is a need to hide errors that name object that a user does not have access to. But there are no justifications for this and it is inconsistently implemented. For example base tables being referenced from a view appear to be ok, but not views. The manual on the other hand is clear: If a user has the privileges SELECT and SHOW VIEW, the view definition is available to that user, period. The fix changes the behavior to support the manual in this respect. @ mysql-test/r/information_schema_db.result Bug#35996: Changed warnings. @ mysql-test/r/view_grant.result Bug#35996: Changed warnings. Test result. @ mysql-test/t/information_schema_db.test Bug#35996: Changed test case to reflect new behavior. @ mysql-test/t/view_grant.test Bug#35996: Test case. @ sql/sql_acl.cc Bug#35996: Code no longer necessary, we may as well exempt SHOW CREATE VIEW from this check. @ sql/sql_show.cc Bug#35996: The fix: An Internal_error_handler that hides most errors raised by access checking as they are not relevant to SHOW CREATE VIEW. @ sql/table.cc Bug#35996: Restricting this hack to act only when there is no Internal_error_handler. modified: mysql-test/r/information_schema_db.result mysql-test/r/view_grant.result mysql-test/t/information_schema_db.test mysql-test/t/view_grant.test sql/sql_acl.cc sql/sql_show.cc sql/table.cc === modified file 'mysql-test/r/information_schema_db.result' --- a/mysql-test/r/information_schema_db.result 2009-05-15 15:47:50 +0000 +++ b/mysql-test/r/information_schema_db.result 2009-09-11 12:49:07 +0000 @@ -139,7 +139,7 @@ show create view testdb_1.v7; View Create View character_set_client collation_connection v7 CREATE ALGORITHM=UNDEFINED DEFINER=`no_such_user`@`no_such_host` SQL SECURITY DEFINER VIEW `v7` AS select `testdb_1`.`t2`.`f1` AS `f1` from `t2` latin1 latin1_swedish_ci Warnings: -Warning 1356 View 'testdb_1.v7' references invalid table(s) or column(s) or function(s) or definer/invoker of view lack rights to use them +Note 1449 The user specified as a definer ('no_such_user'@'no_such_host') does not exist show fields from testdb_1.v7; Field Type Null Key Default Extra f1 char(4) YES NULL @@ -169,7 +169,7 @@ show create view testdb_1.v7; View Create View character_set_client collation_connection v7 CREATE ALGORITHM=UNDEFINED DEFINER=`no_such_user`@`no_such_host` SQL SECURITY DEFINER VIEW `v7` AS select `testdb_1`.`t2`.`f1` AS `f1` from `t2` latin1 latin1_swedish_ci Warnings: -Warning 1356 View 'testdb_1.v7' references invalid table(s) or column(s) or function(s) or definer/invoker of view lack rights to use them +Note 1449 The user specified as a definer ('no_such_user'@'no_such_host') does not exist revoke insert(f1) on v3 from testdb_2@localhost; revoke show view on v5 from testdb_2@localhost; use testdb_1; @@ -187,7 +187,8 @@ ERROR 42000: SELECT command denied to us show create view testdb_1.v7; ERROR 42000: SELECT command denied to user 'testdb_2'@'localhost' for table 'v7' show create view v4; -ERROR HY000: EXPLAIN/SHOW can not be issued; lacking privileges for underlying table +View Create View character_set_client collation_connection +v4 CREATE ALGORITHM=UNDEFINED DEFINER=`testdb_2`@`localhost` SQL SECURITY DEFINER VIEW `v4` AS select `v3`.`f1` AS `f1`,`v3`.`f2` AS `f2` from `testdb_1`.`v3` latin1 latin1_swedish_ci show fields from v4; Field Type Null Key Default Extra f1 char(4) YES NULL === modified file 'mysql-test/r/view_grant.result' --- a/mysql-test/r/view_grant.result 2009-08-21 14:41:48 +0000 +++ b/mysql-test/r/view_grant.result 2009-09-11 12:49:07 +0000 @@ -606,7 +606,7 @@ SHOW CREATE VIEW v; View Create View character_set_client collation_connection v CREATE ALGORITHM=UNDEFINED DEFINER=`no-such-user`@`localhost` SQL SECURITY DEFINER VIEW `v` AS select `test`.`t1`.`a` AS `a` from `t1` latin1 latin1_swedish_ci Warnings: -Warning 1356 View 'test.v' references invalid table(s) or column(s) or function(s) or definer/invoker of view lack rights to use them +Note 1449 The user specified as a definer ('no-such-user'@'localhost') does not exist SELECT * FROM v; ERROR HY000: The user specified as a definer ('no-such-user'@'localhost') does not exist DROP VIEW v; @@ -963,7 +963,7 @@ SHOW CREATE VIEW v1; View Create View character_set_client collation_connection v1 CREATE ALGORITHM=UNDEFINED DEFINER=`no_such`@`user_1` SQL SECURITY DEFINER VIEW `v1` AS select `test`.`t1`.`i` AS `i` from `t1` latin1 latin1_swedish_ci Warnings: -Warning 1356 View 'test.v1' references invalid table(s) or column(s) or function(s) or definer/invoker of view lack rights to use them +Note 1449 The user specified as a definer ('no_such'@'user_1') does not exist ALTER ALGORITHM=MERGE VIEW v1 AS SELECT * FROM t1; Warnings: Note 1449 The user specified as a definer ('no_such'@'user_1') does not exist @@ -971,7 +971,7 @@ SHOW CREATE VIEW v1; View Create View character_set_client collation_connection v1 CREATE ALGORITHM=MERGE DEFINER=`no_such`@`user_1` SQL SECURITY DEFINER VIEW `v1` AS select `test`.`t1`.`i` AS `i` from `t1` latin1 latin1_swedish_ci Warnings: -Warning 1356 View 'test.v1' references invalid table(s) or column(s) or function(s) or definer/invoker of view lack rights to use them +Note 1449 The user specified as a definer ('no_such'@'user_1') does not exist ALTER ALGORITHM=TEMPTABLE DEFINER=no_such@user_2 VIEW v1 AS SELECT * FROM t1; Warnings: Note 1449 The user specified as a definer ('no_such'@'user_2') does not exist @@ -979,7 +979,7 @@ SHOW CREATE VIEW v1; View Create View character_set_client collation_connection v1 CREATE ALGORITHM=TEMPTABLE DEFINER=`no_such`@`user_2` SQL SECURITY DEFINER VIEW `v1` AS select `test`.`t1`.`i` AS `i` from `t1` latin1 latin1_swedish_ci Warnings: -Warning 1356 View 'test.v1' references invalid table(s) or column(s) or function(s) or definer/invoker of view lack rights to use them +Note 1449 The user specified as a definer ('no_such'@'user_2') does not exist DROP VIEW v1; DROP TABLE t1; CREATE USER mysqluser1@localhost; @@ -1044,3 +1044,185 @@ DROP DATABASE mysqltest1; DROP VIEW test.v3; DROP USER mysqluser1@localhost; USE test; +# +# Bug#35996: Security Breach In Smashed TEMPTABLE Views +# +CREATE USER mysqluser1@localhost; +CREATE DATABASE mysqltest1; +CREATE DATABASE mysqltest2; +GRANT USAGE, SELECT, CREATE VIEW, SHOW VIEW +ON mysqltest2.* TO mysqluser1@localhost; +USE mysqltest1; +CREATE TABLE t1( a INT ); +CREATE TABLE t2( a INT, b INT ); +CREATE FUNCTION f1() RETURNS INT RETURN 1; +CREATE VIEW v1 AS SELECT 1 AS a; +CREATE VIEW v2 AS SELECT 1 AS a, 2 AS b; +GRANT SELECT ON TABLE t1 TO mysqluser1@localhost; +GRANT SELECT (a, b) ON TABLE t2 TO mysqluser1@localhost; +GRANT EXECUTE ON FUNCTION f1 TO mysqluser1@localhost; +GRANT SELECT ON TABLE v1 TO mysqluser1@localhost; +GRANT SELECT (a, b) ON TABLE v2 TO mysqluser1@localhost; +CREATE VIEW v_t1 AS SELECT * FROM t1; +CREATE VIEW v_t2 AS SELECT * FROM t2; +CREATE VIEW v_f1 AS SELECT f1() AS a; +CREATE VIEW v_v1 AS SELECT * FROM v1; +CREATE VIEW v_v2 AS SELECT * FROM v2; +GRANT SELECT, SHOW VIEW ON v_t1 TO mysqluser1@localhost; +GRANT SELECT, SHOW VIEW ON v_t2 TO mysqluser1@localhost; +GRANT SELECT, SHOW VIEW ON v_f1 TO mysqluser1@localhost; +GRANT SELECT, SHOW VIEW ON v_v1 TO mysqluser1@localhost; +GRANT SELECT, SHOW VIEW ON v_v2 TO mysqluser1@localhost; +CREATE VIEW v_mysqluser1_t1 AS SELECT * FROM mysqltest1.t1; +CREATE VIEW v_mysqluser1_t2 AS SELECT * FROM mysqltest1.t2; +CREATE VIEW v_mysqluser1_f1 AS SELECT mysqltest1.f1() AS a; +CREATE VIEW v_mysqluser1_v1 AS SELECT * FROM mysqltest1.v1; +CREATE VIEW v_mysqluser1_v2 AS SELECT * FROM mysqltest1.v2; +SHOW CREATE VIEW mysqltest1.v_t1; +View Create View character_set_client collation_connection +v_t1 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `mysqltest1`.`v_t1` AS select `mysqltest1`.`t1`.`a` AS `a` from `mysqltest1`.`t1` latin1 latin1_swedish_ci +SHOW CREATE VIEW mysqltest1.v_t2; +View Create View character_set_client collation_connection +v_t2 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `mysqltest1`.`v_t2` AS select `mysqltest1`.`t2`.`a` AS `a`,`mysqltest1`.`t2`.`b` AS `b` from `mysqltest1`.`t2` latin1 latin1_swedish_ci +SHOW CREATE VIEW mysqltest1.v_f1; +View Create View character_set_client collation_connection +v_f1 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `mysqltest1`.`v_f1` AS select `f1`() AS `a` latin1 latin1_swedish_ci +SHOW CREATE VIEW mysqltest1.v_v1; +View Create View character_set_client collation_connection +v_v1 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `mysqltest1`.`v_v1` AS select `v1`.`a` AS `a` from `mysqltest1`.`v1` latin1 latin1_swedish_ci +SHOW CREATE VIEW mysqltest1.v_v2; +View Create View character_set_client collation_connection +v_v2 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `mysqltest1`.`v_v2` AS select `v2`.`a` AS `a`,`v2`.`b` AS `b` from `mysqltest1`.`v2` latin1 latin1_swedish_ci +SHOW CREATE VIEW v_mysqluser1_t1; +View Create View character_set_client collation_connection +v_mysqluser1_t1 CREATE ALGORITHM=UNDEFINED DEFINER=`mysqluser1`@`localhost` SQL SECURITY DEFINER VIEW `v_mysqluser1_t1` AS select `mysqltest1`.`t1`.`a` AS `a` from `mysqltest1`.`t1` latin1 latin1_swedish_ci +SHOW CREATE VIEW v_mysqluser1_t2; +View Create View character_set_client collation_connection +v_mysqluser1_t2 CREATE ALGORITHM=UNDEFINED DEFINER=`mysqluser1`@`localhost` SQL SECURITY DEFINER VIEW `v_mysqluser1_t2` AS select `mysqltest1`.`t2`.`a` AS `a`,`mysqltest1`.`t2`.`b` AS `b` from `mysqltest1`.`t2` latin1 latin1_swedish_ci +SHOW CREATE VIEW v_mysqluser1_f1; +View Create View character_set_client collation_connection +v_mysqluser1_f1 CREATE ALGORITHM=UNDEFINED DEFINER=`mysqluser1`@`localhost` SQL SECURITY DEFINER VIEW `v_mysqluser1_f1` AS select `mysqltest1`.`f1`() AS `a` latin1 latin1_swedish_ci +SHOW CREATE VIEW v_mysqluser1_v1; +View Create View character_set_client collation_connection +v_mysqluser1_v1 CREATE ALGORITHM=UNDEFINED DEFINER=`mysqluser1`@`localhost` SQL SECURITY DEFINER VIEW `v_mysqluser1_v1` AS select `v1`.`a` AS `a` from `mysqltest1`.`v1` latin1 latin1_swedish_ci +SHOW CREATE VIEW v_mysqluser1_v2; +View Create View character_set_client collation_connection +v_mysqluser1_v2 CREATE ALGORITHM=UNDEFINED DEFINER=`mysqluser1`@`localhost` SQL SECURITY DEFINER VIEW `v_mysqluser1_v2` AS select `v2`.`a` AS `a`,`v2`.`b` AS `b` from `mysqltest1`.`v2` latin1 latin1_swedish_ci +REVOKE SELECT ON TABLE t1 FROM mysqluser1@localhost; +REVOKE SELECT (a) ON TABLE t2 FROM mysqluser1@localhost; +REVOKE EXECUTE ON FUNCTION f1 FROM mysqluser1@localhost; +REVOKE SELECT ON TABLE v1 FROM mysqluser1@localhost; +SHOW CREATE VIEW mysqltest1.v_t1; +View Create View character_set_client collation_connection +v_t1 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `mysqltest1`.`v_t1` AS select `mysqltest1`.`t1`.`a` AS `a` from `mysqltest1`.`t1` latin1 latin1_swedish_ci +SHOW CREATE VIEW mysqltest1.v_t2; +View Create View character_set_client collation_connection +v_t2 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `mysqltest1`.`v_t2` AS select `mysqltest1`.`t2`.`a` AS `a`,`mysqltest1`.`t2`.`b` AS `b` from `mysqltest1`.`t2` latin1 latin1_swedish_ci +SHOW CREATE VIEW mysqltest1.v_f1; +View Create View character_set_client collation_connection +v_f1 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `mysqltest1`.`v_f1` AS select `f1`() AS `a` latin1 latin1_swedish_ci +SHOW CREATE VIEW mysqltest1.v_v1; +View Create View character_set_client collation_connection +v_v1 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `mysqltest1`.`v_v1` AS select `v1`.`a` AS `a` from `mysqltest1`.`v1` latin1 latin1_swedish_ci +SHOW CREATE VIEW mysqltest1.v_v2; +View Create View character_set_client collation_connection +v_v2 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `mysqltest1`.`v_v2` AS select `v2`.`a` AS `a`,`v2`.`b` AS `b` from `mysqltest1`.`v2` latin1 latin1_swedish_ci +SHOW CREATE VIEW v_mysqluser1_t1; +View Create View character_set_client collation_connection +v_mysqluser1_t1 CREATE ALGORITHM=UNDEFINED DEFINER=`mysqluser1`@`localhost` SQL SECURITY DEFINER VIEW `v_mysqluser1_t1` AS select `mysqltest1`.`t1`.`a` AS `a` from `mysqltest1`.`t1` latin1 latin1_swedish_ci +SHOW CREATE VIEW v_mysqluser1_t2; +View Create View character_set_client collation_connection +v_mysqluser1_t2 CREATE ALGORITHM=UNDEFINED DEFINER=`mysqluser1`@`localhost` SQL SECURITY DEFINER VIEW `v_mysqluser1_t2` AS select `mysqltest1`.`t2`.`a` AS `a`,`mysqltest1`.`t2`.`b` AS `b` from `mysqltest1`.`t2` latin1 latin1_swedish_ci +SHOW CREATE VIEW v_mysqluser1_f1; +View Create View character_set_client collation_connection +v_mysqluser1_f1 CREATE ALGORITHM=UNDEFINED DEFINER=`mysqluser1`@`localhost` SQL SECURITY DEFINER VIEW `v_mysqluser1_f1` AS select `mysqltest1`.`f1`() AS `a` latin1 latin1_swedish_ci +SHOW CREATE VIEW v_mysqluser1_v1; +View Create View character_set_client collation_connection +v_mysqluser1_v1 CREATE ALGORITHM=UNDEFINED DEFINER=`mysqluser1`@`localhost` SQL SECURITY DEFINER VIEW `v_mysqluser1_v1` AS select `v1`.`a` AS `a` from `mysqltest1`.`v1` latin1 latin1_swedish_ci +SHOW CREATE VIEW v_mysqluser1_v2; +View Create View character_set_client collation_connection +v_mysqluser1_v2 CREATE ALGORITHM=UNDEFINED DEFINER=`mysqluser1`@`localhost` SQL SECURITY DEFINER VIEW `v_mysqluser1_v2` AS select `v2`.`a` AS `a`,`v2`.`b` AS `b` from `mysqltest1`.`v2` latin1 latin1_swedish_ci +DROP TABLE t1; +DROP FUNCTION f1; +DROP VIEW v1; +SHOW CREATE VIEW mysqltest1.v_t1; +View Create View character_set_client collation_connection +v_t1 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `mysqltest1`.`v_t1` AS select `mysqltest1`.`t1`.`a` AS `a` from `mysqltest1`.`t1` latin1 latin1_swedish_ci +Warnings: +Warning 1356 View 'mysqltest1.v_t1' references invalid table(s) or column(s) or function(s) or definer/invoker of view lack rights to use them +SHOW CREATE VIEW mysqltest1.v_t2; +View Create View character_set_client collation_connection +v_t2 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `mysqltest1`.`v_t2` AS select `mysqltest1`.`t2`.`a` AS `a`,`mysqltest1`.`t2`.`b` AS `b` from `mysqltest1`.`t2` latin1 latin1_swedish_ci +SHOW CREATE VIEW mysqltest1.v_f1; +View Create View character_set_client collation_connection +v_f1 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `mysqltest1`.`v_f1` AS select `f1`() AS `a` latin1 latin1_swedish_ci +Warnings: +Warning 1356 View 'mysqltest1.v_f1' references invalid table(s) or column(s) or function(s) or definer/invoker of view lack rights to use them +SHOW CREATE VIEW mysqltest1.v_v1; +View Create View character_set_client collation_connection +v_v1 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `mysqltest1`.`v_v1` AS select `v1`.`a` AS `a` from `mysqltest1`.`v1` latin1 latin1_swedish_ci +Warnings: +Warning 1356 View 'mysqltest1.v_v1' references invalid table(s) or column(s) or function(s) or definer/invoker of view lack rights to use them +SHOW CREATE VIEW mysqltest1.v_v2; +View Create View character_set_client collation_connection +v_v2 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `mysqltest1`.`v_v2` AS select `v2`.`a` AS `a`,`v2`.`b` AS `b` from `mysqltest1`.`v2` latin1 latin1_swedish_ci +SHOW CREATE VIEW v_mysqluser1_t1; +View Create View character_set_client collation_connection +v_mysqluser1_t1 CREATE ALGORITHM=UNDEFINED DEFINER=`mysqluser1`@`localhost` SQL SECURITY DEFINER VIEW `v_mysqluser1_t1` AS select `mysqltest1`.`t1`.`a` AS `a` from `mysqltest1`.`t1` latin1 latin1_swedish_ci +Warnings: +Warning 1356 View 'mysqltest2.v_mysqluser1_t1' references invalid table(s) or column(s) or function(s) or definer/invoker of view lack rights to use them +SHOW CREATE VIEW v_mysqluser1_t2; +View Create View character_set_client collation_connection +v_mysqluser1_t2 CREATE ALGORITHM=UNDEFINED DEFINER=`mysqluser1`@`localhost` SQL SECURITY DEFINER VIEW `v_mysqluser1_t2` AS select `mysqltest1`.`t2`.`a` AS `a`,`mysqltest1`.`t2`.`b` AS `b` from `mysqltest1`.`t2` latin1 latin1_swedish_ci +SHOW CREATE VIEW v_mysqluser1_f1; +View Create View character_set_client collation_connection +v_mysqluser1_f1 CREATE ALGORITHM=UNDEFINED DEFINER=`mysqluser1`@`localhost` SQL SECURITY DEFINER VIEW `v_mysqluser1_f1` AS select `mysqltest1`.`f1`() AS `a` latin1 latin1_swedish_ci +Warnings: +Warning 1356 View 'mysqltest2.v_mysqluser1_f1' references invalid table(s) or column(s) or function(s) or definer/invoker of view lack rights to use them +SHOW CREATE VIEW v_mysqluser1_v1; +View Create View character_set_client collation_connection +v_mysqluser1_v1 CREATE ALGORITHM=UNDEFINED DEFINER=`mysqluser1`@`localhost` SQL SECURITY DEFINER VIEW `v_mysqluser1_v1` AS select `v1`.`a` AS `a` from `mysqltest1`.`v1` latin1 latin1_swedish_ci +Warnings: +Warning 1356 View 'mysqltest2.v_mysqluser1_v1' references invalid table(s) or column(s) or function(s) or definer/invoker of view lack rights to use them +SHOW CREATE VIEW v_mysqluser1_v2; +View Create View character_set_client collation_connection +v_mysqluser1_v2 CREATE ALGORITHM=UNDEFINED DEFINER=`mysqluser1`@`localhost` SQL SECURITY DEFINER VIEW `v_mysqluser1_v2` AS select `v2`.`a` AS `a`,`v2`.`b` AS `b` from `mysqltest1`.`v2` latin1 latin1_swedish_ci +REVOKE SHOW VIEW ON v_t1 FROM mysqluser1@localhost; +REVOKE SHOW VIEW ON v_f1 FROM mysqluser1@localhost; +REVOKE SHOW VIEW ON v_v1 FROM mysqluser1@localhost; +SHOW CREATE VIEW mysqltest1.v_t1; +ERROR 42000: SHOW VIEW command denied to user 'mysqluser1'@'localhost' for table 'v_t1' +SHOW CREATE VIEW mysqltest1.v_f1; +ERROR 42000: SHOW VIEW command denied to user 'mysqluser1'@'localhost' for table 'v_f1' +SHOW CREATE VIEW mysqltest1.v_v1; +ERROR 42000: SHOW VIEW command denied to user 'mysqluser1'@'localhost' for table 'v_v1' +SHOW CREATE VIEW v_mysqluser1_t1; +View Create View character_set_client collation_connection +v_mysqluser1_t1 CREATE ALGORITHM=UNDEFINED DEFINER=`mysqluser1`@`localhost` SQL SECURITY DEFINER VIEW `v_mysqluser1_t1` AS select `mysqltest1`.`t1`.`a` AS `a` from `mysqltest1`.`t1` latin1 latin1_swedish_ci +Warnings: +Warning 1356 View 'mysqltest2.v_mysqluser1_t1' references invalid table(s) or column(s) or function(s) or definer/invoker of view lack rights to use them +SHOW CREATE VIEW v_mysqluser1_f1; +View Create View character_set_client collation_connection +v_mysqluser1_f1 CREATE ALGORITHM=UNDEFINED DEFINER=`mysqluser1`@`localhost` SQL SECURITY DEFINER VIEW `v_mysqluser1_f1` AS select `mysqltest1`.`f1`() AS `a` latin1 latin1_swedish_ci +Warnings: +Warning 1356 View 'mysqltest2.v_mysqluser1_f1' references invalid table(s) or column(s) or function(s) or definer/invoker of view lack rights to use them +SHOW CREATE VIEW v_mysqluser1_v1; +View Create View character_set_client collation_connection +v_mysqluser1_v1 CREATE ALGORITHM=UNDEFINED DEFINER=`mysqluser1`@`localhost` SQL SECURITY DEFINER VIEW `v_mysqluser1_v1` AS select `v1`.`a` AS `a` from `mysqltest1`.`v1` latin1 latin1_swedish_ci +Warnings: +Warning 1356 View 'mysqltest2.v_mysqluser1_v1' references invalid table(s) or column(s) or function(s) or definer/invoker of view lack rights to use them +DROP USER mysqluser1@localhost; +DROP DATABASE mysqltest1; +DROP DATABASE mysqltest2; +USE test; +CREATE TABLE t1( a INT ); +CREATE DEFINER = no_such_user@no_such_host VIEW v1 AS SELECT * FROM t1; +Warnings: +Note 1449 The user specified as a definer ('no_such_user'@'no_such_host') does not exist +SHOW CREATE VIEW v1; +View Create View character_set_client collation_connection +v1 CREATE ALGORITHM=UNDEFINED DEFINER=`no_such_user`@`no_such_host` SQL SECURITY DEFINER VIEW `v1` AS select `test`.`t1`.`a` AS `a` from `t1` latin1 latin1_swedish_ci +Warnings: +Note 1449 The user specified as a definer ('no_such_user'@'no_such_host') does not exist +DROP TABLE t1; +DROP VIEW v1; === modified file 'mysql-test/t/information_schema_db.test' --- a/mysql-test/t/information_schema_db.test 2009-05-15 09:59:31 +0000 +++ b/mysql-test/t/information_schema_db.test 2009-09-11 12:49:07 +0000 @@ -184,7 +184,6 @@ show fields from testdb_1.v7; --error ER_TABLEACCESS_DENIED_ERROR show create view testdb_1.v7; ---error ER_VIEW_NO_EXPLAIN show create view v4; #--error ER_VIEW_NO_EXPLAIN show fields from v4; === modified file 'mysql-test/t/view_grant.test' --- a/mysql-test/t/view_grant.test 2009-08-21 14:41:48 +0000 +++ b/mysql-test/t/view_grant.test 2009-09-11 12:49:07 +0000 @@ -1382,6 +1382,127 @@ DROP VIEW test.v3; DROP USER mysqluser1@localhost; USE test; +--echo # +--echo # Bug#35996: Security Breach In Smashed TEMPTABLE Views +--echo # +-- source include/not_embedded.inc +CREATE USER mysqluser1@localhost; +CREATE DATABASE mysqltest1; +CREATE DATABASE mysqltest2; +GRANT USAGE, SELECT, CREATE VIEW, SHOW VIEW +ON mysqltest2.* TO mysqluser1@localhost; + +USE mysqltest1; + +CREATE TABLE t1( a INT ); +CREATE TABLE t2( a INT, b INT ); +CREATE FUNCTION f1() RETURNS INT RETURN 1; +CREATE VIEW v1 AS SELECT 1 AS a; +CREATE VIEW v2 AS SELECT 1 AS a, 2 AS b; + +GRANT SELECT ON TABLE t1 TO mysqluser1@localhost; +GRANT SELECT (a, b) ON TABLE t2 TO mysqluser1@localhost; +GRANT EXECUTE ON FUNCTION f1 TO mysqluser1@localhost; +GRANT SELECT ON TABLE v1 TO mysqluser1@localhost; +GRANT SELECT (a, b) ON TABLE v2 TO mysqluser1@localhost; + +CREATE VIEW v_t1 AS SELECT * FROM t1; +CREATE VIEW v_t2 AS SELECT * FROM t2; +CREATE VIEW v_f1 AS SELECT f1() AS a; +CREATE VIEW v_v1 AS SELECT * FROM v1; +CREATE VIEW v_v2 AS SELECT * FROM v2; + +GRANT SELECT, SHOW VIEW ON v_t1 TO mysqluser1@localhost; +GRANT SELECT, SHOW VIEW ON v_t2 TO mysqluser1@localhost; +GRANT SELECT, SHOW VIEW ON v_f1 TO mysqluser1@localhost; +GRANT SELECT, SHOW VIEW ON v_v1 TO mysqluser1@localhost; +GRANT SELECT, SHOW VIEW ON v_v2 TO mysqluser1@localhost; + +--connect (connection1, localhost, mysqluser1,, mysqltest2) +CREATE VIEW v_mysqluser1_t1 AS SELECT * FROM mysqltest1.t1; +CREATE VIEW v_mysqluser1_t2 AS SELECT * FROM mysqltest1.t2; +CREATE VIEW v_mysqluser1_f1 AS SELECT mysqltest1.f1() AS a; +CREATE VIEW v_mysqluser1_v1 AS SELECT * FROM mysqltest1.v1; +CREATE VIEW v_mysqluser1_v2 AS SELECT * FROM mysqltest1.v2; + +SHOW CREATE VIEW mysqltest1.v_t1; +SHOW CREATE VIEW mysqltest1.v_t2; +SHOW CREATE VIEW mysqltest1.v_f1; +SHOW CREATE VIEW mysqltest1.v_v1; +SHOW CREATE VIEW mysqltest1.v_v2; + +SHOW CREATE VIEW v_mysqluser1_t1; +SHOW CREATE VIEW v_mysqluser1_t2; +SHOW CREATE VIEW v_mysqluser1_f1; +SHOW CREATE VIEW v_mysqluser1_v1; +SHOW CREATE VIEW v_mysqluser1_v2; + +--connection default +REVOKE SELECT ON TABLE t1 FROM mysqluser1@localhost; +REVOKE SELECT (a) ON TABLE t2 FROM mysqluser1@localhost; +REVOKE EXECUTE ON FUNCTION f1 FROM mysqluser1@localhost; +REVOKE SELECT ON TABLE v1 FROM mysqluser1@localhost; + +--connection connection1 +SHOW CREATE VIEW mysqltest1.v_t1; +SHOW CREATE VIEW mysqltest1.v_t2; +SHOW CREATE VIEW mysqltest1.v_f1; +SHOW CREATE VIEW mysqltest1.v_v1; +SHOW CREATE VIEW mysqltest1.v_v2; + +SHOW CREATE VIEW v_mysqluser1_t1; +SHOW CREATE VIEW v_mysqluser1_t2; +SHOW CREATE VIEW v_mysqluser1_f1; +SHOW CREATE VIEW v_mysqluser1_v1; +SHOW CREATE VIEW v_mysqluser1_v2; + +--connection default +DROP TABLE t1; +DROP FUNCTION f1; +DROP VIEW v1; + +--connection connection1 +SHOW CREATE VIEW mysqltest1.v_t1; +SHOW CREATE VIEW mysqltest1.v_t2; +SHOW CREATE VIEW mysqltest1.v_f1; +SHOW CREATE VIEW mysqltest1.v_v1; +SHOW CREATE VIEW mysqltest1.v_v2; + +SHOW CREATE VIEW v_mysqluser1_t1; +SHOW CREATE VIEW v_mysqluser1_t2; +SHOW CREATE VIEW v_mysqluser1_f1; +SHOW CREATE VIEW v_mysqluser1_v1; +SHOW CREATE VIEW v_mysqluser1_v2; + +--connection default +REVOKE SHOW VIEW ON v_t1 FROM mysqluser1@localhost; +REVOKE SHOW VIEW ON v_f1 FROM mysqluser1@localhost; +REVOKE SHOW VIEW ON v_v1 FROM mysqluser1@localhost; + +--connection connection1 +--error ER_TABLEACCESS_DENIED_ERROR +SHOW CREATE VIEW mysqltest1.v_t1; +--error ER_TABLEACCESS_DENIED_ERROR +SHOW CREATE VIEW mysqltest1.v_f1; +--error ER_TABLEACCESS_DENIED_ERROR +SHOW CREATE VIEW mysqltest1.v_v1; +SHOW CREATE VIEW v_mysqluser1_t1; +SHOW CREATE VIEW v_mysqluser1_f1; +SHOW CREATE VIEW v_mysqluser1_v1; + +--disconnect connection1 +--connection default +DROP USER mysqluser1@localhost; +DROP DATABASE mysqltest1; +DROP DATABASE mysqltest2; +USE test; + +CREATE TABLE t1( a INT ); +CREATE DEFINER = no_such_user@no_such_host VIEW v1 AS SELECT * FROM t1; +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 === modified file 'sql/sql_acl.cc' --- a/sql/sql_acl.cc 2009-08-28 16:21:54 +0000 +++ b/sql/sql_acl.cc 2009-09-11 12:49:07 +0000 @@ -4072,8 +4072,7 @@ bool check_column_grant_in_table_ref(THD db_name= table_ref->view_db.str; table_name= table_ref->view_name.str; if (table_ref->belong_to_view && - (thd->lex->sql_command == SQLCOM_SHOW_FIELDS || - thd->lex->sql_command == SQLCOM_SHOW_CREATE)) + thd->lex->sql_command == SQLCOM_SHOW_FIELDS) { view_privs= get_column_grant(thd, grant, db_name, table_name, name); if (view_privs & VIEW_ANY_ACL) === modified file 'sql/sql_show.cc' --- a/sql/sql_show.cc 2009-08-28 16:21:54 +0000 +++ b/sql/sql_show.cc 2009-09-11 12:49:07 +0000 @@ -581,6 +581,129 @@ find_files(THD *thd, List *f } +/** + An Internal_error_handler that eliminates errors regarding views' + underlying tables that occur during privilege checking of SHOW CREATE VIEW + commands. This happens in the cases when a view's underlying table + (e.g. referenced in its SELECT list) does not exist. + */ +class Show_create_error_handler : public Internal_error_handler { + + TABLE_LIST *m_top_view; + bool m_handling; + Security_context *m_sctx; + + char m_view_access_denied_message[MYSQL_ERRMSG_SIZE]; + char *m_view_access_denied_message_ptr; + +public: + + /** + Creates a new Show_create_error_handler for the particular security + context and view. + + @thd Thread context, used for security context information if needed. + @top_view The view. We do not verify at this point that top_view is in + fact a view since, alas, these things do not stay constant. + */ + explicit Show_create_error_handler(THD *thd, TABLE_LIST *top_view) : + m_top_view(top_view), m_handling(FALSE), + m_view_access_denied_message_ptr(NULL) { + + m_sctx = test(m_top_view->security_ctx) ? + m_top_view->security_ctx : thd->security_ctx; + } + + /** + Lazy instantiation of 'view access denied' message. The purpose of the + Show_create_error_handler is to hide details of underlying tables for + which we have no privileges behind ER_VIEW_INVALID messages. But this + obviously does not apply if we lack privileges on the view itself. + Unfortunately the information about for which table privilege checking + failed is not available at this point. The only way for us to check is by + reconstructing the actual error message and see if it's the same. + */ + char* get_view_access_denied_message() { + if (!m_view_access_denied_message_ptr) + { + m_view_access_denied_message_ptr= m_view_access_denied_message; + sprintf(m_view_access_denied_message, + ER(ER_TABLEACCESS_DENIED_ERROR), "SHOW VIEW", + m_sctx->priv_user, + m_sctx->host_or_ip, m_top_view->get_table_name()); + } + return m_view_access_denied_message_ptr; + } + + bool handle_error(uint sql_errno, const char *message, + MYSQL_ERROR::enum_warning_level level, THD *thd) { + /* + The handler does not handle the errors raised by itself. + At this point we know if top_view is really a view. + */ + if (m_handling || !m_top_view->view) + return FALSE; + + m_handling= TRUE; + + bool is_handled; + + switch (sql_errno) + { + case ER_TABLEACCESS_DENIED_ERROR: + if (!strcmp(get_view_access_denied_message(), message)) + /* Access to top view is not granted, don't interfere. */ + is_handled= FALSE; + else + /* Current user has no access to underlying table, irrelevant */ + is_handled= TRUE; + break; + + case ER_COLUMNACCESS_DENIED_ERROR: + /* Current user has no access to underlying table, irrelevant */ + is_handled= TRUE; + break; + + case ER_VIEW_NO_EXPLAIN: + /* + Current user has no access to an underlying table, and the error + message was anonymized. We ignore this. + */ + is_handled= TRUE; + break; + + case ER_NO_SUCH_TABLE: + /* Established behavior: warn if underlying tables are missing. */ + push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN, + ER_VIEW_INVALID, + ER(ER_VIEW_INVALID), + m_top_view->get_db_name(), + m_top_view->get_table_name()); + is_handled= TRUE; + break; + case ER_PROCACCESS_DENIED_ERROR: + /* Current user has no access to underlying function/proc, irrelevant */ + is_handled= TRUE; + break; + case ER_SP_DOES_NOT_EXIST: + /* Established behavior: warn if underlying functions are missing. */ + push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN, + ER_VIEW_INVALID, + ER(ER_VIEW_INVALID), + m_top_view->get_db_name(), + m_top_view->get_table_name()); + is_handled= TRUE; + break; + default: + is_handled= FALSE; + } + + m_handling= FALSE; + return is_handled; + } +}; + + bool mysqld_show_create(THD *thd, TABLE_LIST *table_list) { @@ -594,26 +717,13 @@ mysqld_show_create(THD *thd, TABLE_LIST /* We want to preserve the tree for views. */ thd->lex->view_prepare_mode= TRUE; - /* Only one table for now, but VIEW can involve several tables */ - if (open_normal_and_derived_tables(thd, table_list, 0)) { - if (!table_list->view || - (thd->is_error() && thd->main_da.sql_errno() != ER_VIEW_INVALID)) + Show_create_error_handler view_error_suppressor(thd, table_list); + thd->push_internal_handler(&view_error_suppressor); + bool error= open_normal_and_derived_tables(thd, table_list, 0); + thd->pop_internal_handler(); + if (error && thd->main_da.is_error()) DBUG_RETURN(TRUE); - - /* - Clear all messages with 'error' level status and - issue a warning with 'warning' level status in - case of invalid view and last error is ER_VIEW_INVALID - */ - mysql_reset_errors(thd, true); - thd->clear_error(); - - push_warning_printf(thd,MYSQL_ERROR::WARN_LEVEL_WARN, - ER_VIEW_INVALID, - ER(ER_VIEW_INVALID), - table_list->view_db.str, - table_list->view_name.str); } /* TODO: add environment variables show when it become possible */ === modified file 'sql/table.cc' --- a/sql/table.cc 2009-08-12 09:46:08 +0000 +++ b/sql/table.cc 2009-09-11 12:49:07 +0000 @@ -3338,7 +3338,12 @@ bool TABLE_LIST::prep_check_option(THD * /** - Hide errors which show view underlying table information + Hide errors which show view underlying table information. + There are currently two mechanisms at work that handle errors for views, + this one and a more general mechanism based on an Internal_error_handler, + see Show_create_error_handler. The latter handles errors encountered during + execution of SHOW CREATE VIEW, while the machanism using this method is + handles SELECT from views. The two methods should not clash. @param[in,out] thd thread handler @@ -3347,6 +3352,8 @@ bool TABLE_LIST::prep_check_option(THD * void TABLE_LIST::hide_view_error(THD *thd) { + if (thd->get_internal_handler()) + return; /* Hide "Unknown column" or "Unknown function" error */ DBUG_ASSERT(thd->is_error()); --===============0327009724== MIME-Version: 1.0 Content-Type: text/bzr-bundle; charset="us-ascii"; name="bzr/martin.hansson@stripped" Content-Transfer-Encoding: 7bit Content-Disposition: inline # Bazaar merge directive format 2 (Bazaar 0.90) # revision_id: martin.hansson@stripped # target_branch: file:///data0/martin/bzr/bug35996/5.1bt/ # testament_sha1: 21ffa6958054047e0aee020516d2e9c13421e6d8 # timestamp: 2009-09-11 14:49:15 +0200 # base_revision_id: alik@stripped # # Begin bundle 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 GnpVtxuT8F52b/zui9n/xdyRThQkP0lASAA= --===============0327009724==--