Bug #34104 SELECT FROM I_S.STATISTICS have different privilege requirements than SHOW INDEX
Submitted: 28 Jan 2008 13:09 Modified: 4 Feb 2008 11:09
Reporter: Kristofer Pettersson Email Updates:
Status: Verified Impact on me:
None 
Category:MySQL Server: Security: Privileges Severity:S3 (Non-critical)
Version:5.1 OS:Any
Assigned to: Assigned Account CPU Architecture:Any

[28 Jan 2008 13:09] Kristofer Pettersson
Description:
"SHOW INDEX FROM t" should require the same privileges like "SELECT * FROM I_S.STATISTICS WHERE table_name='t'" but it doesn't.

How to repeat:
use mysqltest_db1;
CREATE TABLE t5 (s1 INT);
CREATE INDEX i ON t5 (s1);
CREATE TABLE t6 (s1 INT, s2 INT);
CREATE INDEX i ON t6 (s1);
GRANT UPDATE (s2) ON t6 to mysqltest_u1@localhost;

connection con1;
use mysqltest_db1;
--echo ** Connect as restricted user mysqltest_u1.
--echo ** SELECT FROM INFORMATION_SCHEMA.STATISTICS will succeed because any privileges will do (authentication seems to be enough).
SELECT * FROM INFORMATION_SCHEMA.STATISTICS WHERE table_name='t5';
--echo ** SHOW INDEX FROM t5 will fail because we don't have any privileges on any column combination.
--error 1142
SHOW INDEX FROM t5;

Suggested fix:
In get_all_tables all databases referenced in the sql condition is iterated and access is granted as:

if (!check_access(thd,SELECT_ACL, db_name->str, 
     &thd->col_access, 0, 1, with_i_schema) ||
     sctx->master_access & (DB_ACLS | SHOW_DB_ACL) ||
     acl_get(sctx->host, sctx->ip, sctx->priv_user, db_name->str, 0) ||
     !check_grant_db(thd, db_name->str))

Where the documentation for check_db_grant states that
"Access is accepted if he has a grant for any table/routine in the database"

This check possibly needs to be refined and in the case of I_S.STATISTICS the privilege check should be against User | (DB&Host)
[4 Feb 2008 11:09] MySQL Verification Team
Thank you for the bug report.
[13 May 2016 11:47] Gopal Shankar
More information about the issue:

make_table_name_list() handles 'WHERE TABLE_NAME =' clause
bit differently. And the problem is that this part of code does
not care for access check. If we run a I_S query without
WHERE clause containing TABLE_NAME field, then we see that
table 't5' is not shown and skipped by proper access check.

E.g.,

So the following shows the table 't5', without doing access check.

 => SELECT * FROM INFORMATION_SCHEMA.STATISTICS WHERE table_name='t5';

And the following does not show table 't5', as it does proper
access check,

 => SELECT * FROM INFORMATION_SCHEMA.STATISTICS;

This can be fixed in 5.7 and earlier versions.
In 5.8, this issue would get fixed by WL#6599.