diff --git a/mysql-test/suite/perfschema/r/grant.result b/mysql-test/suite/perfschema/r/grant.result index 4679499279f..985473c80f0 100644 --- a/mysql-test/suite/perfschema/r/grant.result +++ b/mysql-test/suite/perfschema/r/grant.result @@ -5,3 +5,19 @@ VARIABLE_NAME VARIABLE_VALUE connection default; disconnect a; drop user a@localhost; +# +# MDEV-35384 Table performance_schema.session_status and other two tables are not shown in information_schema.tables for normal users +# +create user foo@localhost; +connect foo,localhost,foo; +select table_schema,engine from information_schema.tables where table_name='session_status'; +table_schema engine +information_schema MEMORY +performance_schema PERFORMANCE_SCHEMA +select count(*) > 0 as 'table is readable' from performance_schema.session_status; +table is readable +1 +connection default; +disconnect foo; +drop user foo@localhost; +# End of 10.6 tests diff --git a/mysql-test/suite/perfschema/t/grant.test b/mysql-test/suite/perfschema/t/grant.test index 446965dfe9d..7c9bc31104e 100644 --- a/mysql-test/suite/perfschema/t/grant.test +++ b/mysql-test/suite/perfschema/t/grant.test @@ -10,3 +10,16 @@ connection default; disconnect a; drop user a@localhost; +--echo # +--echo # MDEV-35384 Table performance_schema.session_status and other two tables are not shown in information_schema.tables for normal users +--echo # +create user foo@localhost; +connect foo,localhost,foo; +sorted_result; +select table_schema,engine from information_schema.tables where table_name='session_status'; +select count(*) > 0 as 'table is readable' from performance_schema.session_status; +connection default; +disconnect foo; +drop user foo@localhost; + +--echo # End of 10.6 tests diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc index d8053f7e49a..86e4d6415c7 100644 --- a/sql/sql_acl.cc +++ b/sql/sql_acl.cc @@ -8349,7 +8349,8 @@ bool check_grant(THD *thd, privilege_t want_access, TABLE_LIST *tables, if (access) { - switch(access->check(orig_want_access, &t_ref->grant.privilege)) + switch(access->check(orig_want_access, &t_ref->grant.privilege, + any_combination_will_do)) { case ACL_INTERNAL_ACCESS_GRANTED: t_ref->grant.privilege|= orig_want_access; diff --git a/sql/sql_acl.h b/sql/sql_acl.h index 44f3fa64b88..9506b911fa5 100644 --- a/sql/sql_acl.h +++ b/sql/sql_acl.h @@ -205,7 +205,7 @@ public: in save_priv. */ virtual ACL_internal_access_result check(privilege_t want_access, - privilege_t *save_priv) const= 0; + privilege_t *save_priv, bool any_combination_will_do) const= 0; }; /** diff --git a/sql/sql_show.cc b/sql/sql_show.cc index 108346c275e..b654bd8c3d9 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -5174,7 +5174,6 @@ int get_all_tables(THD *thd, TABLE_LIST *tables, COND *cond) DBUG_ENTER("get_all_tables"); LEX *lex= thd->lex; TABLE *table= tables->table; - TABLE_LIST table_acl_check; SELECT_LEX *lsel= tables->schema_select_lex; ST_SCHEMA_TABLE *schema_table= tables->schema_table; IS_table_read_plan *plan= tables->is_table_read_plan; @@ -5264,8 +5263,6 @@ int get_all_tables(THD *thd, TABLE_LIST *tables, COND *cond) goto err; } - bzero((char*) &table_acl_check, sizeof(table_acl_check)); - if (make_db_list(thd, &db_names, &plan->lookup_field_vals)) goto err; @@ -5278,9 +5275,7 @@ int get_all_tables(THD *thd, TABLE_LIST *tables, COND *cond) LEX_CSTRING *db_name= db_names.at(i); DBUG_ASSERT(db_name->length <= NAME_LEN); #ifndef NO_EMBEDDED_ACCESS_CHECKS - if (!(check_access(thd, SELECT_ACL, db_name->str, - &thd->col_access, NULL, 0, 1) || - (!thd->col_access && check_grant_db(thd, db_name->str))) || + if (!check_access(thd, SELECT_ACL, db_name->str, &thd->col_access, 0,0,1) || sctx->master_access & (DB_ACLS | SHOW_DB_ACL) || acl_get(sctx->host, sctx->ip, sctx->priv_user, db_name->str, 0)) #endif @@ -5301,6 +5296,8 @@ int get_all_tables(THD *thd, TABLE_LIST *tables, COND *cond) #ifndef NO_EMBEDDED_ACCESS_CHECKS if (!(thd->col_access & TABLE_ACLS)) { + TABLE_LIST table_acl_check; + table_acl_check.reset(); table_acl_check.db= *db_name; table_acl_check.table_name= *table_name; table_acl_check.grant.privilege= thd->col_access; diff --git a/storage/perfschema/pfs_engine_table.cc b/storage/perfschema/pfs_engine_table.cc index b46eed0b531..f25c28ff441 100644 --- a/storage/perfschema/pfs_engine_table.cc +++ b/storage/perfschema/pfs_engine_table.cc @@ -760,28 +760,34 @@ static bool allow_drop_table_privilege() { PFS_readonly_acl pfs_readonly_acl; ACL_internal_access_result -PFS_readonly_acl::check(privilege_t want_access, privilege_t *save_priv) const +PFS_readonly_acl::check(privilege_t want_access, + privilege_t *save_priv, bool any_combination_will_do) const { const privilege_t always_forbidden= INSERT_ACL | UPDATE_ACL | DELETE_ACL | /* CREATE_ACL | */ REFERENCES_ACL | INDEX_ACL | ALTER_ACL | CREATE_VIEW_ACL | SHOW_VIEW_ACL | TRIGGER_ACL | LOCK_TABLES_ACL; - if (unlikely((want_access & always_forbidden) != NO_ACL)) - return ACL_INTERNAL_ACCESS_DENIED; - - return ACL_INTERNAL_ACCESS_CHECK_GRANT; + if (any_combination_will_do) + return want_access & ~always_forbidden + ? ACL_INTERNAL_ACCESS_CHECK_GRANT: ACL_INTERNAL_ACCESS_DENIED; + else + return want_access & always_forbidden + ? ACL_INTERNAL_ACCESS_DENIED : ACL_INTERNAL_ACCESS_CHECK_GRANT; } PFS_readonly_world_acl pfs_readonly_world_acl; ACL_internal_access_result -PFS_readonly_world_acl::check(privilege_t want_access, privilege_t *save_priv) const +PFS_readonly_world_acl::check(privilege_t want_access, + privilege_t *save_priv, bool any_combination_will_do) const { - ACL_internal_access_result res= PFS_readonly_acl::check(want_access, save_priv); + ACL_internal_access_result res= + PFS_readonly_acl::check(want_access, save_priv, any_combination_will_do); if (res == ACL_INTERNAL_ACCESS_CHECK_GRANT) { - if (want_access == SELECT_ACL) + if (any_combination_will_do ? + ((want_access & SELECT_ACL) != NO_ACL) : (want_access == SELECT_ACL)) res= ACL_INTERNAL_ACCESS_GRANTED; } return res; @@ -790,9 +796,11 @@ PFS_readonly_world_acl::check(privilege_t want_access, privilege_t *save_priv) c PFS_readonly_processlist_acl pfs_readonly_processlist_acl; ACL_internal_access_result PFS_readonly_processlist_acl::check( - privilege_t want_access, privilege_t *save_priv) const { + privilege_t want_access, + privilege_t *save_priv, bool any_combination_will_do) const +{ ACL_internal_access_result res = - PFS_readonly_acl::check(want_access, save_priv); + PFS_readonly_acl::check(want_access, save_priv, any_combination_will_do); if ((res == ACL_INTERNAL_ACCESS_CHECK_GRANT) && (want_access == SELECT_ACL)) { THD *thd = current_thd; @@ -818,34 +826,41 @@ ACL_internal_access_result PFS_readonly_processlist_acl::check( PFS_truncatable_acl pfs_truncatable_acl; ACL_internal_access_result -PFS_truncatable_acl::check(privilege_t want_access, privilege_t *save_priv) const +PFS_truncatable_acl::check(privilege_t want_access, + privilege_t *save_priv, bool any_combination_will_do) const { const privilege_t always_forbidden= INSERT_ACL | UPDATE_ACL | DELETE_ACL | /* CREATE_ACL | */ REFERENCES_ACL | INDEX_ACL | ALTER_ACL | CREATE_VIEW_ACL | SHOW_VIEW_ACL | TRIGGER_ACL | LOCK_TABLES_ACL; - if (unlikely((want_access & always_forbidden) != NO_ACL)) - return ACL_INTERNAL_ACCESS_DENIED; - - return ACL_INTERNAL_ACCESS_CHECK_GRANT; + if (any_combination_will_do) + return want_access & ~always_forbidden + ? ACL_INTERNAL_ACCESS_CHECK_GRANT: ACL_INTERNAL_ACCESS_DENIED; + else + return want_access & always_forbidden + ? ACL_INTERNAL_ACCESS_DENIED : ACL_INTERNAL_ACCESS_CHECK_GRANT; } PFS_truncatable_world_acl pfs_truncatable_world_acl; ACL_internal_access_result -PFS_truncatable_world_acl::check(privilege_t want_access, privilege_t *save_priv) const +PFS_truncatable_world_acl::check(privilege_t want_access, + privilege_t *save_priv, bool any_combination_will_do) const { - ACL_internal_access_result res= PFS_truncatable_acl::check(want_access, save_priv); + ACL_internal_access_result res= + PFS_truncatable_acl::check(want_access, save_priv, any_combination_will_do); if (res == ACL_INTERNAL_ACCESS_CHECK_GRANT) { - if (want_access == DROP_ACL) + if (any_combination_will_do ? + ((want_access & SELECT_ACL) != NO_ACL) : (want_access == SELECT_ACL)) + res= ACL_INTERNAL_ACCESS_GRANTED; + else if (any_combination_will_do ? + ((want_access & DROP_ACL) != NO_ACL) : (want_access == DROP_ACL)) { if (allow_drop_table_privilege()) res= ACL_INTERNAL_ACCESS_GRANTED; } - else if (want_access == SELECT_ACL) - res= ACL_INTERNAL_ACCESS_GRANTED; } return res; } @@ -854,44 +869,48 @@ PFS_truncatable_world_acl::check(privilege_t want_access, privilege_t *save_priv PFS_updatable_acl pfs_updatable_acl; ACL_internal_access_result -PFS_updatable_acl::check(privilege_t want_access, privilege_t *save_priv) const +PFS_updatable_acl::check(privilege_t want_access, + privilege_t *save_priv, bool any_combination_will_do) const { const privilege_t always_forbidden= INSERT_ACL | DELETE_ACL | /* CREATE_ACL | */ REFERENCES_ACL | INDEX_ACL | ALTER_ACL | CREATE_VIEW_ACL | SHOW_VIEW_ACL | TRIGGER_ACL; - if (unlikely((want_access & always_forbidden) != NO_ACL)) - return ACL_INTERNAL_ACCESS_DENIED; - - return ACL_INTERNAL_ACCESS_CHECK_GRANT; + if (any_combination_will_do) + return want_access & ~always_forbidden + ? ACL_INTERNAL_ACCESS_CHECK_GRANT: ACL_INTERNAL_ACCESS_DENIED; + else + return want_access & always_forbidden + ? ACL_INTERNAL_ACCESS_DENIED : ACL_INTERNAL_ACCESS_CHECK_GRANT; } PFS_editable_acl pfs_editable_acl; ACL_internal_access_result -PFS_editable_acl::check(privilege_t want_access, privilege_t *save_priv) const +PFS_editable_acl::check(privilege_t want_access, + privilege_t *save_priv, bool any_combination_will_do) const { const privilege_t always_forbidden= /* CREATE_ACL | */ REFERENCES_ACL | INDEX_ACL | ALTER_ACL | CREATE_VIEW_ACL | SHOW_VIEW_ACL | TRIGGER_ACL; - if (unlikely((want_access & always_forbidden) != NO_ACL)) - return ACL_INTERNAL_ACCESS_DENIED; - - return ACL_INTERNAL_ACCESS_CHECK_GRANT; + if (any_combination_will_do) + return want_access & ~always_forbidden + ? ACL_INTERNAL_ACCESS_CHECK_GRANT: ACL_INTERNAL_ACCESS_DENIED; + else + return want_access & always_forbidden + ? ACL_INTERNAL_ACCESS_DENIED : ACL_INTERNAL_ACCESS_CHECK_GRANT; } PFS_unknown_acl pfs_unknown_acl; ACL_internal_access_result -PFS_unknown_acl::check(privilege_t want_access, privilege_t *save_priv) const +PFS_unknown_acl::check(privilege_t want_access, + privilege_t *save_priv, bool any_combination_will_do) const { const privilege_t always_forbidden= CREATE_ACL | REFERENCES_ACL | INDEX_ACL | ALTER_ACL | CREATE_VIEW_ACL | TRIGGER_ACL; - if (unlikely((want_access & always_forbidden) != NO_ACL)) - return ACL_INTERNAL_ACCESS_DENIED; - /* There is no point in hiding (by enforcing ACCESS_DENIED for SELECT_ACL on performance_schema.*) tables that do not exist anyway. @@ -902,7 +921,12 @@ PFS_unknown_acl::check(privilege_t want_access, privilege_t *save_priv) const The same goes for other DML (INSERT_ACL | UPDATE_ACL | DELETE_ACL), for ease of use: error messages will be less surprising. */ - return ACL_INTERNAL_ACCESS_CHECK_GRANT; + if (any_combination_will_do) + return want_access & ~always_forbidden + ? ACL_INTERNAL_ACCESS_CHECK_GRANT: ACL_INTERNAL_ACCESS_DENIED; + else + return want_access & always_forbidden + ? ACL_INTERNAL_ACCESS_DENIED : ACL_INTERNAL_ACCESS_CHECK_GRANT; } /** diff --git a/storage/perfschema/pfs_engine_table.h b/storage/perfschema/pfs_engine_table.h index 0bf8e58c081..45fded27d24 100644 --- a/storage/perfschema/pfs_engine_table.h +++ b/storage/perfschema/pfs_engine_table.h @@ -340,8 +340,8 @@ public: ~PFS_readonly_acl() = default; - ACL_internal_access_result check(privilege_t want_access, - privilege_t *save_priv) const override; + ACL_internal_access_result check(privilege_t want_access, + privilege_t *save_priv, bool any_combination_will_do) const override; }; /** Singleton instance of PFS_readonly_acl. */ @@ -359,7 +359,7 @@ public: ~PFS_truncatable_acl() = default; ACL_internal_access_result check(privilege_t want_access, - privilege_t *save_priv) const override; + privilege_t *save_priv, bool any_combination_will_do) const override; }; /** Singleton instance of PFS_truncatable_acl. */ @@ -377,7 +377,7 @@ public: ~PFS_updatable_acl() = default; ACL_internal_access_result check(privilege_t want_access, - privilege_t *save_priv) const override; + privilege_t *save_priv, bool any_combination_will_do) const override; }; /** Singleton instance of PFS_updatable_acl. */ @@ -395,7 +395,7 @@ public: ~PFS_editable_acl() = default; ACL_internal_access_result check(privilege_t want_access, - privilege_t *save_priv) const override; + privilege_t *save_priv, bool any_combination_will_do) const override; }; /** Singleton instance of PFS_editable_acl. */ @@ -412,7 +412,7 @@ public: ~PFS_unknown_acl() = default; ACL_internal_access_result check(privilege_t want_access, - privilege_t *save_priv) const override; + privilege_t *save_priv, bool any_combination_will_do) const override; }; /** Singleton instance of PFS_unknown_acl. */ @@ -430,7 +430,8 @@ public: ~PFS_readonly_world_acl() {} - ACL_internal_access_result check(privilege_t want_access, privilege_t *save_priv) const override; + ACL_internal_access_result check(privilege_t want_access, + privilege_t *save_priv, bool any_combination_will_do) const override; }; @@ -449,7 +450,8 @@ public: ~PFS_truncatable_world_acl() {} - ACL_internal_access_result check(privilege_t want_access, privilege_t *save_priv) const override; + ACL_internal_access_result check(privilege_t want_access, + privilege_t *save_priv, bool any_combination_will_do) const override; }; @@ -469,7 +471,7 @@ class PFS_readonly_processlist_acl : public PFS_readonly_acl { {} ACL_internal_access_result check(privilege_t want_access, - privilege_t *save_priv) const override; + privilege_t *save_priv, bool any_combination_will_do) const override; }; /** Singleton instance of PFS_readonly_processlist_acl */