Skip to content

Commit

Permalink
MDEV-32500 Information schema leaks table names and structure to unau…
Browse files Browse the repository at this point in the history
…thorized users

standard table KEY_COLUMN_USAGE should only show keys where
a user has some privileges on every column of the key

standard table TABLE_CONSTRAINTS should show tables where
a user has any non-SELECT privilege on the table or on any column
of the table

standard table REFERENTIAL_CONSTRAINTS is defined in terms of
TABLE_CONSTRAINTS, so the same rule applies. If the user
has no rights to see the REFERENCED_TABLE_NAME value, it should be NULL

SHOW INDEX (and STATISTICS table) is non-standard, but it seems
reasonable to use the same logic as for KEY_COLUMN_USAGE.
  • Loading branch information
vuvova committed Oct 23, 2023
1 parent 2eee0e9 commit 547dfc0
Show file tree
Hide file tree
Showing 10 changed files with 229 additions and 25 deletions.
1 change: 0 additions & 1 deletion mysql-test/main/grant4.result
Expand Up @@ -101,7 +101,6 @@ ERROR 42000: SELECT command denied to user 'mysqltest_u1'@'localhost' for table
** SHOW INDEX FROM t6 will succeed because there exist a privilege on a column combination on t6.
SHOW INDEX FROM t6;
Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment Index_comment
t6 1 i 1 s1 A NULL NULL NULL YES BTREE
** CHECK TABLE requires any privilege on any column combination and should succeed for t6:
CHECK TABLE t6;
Table Op Msg_type Msg_text
Expand Down
48 changes: 46 additions & 2 deletions mysql-test/main/information_schema_db.result
Expand Up @@ -262,8 +262,8 @@ set global sql_mode=default;
create user foo@localhost;
grant select on test.* to foo@localhost;
create procedure rootonly() select 1;
create sql security definer view v1d as select current_user(),user from information_schema.processlist;
create sql security invoker view v1i as select current_user(),user from information_schema.processlist;
create sql security definer view v1d as select current_user(),user from information_schema.processlist where command!='daemon';
create sql security invoker view v1i as select current_user(),user from information_schema.processlist where command!='daemon';
create sql security definer view v2d as select table_name from information_schema.tables where table_schema='mysql' and table_name like '%user%';
create sql security invoker view v2i as select table_name from information_schema.tables where table_schema='mysql' and table_name like '%user%';
create sql security definer view v3d as select schema_name from information_schema.schemata where schema_name like '%mysql%';
Expand Down Expand Up @@ -341,3 +341,47 @@ drop procedure rootonly;
#
# End of 10.2 tests
#
#
# MDEV-32500 Information schema leaks table names and structure to unauthorized users
#
create database db;
create table db.t1 (x int, key(x)) engine=InnoDB;
create table db.t2 (a int, b int, c int, unique(b), check(c>b), foreign key(c) references db.t1(x)) engine=InnoDB;
create table db.t3 (d int, e int, f int, unique(e), check(f>e), foreign key(f) references db.t1(x),
foreign key(e) references db.t2(b),
foreign key(d) references db.t3(f)
) engine=InnoDB;
create user u@localhost;
grant select (a) on db.t2 to u@localhost;
grant update (d) on db.t3 to u@localhost;
connect con1,localhost,u,,db;
select table_name, column_name from information_schema.columns where table_name like 't_';
table_name column_name
t2 a
t3 d
select table_name, column_name from information_schema.key_column_usage where table_name like 't_';
table_name column_name
select table_name, unique_constraint_name, referenced_table_name from information_schema.referential_constraints where table_name like 't_';
table_name unique_constraint_name referenced_table_name
t3 x NULL
t3 b NULL
t3 f t3
select table_name, constraint_name, constraint_type from information_schema.table_constraints where table_name like 't_';
table_name constraint_name constraint_type
t3 e UNIQUE
t3 CONSTRAINT_1 CHECK
t3 t3_ibfk_1 FOREIGN KEY
t3 t3_ibfk_2 FOREIGN KEY
t3 t3_ibfk_3 FOREIGN KEY
show index in t2;
Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment Index_comment
show index in t3;
Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment Index_comment
t3 1 d 1 d A 0 NULL NULL YES BTREE
disconnect con1;
connection default;
drop user u@localhost;
drop database db;
#
# End of 10.4 tests
#
39 changes: 36 additions & 3 deletions mysql-test/main/information_schema_db.test
@@ -1,7 +1,7 @@
# this test mostly test privilege control (what doesn't work
# in the embedded server by default). So skip the test in embedded-server mode.
-- source include/not_embedded.inc

-- source include/have_innodb.inc
-- source include/testdb_only.inc

set local sql_mode="";
Expand Down Expand Up @@ -256,8 +256,8 @@ set global sql_mode=default;
create user foo@localhost;
grant select on test.* to foo@localhost;
create procedure rootonly() select 1;
create sql security definer view v1d as select current_user(),user from information_schema.processlist;
create sql security invoker view v1i as select current_user(),user from information_schema.processlist;
create sql security definer view v1d as select current_user(),user from information_schema.processlist where command!='daemon';
create sql security invoker view v1i as select current_user(),user from information_schema.processlist where command!='daemon';
create sql security definer view v2d as select table_name from information_schema.tables where table_schema='mysql' and table_name like '%user%';
create sql security invoker view v2i as select table_name from information_schema.tables where table_schema='mysql' and table_name like '%user%';
create sql security definer view v3d as select schema_name from information_schema.schemata where schema_name like '%mysql%';
Expand Down Expand Up @@ -297,3 +297,36 @@ drop procedure rootonly;
--echo #
--echo # End of 10.2 tests
--echo #

--echo #
--echo # MDEV-32500 Information schema leaks table names and structure to unauthorized users
--echo #
create database db;
create table db.t1 (x int, key(x)) engine=InnoDB;
create table db.t2 (a int, b int, c int, unique(b), check(c>b), foreign key(c) references db.t1(x)) engine=InnoDB;
create table db.t3 (d int, e int, f int, unique(e), check(f>e), foreign key(f) references db.t1(x),
foreign key(e) references db.t2(b),
foreign key(d) references db.t3(f)
) engine=InnoDB;

create user u@localhost;
grant select (a) on db.t2 to u@localhost;
grant update (d) on db.t3 to u@localhost;

--connect con1,localhost,u,,db
--sorted_result
select table_name, column_name from information_schema.columns where table_name like 't_';
select table_name, column_name from information_schema.key_column_usage where table_name like 't_';
select table_name, unique_constraint_name, referenced_table_name from information_schema.referential_constraints where table_name like 't_';
select table_name, constraint_name, constraint_type from information_schema.table_constraints where table_name like 't_';
show index in t2;
show index in t3;

--disconnect con1
--connection default
drop user u@localhost;
drop database db;

--echo #
--echo # End of 10.4 tests
--echo #
2 changes: 1 addition & 1 deletion mysql-test/suite/funcs_1/r/is_columns_is.result
Expand Up @@ -287,7 +287,7 @@ def information_schema REFERENTIAL_CONSTRAINTS CONSTRAINT_NAME 3 NULL NO varchar
def information_schema REFERENTIAL_CONSTRAINTS CONSTRAINT_SCHEMA 2 NULL NO varchar 64 192 NULL NULL NULL utf8 utf8_general_ci varchar(64) select NEVER NULL
def information_schema REFERENTIAL_CONSTRAINTS DELETE_RULE 9 NULL NO varchar 64 192 NULL NULL NULL utf8 utf8_general_ci varchar(64) select NEVER NULL
def information_schema REFERENTIAL_CONSTRAINTS MATCH_OPTION 7 NULL NO varchar 64 192 NULL NULL NULL utf8 utf8_general_ci varchar(64) select NEVER NULL
def information_schema REFERENTIAL_CONSTRAINTS REFERENCED_TABLE_NAME 11 NULL NO varchar 64 192 NULL NULL NULL utf8 utf8_general_ci varchar(64) select NEVER NULL
def information_schema REFERENTIAL_CONSTRAINTS REFERENCED_TABLE_NAME 11 NULL YES varchar 64 192 NULL NULL NULL utf8 utf8_general_ci varchar(64) select NEVER NULL
def information_schema REFERENTIAL_CONSTRAINTS TABLE_NAME 10 NULL NO varchar 64 192 NULL NULL NULL utf8 utf8_general_ci varchar(64) select NEVER NULL
def information_schema REFERENTIAL_CONSTRAINTS UNIQUE_CONSTRAINT_CATALOG 4 NULL NO varchar 512 1536 NULL NULL NULL utf8 utf8_general_ci varchar(512) select NEVER NULL
def information_schema REFERENTIAL_CONSTRAINTS UNIQUE_CONSTRAINT_NAME 6 NULL YES varchar 64 192 NULL NULL NULL utf8 utf8_general_ci varchar(64) select NEVER NULL
Expand Down
2 changes: 1 addition & 1 deletion mysql-test/suite/funcs_1/r/is_columns_is_embedded.result
Expand Up @@ -287,7 +287,7 @@ def information_schema REFERENTIAL_CONSTRAINTS CONSTRAINT_NAME 3 NULL NO varchar
def information_schema REFERENTIAL_CONSTRAINTS CONSTRAINT_SCHEMA 2 NULL NO varchar 64 192 NULL NULL NULL utf8 utf8_general_ci varchar(64) NEVER NULL
def information_schema REFERENTIAL_CONSTRAINTS DELETE_RULE 9 NULL NO varchar 64 192 NULL NULL NULL utf8 utf8_general_ci varchar(64) NEVER NULL
def information_schema REFERENTIAL_CONSTRAINTS MATCH_OPTION 7 NULL NO varchar 64 192 NULL NULL NULL utf8 utf8_general_ci varchar(64) NEVER NULL
def information_schema REFERENTIAL_CONSTRAINTS REFERENCED_TABLE_NAME 11 NULL NO varchar 64 192 NULL NULL NULL utf8 utf8_general_ci varchar(64) NEVER NULL
def information_schema REFERENTIAL_CONSTRAINTS REFERENCED_TABLE_NAME 11 NULL YES varchar 64 192 NULL NULL NULL utf8 utf8_general_ci varchar(64) NEVER NULL
def information_schema REFERENTIAL_CONSTRAINTS TABLE_NAME 10 NULL NO varchar 64 192 NULL NULL NULL utf8 utf8_general_ci varchar(64) NEVER NULL
def information_schema REFERENTIAL_CONSTRAINTS UNIQUE_CONSTRAINT_CATALOG 4 NULL NO varchar 512 1536 NULL NULL NULL utf8 utf8_general_ci varchar(512) NEVER NULL
def information_schema REFERENTIAL_CONSTRAINTS UNIQUE_CONSTRAINT_NAME 6 NULL YES varchar 64 192 NULL NULL NULL utf8 utf8_general_ci varchar(64) NEVER NULL
Expand Down
4 changes: 0 additions & 4 deletions mysql-test/suite/funcs_1/r/is_statistics.result
Expand Up @@ -250,8 +250,6 @@ ORDER BY table_schema,table_name,index_name,seq_in_index,column_name;
TABLE_CATALOG TABLE_SCHEMA TABLE_NAME NON_UNIQUE INDEX_SCHEMA INDEX_NAME SEQ_IN_INDEX COLUMN_NAME COLLATION CARDINALITY SUB_PART PACKED NULLABLE INDEX_TYPE COMMENT INDEX_COMMENT
def db_datadict t1 1 db_datadict f2_ind 1 f2 NULL 0 NULL NULL YES HASH
def db_datadict t1 0 db_datadict PRIMARY 1 f1 NULL 0 NULL NULL HASH
def db_datadict_2 t3 1 db_datadict_2 f2f1_ind 1 f2 NULL NULL NULL NULL YES HASH
def db_datadict_2 t3 1 db_datadict_2 f2f1_ind 2 f1 NULL 0 NULL NULL HASH
def db_datadict_2 t3 0 db_datadict_2 f5 1 f5 NULL 0 NULL NULL YES HASH
def db_datadict_2 t3 0 db_datadict_2 PRIMARY 1 f1 NULL 0 NULL NULL HASH
SHOW GRANTS FOR 'testuser1'@'localhost';
Expand Down Expand Up @@ -282,8 +280,6 @@ SELECT * FROM information_schema.statistics
WHERE table_schema LIKE 'db_datadict%'
ORDER BY table_schema,table_name,index_name,seq_in_index,column_name;
TABLE_CATALOG TABLE_SCHEMA TABLE_NAME NON_UNIQUE INDEX_SCHEMA INDEX_NAME SEQ_IN_INDEX COLUMN_NAME COLLATION CARDINALITY SUB_PART PACKED NULLABLE INDEX_TYPE COMMENT INDEX_COMMENT
def db_datadict_2 t3 1 db_datadict_2 f2f1_ind 1 f2 NULL NULL NULL NULL YES HASH
def db_datadict_2 t3 1 db_datadict_2 f2f1_ind 2 f1 NULL 0 NULL NULL HASH
def db_datadict_2 t3 0 db_datadict_2 f5 1 f5 NULL 0 NULL NULL YES HASH
def db_datadict_2 t3 0 db_datadict_2 PRIMARY 1 f1 NULL 0 NULL NULL HASH
SHOW GRANTS FOR 'testuser1'@'localhost';
Expand Down
11 changes: 3 additions & 8 deletions mysql-test/suite/funcs_1/r/is_table_constraints.result
Expand Up @@ -104,11 +104,11 @@ CREATE TABLE db_datadict.t2 (f1 BIGINT, f2 BIGINT, f3 BIGINT, f4 BIGINT,
f5 BIGINT, f6 BIGINT, PRIMARY KEY (f1,f2))
ENGINE = <some_engine_type>;
CREATE USER 'testuser1'@'localhost';
GRANT SELECT(f5) ON db_datadict.t1 TO 'testuser1'@'localhost';
GRANT SELECT(f5), UPDATE(f6) ON db_datadict.t1 TO 'testuser1'@'localhost';
SHOW GRANTS FOR 'testuser1'@'localhost';
Grants for testuser1@localhost
GRANT USAGE ON *.* TO `testuser1`@`localhost`
GRANT SELECT (`f5`) ON `db_datadict`.`t1` TO `testuser1`@`localhost`
GRANT SELECT (`f5`), UPDATE (`f6`) ON `db_datadict`.`t1` TO `testuser1`@`localhost`
SELECT * FROM information_schema.table_constraints
WHERE table_schema = 'db_datadict'
ORDER BY table_schema,table_name, constraint_name;
Expand All @@ -132,7 +132,7 @@ connect testuser1, localhost, testuser1, , db_datadict;
SHOW GRANTS FOR 'testuser1'@'localhost';
Grants for testuser1@localhost
GRANT USAGE ON *.* TO `testuser1`@`localhost`
GRANT SELECT (`f5`) ON `db_datadict`.`t1` TO `testuser1`@`localhost`
GRANT SELECT (`f5`), UPDATE (`f6`) ON `db_datadict`.`t1` TO `testuser1`@`localhost`
SELECT * FROM information_schema.table_constraints
WHERE table_schema = 'db_datadict'
ORDER BY table_schema,table_name, constraint_name;
Expand All @@ -142,11 +142,6 @@ def db_datadict my_idx2 db_datadict t1 UNIQUE
def db_datadict PRIMARY db_datadict t1 PRIMARY KEY
SHOW INDEXES FROM db_datadict.t1;
Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment Index_comment
t1 0 PRIMARY 1 f1 ### ### ### ### ### ### ###
t1 0 PRIMARY 2 f2 ### ### ### ### ### ### ###
t1 0 my_idx1 1 f6 ### ### ### ### ### ### ###
t1 0 my_idx1 2 f1 ### ### ### ### ### ### ###
t1 0 my_idx2 1 f3 ### ### ### ### ### ### ###
SHOW INDEXES FROM db_datadict.t2;
ERROR 42000: SELECT command denied to user 'testuser1'@'localhost' for table `db_datadict`.`t2`
connection default;
Expand Down
2 changes: 1 addition & 1 deletion mysql-test/suite/funcs_1/t/is_table_constraints.test
Expand Up @@ -99,7 +99,7 @@ CREATE TABLE db_datadict.t2 (f1 BIGINT, f2 BIGINT, f3 BIGINT, f4 BIGINT,
ENGINE = $engine_type;

CREATE USER 'testuser1'@'localhost';
GRANT SELECT(f5) ON db_datadict.t1 TO 'testuser1'@'localhost';
GRANT SELECT(f5), UPDATE(f6) ON db_datadict.t1 TO 'testuser1'@'localhost';
SHOW GRANTS FOR 'testuser1'@'localhost';

let $my_select = SELECT * FROM information_schema.table_constraints
Expand Down
1 change: 1 addition & 0 deletions sql/sql_parse.cc
Expand Up @@ -7011,6 +7011,7 @@ static bool check_show_access(THD *thd, TABLE_LIST *table)
FALSE, FALSE))
return TRUE; /* Access denied */

thd->col_access= dst_table->grant.privilege; // for sql_show.cc
/*
Check_grant will grant access if there is any column privileges on
all of the tables thanks to the fourth parameter (bool show_table).
Expand Down

0 comments on commit 547dfc0

Please sign in to comment.