#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<LEX_STRING> *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)
Attachment: [text/bzr-bundle] bzr/martin.hansson@sun.com-20090812140258-z8r3t7wqr10sbpy0.bundle
| Thread |
|---|
| • bzr commit into mysql-5.1-bugteam branch (martin.hansson:2936) Bug#35996 | Martin Hansson | 12 Aug |