From fcd15f725eaa04723a6807db314fd3c869f07eb6 Mon Sep 17 00:00:00 2001 From: Morgan Tocker Date: Thu, 27 Dec 2018 20:10:35 -0700 Subject: [PATCH] planner: privilege check ANALYZE TABLE stmt (#8486) --- planner/core/planbuilder.go | 8 ++++-- privilege/privileges/privileges_test.go | 37 +++++++++++++++++++++++++ 2 files changed, 43 insertions(+), 2 deletions(-) diff --git a/planner/core/planbuilder.go b/planner/core/planbuilder.go index 5868bc304b9db..87ec96a350385 100644 --- a/planner/core/planbuilder.go +++ b/planner/core/planbuilder.go @@ -119,7 +119,7 @@ type PlanBuilder struct { inUpdateStmt bool // colMapper stores the column that must be pre-resolved. colMapper map[*ast.ColumnNameExpr]int - // Collect the visit information for privilege check. + // visitInfo is used for privilege check. visitInfo []visitInfo tableHintInfo []tableHintInfo optFlag uint64 @@ -275,7 +275,7 @@ func (b *PlanBuilder) buildSet(v *ast.SetStmt) (Plan, error) { return p, nil } -// Detect aggregate function or groupby clause. +// detectSelectAgg detects an aggregate function or GROUP BY clause. func (b *PlanBuilder) detectSelectAgg(sel *ast.SelectStmt) bool { if sel.GroupBy != nil { return true @@ -749,6 +749,10 @@ const ( ) func (b *PlanBuilder) buildAnalyze(as *ast.AnalyzeTableStmt) (Plan, error) { + for _, tbl := range as.TableNames { + b.visitInfo = appendVisitInfo(b.visitInfo, mysql.InsertPriv, tbl.Schema.O, tbl.Name.O, "") + b.visitInfo = appendVisitInfo(b.visitInfo, mysql.SelectPriv, tbl.Schema.O, tbl.Name.O, "") + } if as.MaxNumBuckets == 0 { as.MaxNumBuckets = defaultMaxNumBuckets } else { diff --git a/privilege/privileges/privileges_test.go b/privilege/privileges/privileges_test.go index 3dec73867a627..af3edfbb3db2c 100644 --- a/privilege/privileges/privileges_test.go +++ b/privilege/privileges/privileges_test.go @@ -349,6 +349,43 @@ func (s *testPrivilegeSuite) TestUseDb(c *C) { } +func (s *testPrivilegeSuite) TestAnalyzeTable(c *C) { + + se := newSession(c, s.store, s.dbName) + // high privileged user + mustExec(c, se, "CREATE USER 'asuper'") + mustExec(c, se, "CREATE USER 'anobody'") + mustExec(c, se, "GRANT ALL ON *.* TO 'asuper'") + mustExec(c, se, "FLUSH PRIVILEGES") + mustExec(c, se, "CREATE DATABASE atest") + mustExec(c, se, "use atest") + mustExec(c, se, "CREATE TABLE t1 (a int)") + + c.Assert(se.Auth(&auth.UserIdentity{Username: "asuper", Hostname: "localhost", AuthUsername: "asuper", AuthHostname: "%"}, nil, nil), IsTrue) + mustExec(c, se, "analyze table mysql.user") + // low privileged user + c.Assert(se.Auth(&auth.UserIdentity{Username: "anobody", Hostname: "localhost", AuthUsername: "anobody", AuthHostname: "%"}, nil, nil), IsTrue) + _, err := se.Execute(context.Background(), "analyze table t1") + c.Assert(err, NotNil) // fails + + // try again after SELECT privilege granted + c.Assert(se.Auth(&auth.UserIdentity{Username: "asuper", Hostname: "localhost", AuthUsername: "asuper", AuthHostname: "%"}, nil, nil), IsTrue) + mustExec(c, se, "GRANT SELECT ON atest.* TO 'anobody'") + mustExec(c, se, "FLUSH PRIVILEGES") + c.Assert(se.Auth(&auth.UserIdentity{Username: "anobody", Hostname: "localhost", AuthUsername: "anobody", AuthHostname: "%"}, nil, nil), IsTrue) + _, err = se.Execute(context.Background(), "analyze table t1") + c.Assert(err, NotNil) // stll fails (only select) + + // Add INSERT privilege and it should work. + c.Assert(se.Auth(&auth.UserIdentity{Username: "asuper", Hostname: "localhost", AuthUsername: "asuper", AuthHostname: "%"}, nil, nil), IsTrue) + mustExec(c, se, "GRANT INSERT ON atest.* TO 'anobody'") + mustExec(c, se, "FLUSH PRIVILEGES") + c.Assert(se.Auth(&auth.UserIdentity{Username: "anobody", Hostname: "localhost", AuthUsername: "anobody", AuthHostname: "%"}, nil, nil), IsTrue) + _, err = se.Execute(context.Background(), "analyze table t1") + c.Assert(err, IsNil) + +} + func (s *testPrivilegeSuite) TestInformationSchema(c *C) { // This test tests no privilege check for INFORMATION_SCHEMA database.