Skip to content

Commit

Permalink
privilege: add DDL and DML privilege check for system tables (#15095) (
Browse files Browse the repository at this point in the history
  • Loading branch information
sre-bot authored Mar 18, 2020
1 parent f7e6943 commit 19adfd7
Show file tree
Hide file tree
Showing 4 changed files with 56 additions and 4 deletions.
23 changes: 23 additions & 0 deletions infoschema/perfschema/tables.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@
package perfschema

import (
"strings"

"github.com/pingcap/parser/model"
"github.com/pingcap/tidb/infoschema"
"github.com/pingcap/tidb/kv"
Expand All @@ -36,6 +38,17 @@ const (
tableNameTiDBProfileGoroutines = "tidb_profile_goroutines"
)

var tableList = []string{
tableNameEventsStatementsSummaryByDigest,
tableNameTiDBProfileCPU,
tableNameTiDBProfileMemory,
tableNameTiDBProfileMutex,
tableNameTiDBProfileAllocs,
tableNameTiDBProfileBlock,
tableNameTiDBProfileGoroutines,
tableNameEventsStatementsSummaryByDigestHistory,
}

// perfSchemaTable stands for the fake table all its data is in the memory.
type perfSchemaTable struct {
infoschema.VirtualTable
Expand All @@ -45,6 +58,16 @@ type perfSchemaTable struct {

var pluginTable = make(map[string]func(autoid.Allocators, *model.TableInfo) (table.Table, error))

// IsPredefinedTable judges whether this table is predefined.
func IsPredefinedTable(tableName string) bool {
for _, name := range tableList {
if strings.EqualFold(tableName, name) {
return true
}
}
return false
}

// RegisterTable registers a new table into TiDB.
func RegisterTable(tableName, sql string,
tableFromMeta func(autoid.Allocators, *model.TableInfo) (table.Table, error)) {
Expand Down
6 changes: 6 additions & 0 deletions infoschema/perfschema/tables_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import (
. "github.com/pingcap/check"
"github.com/pingcap/failpoint"
"github.com/pingcap/tidb/domain"
"github.com/pingcap/tidb/infoschema/perfschema"
"github.com/pingcap/tidb/kv"
"github.com/pingcap/tidb/session"
"github.com/pingcap/tidb/store/mockstore"
Expand Down Expand Up @@ -56,6 +57,11 @@ func (s *testTableSuite) TearDownSuite(c *C) {
s.store.Close()
}

func (s *testTableSuite) TestPredefinedTables(c *C) {
c.Assert(perfschema.IsPredefinedTable("EVENTS_statements_summary_by_digest"), IsTrue)
c.Assert(perfschema.IsPredefinedTable("statements"), IsFalse)
}

func (s *testTableSuite) TestPerfSchemaTables(c *C) {
tk := testkit.NewTestKit(c, s.store)

Expand Down
19 changes: 17 additions & 2 deletions privilege/privileges/privileges.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import (

"github.com/pingcap/parser/auth"
"github.com/pingcap/parser/mysql"
"github.com/pingcap/tidb/infoschema/perfschema"
"github.com/pingcap/tidb/privilege"
"github.com/pingcap/tidb/sessionctx"
"github.com/pingcap/tidb/types"
Expand Down Expand Up @@ -52,15 +53,29 @@ func (p *UserPrivileges) RequestVerification(activeRoles []*auth.RoleIdentity, d
return true
}

// Skip check for INFORMATION_SCHEMA database.
// Skip check for system databases.
// See https://dev.mysql.com/doc/refman/5.7/en/information-schema.html
if strings.EqualFold(db, "INFORMATION_SCHEMA") {
dbLowerName := strings.ToLower(db)
switch dbLowerName {
case util.InformationSchemaName.L:
switch priv {
case mysql.CreatePriv, mysql.AlterPriv, mysql.DropPriv, mysql.IndexPriv, mysql.CreateViewPriv,
mysql.InsertPriv, mysql.UpdatePriv, mysql.DeletePriv:
return false
}
return true
// We should be very careful of limiting privileges, so ignore `mysql` for now.
case util.PerformanceSchemaName.L:
// CREATE and DROP privileges are not limited in the older versions, so ignore them now.
// User may have created some tables in these schema, but predefined tables can't be altered or modified.
if dbLowerName == util.PerformanceSchemaName.L && perfschema.IsPredefinedTable(table) {
switch priv {
case mysql.AlterPriv, mysql.DropPriv, mysql.IndexPriv, mysql.InsertPriv, mysql.UpdatePriv, mysql.DeletePriv:
return false
case mysql.SelectPriv:
return true
}
}
}

mysqlPriv := p.Handle.Get()
Expand Down
12 changes: 10 additions & 2 deletions privilege/privileges/privileges_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -880,8 +880,7 @@ func (s *testPrivilegeSuite) TestAnalyzeTable(c *C) {

}

func (s *testPrivilegeSuite) TestInformationSchema(c *C) {

func (s *testPrivilegeSuite) TestSystemSchema(c *C) {
// This test tests no privilege check for INFORMATION_SCHEMA database.
se := newSession(c, s.store, s.dbName)
mustExec(c, se, `CREATE USER 'u1'@'localhost';`)
Expand All @@ -894,6 +893,15 @@ func (s *testPrivilegeSuite) TestInformationSchema(c *C) {
c.Assert(strings.Contains(err.Error(), "denied to user"), IsTrue)
_, err = se.Execute(context.Background(), "update information_schema.tables set table_name = 'tst' where table_name = 'mysql'")
c.Assert(strings.Contains(err.Error(), "privilege check fail"), IsTrue)

// Test performance_schema.
mustExec(c, se, `select * from performance_schema.events_statements_summary_by_digest`)
_, err = se.Execute(context.Background(), "drop table performance_schema.events_statements_summary_by_digest")
c.Assert(strings.Contains(err.Error(), "denied to user"), IsTrue)
_, err = se.Execute(context.Background(), "update performance_schema.events_statements_summary_by_digest set table_names = 'tst'")
c.Assert(strings.Contains(err.Error(), "privilege check fail"), IsTrue)
_, err = se.Execute(context.Background(), "delete from performance_schema.events_statements_summary_by_digest")
c.Assert(strings.Contains(err.Error(), "privilege check fail"), IsTrue)
}

func (s *testPrivilegeSuite) TestAdminCommand(c *C) {
Expand Down

0 comments on commit 19adfd7

Please sign in to comment.