From 71a8ef2bb8c9f2fa4d4892bdddcc0b5ff1c2e88c Mon Sep 17 00:00:00 2001 From: reafans <30926443+reafans@users.noreply.github.com> Date: Fri, 13 Dec 2019 14:26:41 +0800 Subject: [PATCH] infoschema: improve the security vunerability of TABLE_CONSTRAINTS infoschema (#14037) --- infoschema/tables.go | 9 +++++++-- infoschema/tables_test.go | 19 +++++++++++++++++++ 2 files changed, 26 insertions(+), 2 deletions(-) diff --git a/infoschema/tables.go b/infoschema/tables.go index 5e3bc7ae6c..b3413a9144 100644 --- a/infoschema/tables.go +++ b/infoschema/tables.go @@ -1706,10 +1706,15 @@ const ( ) // dataForTableConstraints constructs data for table information_schema.constraints.See https://dev.mysql.com/doc/refman/5.7/en/table-constraints-table.html -func dataForTableConstraints(schemas []*model.DBInfo) [][]types.Datum { +func dataForTableConstraints(ctx sessionctx.Context, schemas []*model.DBInfo) [][]types.Datum { + checker := privilege.GetPrivilegeManager(ctx) var rows [][]types.Datum for _, schema := range schemas { for _, tbl := range schema.Tables { + if checker != nil && !checker.RequestVerification(ctx.GetSessionVars().ActiveRoles, schema.Name.L, tbl.Name.L, "", mysql.AllPrivMask) { + continue + } + if tbl.PKIsHandle { record := types.MakeDatums( catalogVal, // CONSTRAINT_CATALOG @@ -2346,7 +2351,7 @@ func (it *infoschemaTable) getRows(ctx sessionctx.Context, cols []*table.Column) case tableSessionVar: fullRows, err = dataForSessionVar(ctx) case tableConstraints: - fullRows = dataForTableConstraints(dbs) + fullRows = dataForTableConstraints(ctx, dbs) case tableFiles: case tableProfiling: if v, ok := ctx.GetSessionVars().GetSystemVar("profiling"); ok && variable.TiDBOptOn(v) { diff --git a/infoschema/tables_test.go b/infoschema/tables_test.go index f4d41dc622..4beeedc7e8 100644 --- a/infoschema/tables_test.go +++ b/infoschema/tables_test.go @@ -445,6 +445,25 @@ func (s *testTableSuite) TestSomeTables(c *C) { tk.MustQuery("select * from information_schema.SESSION_VARIABLES where VARIABLE_NAME='tidb_retry_limit';").Check(testkit.Rows("tidb_retry_limit 10")) tk.MustQuery("select * from information_schema.ENGINES;").Check(testkit.Rows("InnoDB DEFAULT Supports transactions, row-level locking, and foreign keys YES YES YES")) tk.MustQuery("select * from information_schema.TABLE_CONSTRAINTS where TABLE_NAME='gc_delete_range';").Check(testkit.Rows("def mysql delete_range_index mysql gc_delete_range UNIQUE")) + + //test the privilege of new user for information_schema.table_constraints + tk.MustExec("create user constraints_tester") + constraintsTester := testkit.NewTestKit(c, s.store) + constraintsTester.MustExec("use information_schema") + c.Assert(constraintsTester.Se.Auth(&auth.UserIdentity{ + Username: "constraints_tester", + Hostname: "127.0.0.1", + }, nil, nil), IsTrue) + constraintsTester.MustQuery("select * from information_schema.TABLE_CONSTRAINTS;").Check([][]interface{}{}) + + //test the privilege of user with privilege of mysql.gc_delete_range for information_schema.table_constraints + tk.MustExec("CREATE ROLE r_gc_delete_range ;") + tk.MustExec("GRANT ALL PRIVILEGES ON mysql.gc_delete_range TO r_gc_delete_range;") + tk.MustExec("GRANT r_gc_delete_range TO constraints_tester;") + constraintsTester.MustExec("set role r_gc_delete_range") + c.Assert(len(constraintsTester.MustQuery("select * from information_schema.TABLE_CONSTRAINTS where TABLE_NAME='gc_delete_range';").Rows()), Greater, 0) + constraintsTester.MustQuery("select * from information_schema.TABLE_CONSTRAINTS where TABLE_NAME='tables_priv';").Check([][]interface{}{}) + tk.MustQuery("select * from information_schema.KEY_COLUMN_USAGE where TABLE_NAME='stats_meta' and COLUMN_NAME='table_id';").Check( testkit.Rows("def mysql tbl def mysql stats_meta table_id 1 ")) tk.MustQuery("select * from information_schema.SCHEMATA where schema_name='mysql';").Check(