Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

privilege: add DDL and DML privilege check for system tables (#15095) (#15417) #15445

Merged
merged 2 commits into from
Mar 18, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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