mirror of
https://github.com/MariaDB/server.git
synced 2025-07-30 16:24:05 +03:00
Bug#11765687 (MySQL58677): No privilege on table / view, but can know #rows / underlying table's name
1 - If a user had SHOW VIEW and SELECT privileges on a view and this view was referencing another view, EXPLAIN SELECT on the outer view (that the user had privileges on) could reveal the structure of the underlying "inner" view as well as the number of rows in the underlying tables, even if the user had privileges on none of these referenced objects. This happened because we used DEFINER's UID ("SUID") not just for the view given in EXPLAIN, but also when checking privileges on the underlying views (where we should use the UID of the EXPLAIN's INVOKER instead). We no longer run the EXPLAIN SUID (with DEFINER's privileges). This prevents a possible exploit and makes permissions more orthogonal. 2 - EXPLAIN SELECT would reveal a view's structure even if the user did not have SHOW VIEW privileges for that view, as long as they had SELECT privilege on the underlying tables. Instead of requiring both SHOW VIEW privilege on a view and SELECT privilege on all underlying tables, we were checking for presence of either of them. We now explicitly require SHOW VIEW and SELECT privileges on the view we run EXPLAIN SELECT on, as well as all its underlying views. We also require SELECT on all relevant tables.
This commit is contained in:
@ -1148,8 +1148,38 @@ bool mysql_make_view(THD *thd, File_parser *parser, TABLE_LIST *table,
|
||||
if (!table->prelocking_placeholder &&
|
||||
(old_lex->sql_command == SQLCOM_SELECT && old_lex->describe))
|
||||
{
|
||||
if (check_table_access(thd, SELECT_ACL, view_tables, 1) &&
|
||||
check_table_access(thd, SHOW_VIEW_ACL, table, 1))
|
||||
/*
|
||||
The user we run EXPLAIN as (either the connected user who issued
|
||||
the EXPLAIN statement, or the definer of a SUID stored routine
|
||||
which contains the EXPLAIN) should have both SHOW_VIEW_ACL and
|
||||
SELECT_ACL on the view being opened as well as on all underlying
|
||||
views since EXPLAIN will disclose their structure. This user also
|
||||
should have SELECT_ACL on all underlying tables of the view since
|
||||
this EXPLAIN will disclose information about the number of rows in it.
|
||||
|
||||
To perform this privilege check we create auxiliary TABLE_LIST object
|
||||
for the view in order a) to avoid trashing "table->grant" member for
|
||||
original table list element, which contents can be important at later
|
||||
stage for column-level privilege checking b) get TABLE_LIST object
|
||||
with "security_ctx" member set to 0, i.e. forcing check_table_access()
|
||||
to use active user's security context.
|
||||
|
||||
There is no need for creating similar copies of table list elements
|
||||
for underlying tables since they are just have been constructed and
|
||||
thus have TABLE_LIST::security_ctx == 0 and fresh TABLE_LIST::grant
|
||||
member.
|
||||
|
||||
Finally at this point making sure we have SHOW_VIEW_ACL on the views
|
||||
will suffice as we implicitly require SELECT_ACL anyway.
|
||||
*/
|
||||
|
||||
TABLE_LIST view;
|
||||
bzero((char *)&view, sizeof(TABLE_LIST));
|
||||
view.db= table->db;
|
||||
view.table_name= table->table_name;
|
||||
|
||||
if (check_table_access(thd, SELECT_ACL, view_tables, 1) ||
|
||||
check_table_access(thd, SHOW_VIEW_ACL, &view, 1))
|
||||
{
|
||||
my_message(ER_VIEW_NO_EXPLAIN, ER(ER_VIEW_NO_EXPLAIN), MYF(0));
|
||||
goto err;
|
||||
|
Reference in New Issue
Block a user