From: Martin Hansson Date: August 12 2009 2:03pm Subject: bzr commit into mysql-5.1-bugteam branch (martin.hansson:2936) Bug#35996 List-Archive: http://lists.mysql.com/commits/80677 X-Bug: 35996 Message-Id: <200908121404.n7CE43JT020352@riff-raff> MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="===============0637978129==" --===============0637978129== 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-gca-commmit/ based on revid:davi.arnaut@stripped 2936 Martin Hansson 2009-08-12 Bug#35996: Security Breach In Smashed TEMPTABLE Views There were no errors displayed when issuing a SHOW CREATE VIEW for views that reference base tables for which the user did not have sufficient privileges to see the table structure. If the view referenced a view with the same lack of privileges, however, an error was raised correctly. This came about because the 'access denied' error message was first issued during normal access checking for the referenced base table, then converted into a generic 'view invalid' message for the referencing view in order to hide details of the table structure which were otherwise visible in the error message. Later still, all 'view invalid' errors were cleared and a warning issued instead, the rationale being that we should not get errors simply because a view referenced a nonexisting object. At this point all information about the initial causes of the error condition were lost. Fixed by implementing a specialized subclass of Internal_error_handler and removing error handling that manipulates error messages. @ mysql-test/r/information_schema_db.result Bug#35996: Changed result. @ mysql-test/r/view_grant.result Bug#35996: Changed result. @ mysql-test/t/information_schema_db.test Bug#35996: Changed test case. @ mysql-test/t/view_grant.test Bug#35996: Changed test case, test case for bug. @ sql/sql_base.cc Bug#35996: Partial removal of old style of error handling. @ sql/sql_show.cc Bug#35996: Implementation of the new Internal_error_handler subclass. 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_base.cc sql/sql_show.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-08-12 14:02:58 +0000 @@ -136,10 +136,7 @@ show create view testdb_1.v6; View Create View character_set_client collation_connection v6 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `v6` AS select `t1`.`f1` AS `f1` from `t1` latin1 latin1_swedish_ci 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 +ERROR HY000: EXPLAIN/SHOW can not be issued; lacking privileges for underlying table show fields from testdb_1.v7; Field Type Null Key Default Extra f1 char(4) YES NULL @@ -166,10 +163,7 @@ f1 char(4) YES NULL Warnings: Note 1449 The user specified as a definer ('no_such_user'@'no_such_host') does not exist 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 +ERROR HY000: EXPLAIN/SHOW can not be issued; lacking privileges for underlying table revoke insert(f1) on v3 from testdb_2@localhost; revoke show view on v5 from testdb_2@localhost; use testdb_1; === modified file 'mysql-test/r/view_grant.result' --- a/mysql-test/r/view_grant.result 2009-05-15 12:57:51 +0000 +++ b/mysql-test/r/view_grant.result 2009-08-12 14:02:58 +0000 @@ -603,10 +603,7 @@ CREATE DEFINER = 'no-such-user'@localhos Warnings: Note 1449 The user specified as a definer ('no-such-user'@'localhost') does not exist 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 +ERROR HY000: EXPLAIN/SHOW can not be issued; lacking privileges for underlying table SELECT * FROM v; ERROR HY000: The user specified as a definer ('no-such-user'@'localhost') does not exist DROP VIEW v; @@ -960,26 +957,17 @@ ALTER DEFINER=no_such@user_1 VIEW v1 AS Warnings: Note 1449 The user specified as a definer ('no_such'@'user_1') does not exist 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 +ERROR HY000: EXPLAIN/SHOW can not be issued; lacking privileges for underlying table 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 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 +ERROR HY000: EXPLAIN/SHOW can not be issued; lacking privileges for underlying table 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 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 +ERROR HY000: EXPLAIN/SHOW can not be issued; lacking privileges for underlying table DROP VIEW v1; DROP TABLE t1; CREATE USER mysqluser1@localhost; @@ -1044,3 +1032,46 @@ DROP DATABASE mysqltest1; DROP VIEW test.v3; DROP USER mysqluser1@localhost; USE test; +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 VIEW v1 AS SELECT 1 AS a; +GRANT SELECT ON t1 TO mysqluser1@localhost; +GRANT SELECT ON v1 TO mysqluser1@localhost; +CREATE VIEW v_t1 AS SELECT * FROM mysqltest1.t1; +CREATE VIEW v_v1 AS SELECT * FROM mysqltest1.v1; +REVOKE SELECT ON t1 FROM mysqluser1@localhost; +REVOKE SELECT ON v1 FROM mysqluser1@localhost; +SHOW CREATE VIEW v_t1; +ERROR HY000: EXPLAIN/SHOW can not be issued; lacking privileges for underlying table +SHOW CREATE VIEW v_v1; +ERROR HY000: EXPLAIN/SHOW can not be issued; lacking privileges for underlying table +DROP TABLE t1; +DROP VIEW v1; +SHOW CREATE VIEW v_t1; +View Create View character_set_client collation_connection +v_t1 CREATE ALGORITHM=UNDEFINED DEFINER=`mysqluser1`@`localhost` SQL SECURITY DEFINER VIEW `v_t1` AS select `mysqltest1`.`t1`.`a` AS `a` from `mysqltest1`.`t1` latin1 latin1_swedish_ci +Warnings: +Warning 1356 View 'mysqltest2.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 v_v1; +View Create View character_set_client collation_connection +v_v1 CREATE ALGORITHM=UNDEFINED DEFINER=`mysqluser1`@`localhost` SQL SECURITY DEFINER VIEW `v_v1` AS select `v1`.`a` AS `a` from `mysqltest1`.`v1` latin1 latin1_swedish_ci +Warnings: +Warning 1356 View 'mysqltest2.v_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 FUNCTION f1() RETURNS INT RETURN 1; +CREATE VIEW v1 AS SELECT f1() AS a; +DROP FUNCTION f1; +SHOW CREATE VIEW v1; +View Create View character_set_client collation_connection +v1 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `v1` AS select `f1`() AS `a` 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 +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-08-12 14:02:58 +0000 @@ -139,6 +139,7 @@ create definer=`no_such_user`@`no_such_h show fields from testdb_1.v6; show create view testdb_1.v6; +--error ER_VIEW_NO_EXPLAIN show create view testdb_1.v7; show fields from testdb_1.v7; @@ -160,6 +161,7 @@ show create view testdb_1.v6; connection testdb_1; show fields from testdb_1.v7; +--error ER_VIEW_NO_EXPLAIN show create view testdb_1.v7; revoke insert(f1) on v3 from testdb_2@localhost; === modified file 'mysql-test/t/view_grant.test' --- a/mysql-test/t/view_grant.test 2009-05-15 12:57:51 +0000 +++ b/mysql-test/t/view_grant.test 2009-08-12 14:02:58 +0000 @@ -793,7 +793,7 @@ DROP DATABASE mysqltest1; CREATE TABLE t1 (a INT PRIMARY KEY); INSERT INTO t1 VALUES (1), (2), (3); CREATE DEFINER = 'no-such-user'@localhost VIEW v AS SELECT a from t1; -#--warning ER_VIEW_OTHER_USER +--error ER_VIEW_NO_EXPLAIN SHOW CREATE VIEW v; --error ER_NO_SUCH_USER SELECT * FROM v; @@ -1255,10 +1255,13 @@ CREATE VIEW v1 AS SELECT * FROM t1; ALTER VIEW v1 AS SELECT * FROM t1; SHOW CREATE VIEW v1; ALTER DEFINER=no_such@user_1 VIEW v1 AS SELECT * FROM t1; +--error ER_VIEW_NO_EXPLAIN SHOW CREATE VIEW v1; ALTER ALGORITHM=MERGE VIEW v1 AS SELECT * FROM t1; +--error ER_VIEW_NO_EXPLAIN SHOW CREATE VIEW v1; ALTER ALGORITHM=TEMPTABLE DEFINER=no_such@user_2 VIEW v1 AS SELECT * FROM t1; +--error ER_VIEW_NO_EXPLAIN SHOW CREATE VIEW v1; DROP VIEW v1; @@ -1385,3 +1388,54 @@ USE test; # Wait till we reached the initial number of concurrent sessions --source include/wait_until_count_sessions.inc +# +# Bug#35996: Security Breach In Smashed TEMPTABLE Views +# +-- 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 VIEW v1 AS SELECT 1 AS a; + +GRANT SELECT ON t1 TO mysqluser1@localhost; +GRANT SELECT ON v1 TO mysqluser1@localhost; + +--connect (connection1, localhost, mysqluser1,, mysqltest2) +CREATE VIEW v_t1 AS SELECT * FROM mysqltest1.t1; +CREATE VIEW v_v1 AS SELECT * FROM mysqltest1.v1; + +--connection default +REVOKE SELECT ON t1 FROM mysqluser1@localhost; +REVOKE SELECT ON v1 FROM mysqluser1@localhost; + +--connection connection1 +--error ER_VIEW_NO_EXPLAIN +SHOW CREATE VIEW v_t1; +--error ER_VIEW_NO_EXPLAIN +SHOW CREATE VIEW v_v1; + +--connection default +DROP TABLE t1; +DROP VIEW v1; +--connection connection1 +SHOW CREATE VIEW v_t1; +SHOW CREATE VIEW v_v1; + +--disconnect connection1 +--connection default +DROP USER mysqluser1@localhost; +DROP DATABASE mysqltest1; +DROP DATABASE mysqltest2; +USE test; + +CREATE FUNCTION f1() RETURNS INT RETURN 1; +CREATE VIEW v1 AS SELECT f1() AS a; +DROP FUNCTION f1; +SHOW CREATE VIEW v1; +DROP VIEW v1; === modified file 'sql/sql_base.cc' --- a/sql/sql_base.cc 2009-05-30 13:32:28 +0000 +++ b/sql/sql_base.cc 2009-08-12 14:02:58 +0000 @@ -7644,7 +7644,12 @@ bool setup_tables_and_check_access(THD * check_single_table_access(thd, first_table ? want_access_first : want_access, leaves_tmp, FALSE)) { - tables->hide_view_error(thd); + /* + Unless the Show_create_error_handler is in effect, revert to old + method of supressing errors. + */ + if (!thd->get_internal_handler()) + tables->hide_view_error(thd); return TRUE; } first_table= 0; === modified file 'sql/sql_show.cc' --- a/sql/sql_show.cc 2009-05-15 12:57:51 +0000 +++ b/sql/sql_show.cc 2009-08-12 14:02:58 +0000 @@ -584,6 +584,105 @@ find_files(THD *thd, List *f } +/** + An Internal_error_handler that downgrades SHOW CREATE VIEW errors for + certain invalid views to warnings. + + This happens in the cases when a view's + underlying object (e.g. referenced in its SELECT list) does not exist. + + - For views referencing non-existing functions + + - For views referencing non-existing tables + */ +class Show_create_error_handler : public Internal_error_handler +{ + + /** + 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 the point of calling + handle_error(). The only way for us to check is by reconstructing the + actual error message and use strcmp() to see if it's the same. + */ + char view_access_denied_message[256]; + + TABLE_LIST *table; + bool within_handler; + + bool handle_error_impl(uint sql_errno, const char *message, + MYSQL_ERROR::enum_warning_level level, THD *thd) + { + + switch (sql_errno) { + + case ER_NO_SUCH_TABLE: + /* If an underlying table is missing, just warn. */ + push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN, + ER_VIEW_INVALID, + ER(ER_VIEW_INVALID), + table->get_db_name(), + table->get_table_name()); + return TRUE; + + case ER_VIEW_INVALID: + /* + If an underlying function does not exist, remove error and issue + warning instead. + */ + mysql_reset_errors(thd, true); + push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN, + ER_VIEW_INVALID, + ER(ER_VIEW_INVALID), + table->get_db_name(), + table->get_table_name()); + return TRUE; + case ER_TABLEACCESS_DENIED_ERROR: + if (!strcmp(view_access_denied_message, message)) + /* If access to the view itself is not granted, don't interfere. */ + return FALSE; + /* Missing privilege on underlying table, throw an error. */ + my_error(ER_VIEW_NO_EXPLAIN, MYF(0)); + return TRUE; + } + return FALSE; + } + +public: + explicit Show_create_error_handler(THD *thd, TABLE_LIST *table_list) : + table(table_list), within_handler(FALSE) + { + Security_context *sctx = test(table->security_ctx) ? + table->security_ctx : thd->security_ctx; + sprintf(view_access_denied_message, + ER(ER_TABLEACCESS_DENIED_ERROR), "SHOW VIEW", + sctx->priv_user, + sctx->host_or_ip, table->get_table_name()); + + } + + bool handle_error(uint sql_errno, const char *message, + MYSQL_ERROR::enum_warning_level level, THD *thd) + { + + /* Only view errors are handled. */ + if (!table->view) + return FALSE; + + /* The handler does not handle the errors raised by itself, obviously. */ + if (within_handler) + return FALSE; + + within_handler= TRUE; + bool is_handled= handle_error_impl(sql_errno, message, level, thd); + within_handler= FALSE; + return is_handled; + } +}; + + bool mysqld_show_create(THD *thd, TABLE_LIST *table_list) { @@ -597,27 +696,12 @@ 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) - 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); - } + 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); /* TODO: add environment variables show when it become possible */ if (thd->lex->only_view && !table_list->view) --===============0637978129== 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-gca-commmit/ # testament_sha1: b3c99eda729228dd699ae2d0525b7bd808e58193 # timestamp: 2009-08-12 16:03:03 +0200 # base_revision_id: davi.arnaut@stripped\ # y7y7n931lbgnesb4 # # Begin bundle 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 IQuol/Y= --===============0637978129==--