From ff1b6ff5b8ad46f15e23aeeec5f0e173c76e7108 Mon Sep 17 00:00:00 2001 From: likzn <1020193211@qq.com> Date: Wed, 22 Jun 2022 01:18:36 +0800 Subject: [PATCH] planner: make some `show stmt` more fine-grained privilege check (#35493) close pingcap/tidb#35393 --- executor/showtest/show_test.go | 26 +++++++++++++++++++------- parser/parser.go | 6 +++--- parser/parser.y | 6 +++--- planner/core/planbuilder.go | 11 ++++++++--- plugin/integration_test.go | 2 ++ 5 files changed, 35 insertions(+), 16 deletions(-) diff --git a/executor/showtest/show_test.go b/executor/showtest/show_test.go index 641207d8b6a37..75e93d9655854 100644 --- a/executor/showtest/show_test.go +++ b/executor/showtest/show_test.go @@ -795,20 +795,32 @@ func TestShowStatsPrivilege(t *testing.T) { tk1 := testkit.NewTestKit(t, store) require.True(t, tk1.Session().Auth(&auth.UserIdentity{Username: "show_stats", Hostname: "%"}, nil, nil)) + e := "[planner:1142]SHOW command denied to user 'show_stats'@'%' for table" + err := tk1.ExecToErr("show stats_meta") + require.ErrorContains(t, err, e) + err = tk1.ExecToErr("SHOW STATS_BUCKETS") + require.ErrorContains(t, err, e) + err = tk1.ExecToErr("SHOW STATS_HISTOGRAMS") + require.ErrorContains(t, err, e) + eqErr := plannercore.ErrDBaccessDenied.GenWithStackByArgs("show_stats", "%", mysql.SystemDB) - _, err := tk1.Exec("show stats_meta") - require.EqualError(t, err, eqErr.Error()) - _, err = tk1.Exec("SHOW STATS_BUCKETS") - require.EqualError(t, err, eqErr.Error()) - _, err = tk1.Exec("SHOW STATS_HEALTHY") - require.EqualError(t, err, eqErr.Error()) - _, err = tk1.Exec("SHOW STATS_HISTOGRAMS") + err = tk1.ExecToErr("SHOW STATS_HEALTHY") require.EqualError(t, err, eqErr.Error()) tk.MustExec("grant select on mysql.* to show_stats") tk1.MustExec("show stats_meta") tk1.MustExec("SHOW STATS_BUCKETS") tk1.MustExec("SHOW STATS_HEALTHY") tk1.MustExec("SHOW STATS_HISTOGRAMS") + + tk.MustExec("create user a@'%' identified by '';") + require.True(t, tk1.Session().Auth(&auth.UserIdentity{Username: "a", Hostname: "%"}, nil, nil)) + tk.MustExec("grant select on mysql.stats_meta to a@'%';") + tk.MustExec("grant select on mysql.stats_buckets to a@'%';") + tk.MustExec("grant select on mysql.stats_histograms to a@'%';") + tk1.MustExec("show stats_meta") + tk1.MustExec("SHOW STATS_BUCKETS") + tk1.MustExec("SHOW STATS_HISTOGRAMS") + } func TestIssue18878(t *testing.T) { diff --git a/parser/parser.go b/parser/parser.go index cfd1786602b21..6263a9718444b 100644 --- a/parser/parser.go +++ b/parser/parser.go @@ -19010,11 +19010,11 @@ yynewstate: } case 1896: { - parser.yyVAL.item = &ast.ShowStmt{Tp: ast.ShowStatsMeta} + parser.yyVAL.item = &ast.ShowStmt{Tp: ast.ShowStatsMeta, Table: &ast.TableName{Name: model.NewCIStr("STATS_META"), Schema: model.NewCIStr(mysql.SystemDB)}} } case 1897: { - parser.yyVAL.item = &ast.ShowStmt{Tp: ast.ShowStatsHistograms} + parser.yyVAL.item = &ast.ShowStmt{Tp: ast.ShowStatsHistograms, Table: &ast.TableName{Name: model.NewCIStr("STATS_HISTOGRAMS"), Schema: model.NewCIStr(mysql.SystemDB)}} } case 1898: { @@ -19022,7 +19022,7 @@ yynewstate: } case 1899: { - parser.yyVAL.item = &ast.ShowStmt{Tp: ast.ShowStatsBuckets} + parser.yyVAL.item = &ast.ShowStmt{Tp: ast.ShowStatsBuckets, Table: &ast.TableName{Name: model.NewCIStr("STATS_BUCKETS"), Schema: model.NewCIStr(mysql.SystemDB)}} } case 1900: { diff --git a/parser/parser.y b/parser/parser.y index 1f175038467c2..465a2c69101aa 100644 --- a/parser/parser.y +++ b/parser/parser.y @@ -10821,11 +10821,11 @@ ShowTargetFilterable: } | "STATS_META" { - $$ = &ast.ShowStmt{Tp: ast.ShowStatsMeta} + $$ = &ast.ShowStmt{Tp: ast.ShowStatsMeta, Table: &ast.TableName{Name: model.NewCIStr("STATS_META"), Schema: model.NewCIStr(mysql.SystemDB)}} } | "STATS_HISTOGRAMS" { - $$ = &ast.ShowStmt{Tp: ast.ShowStatsHistograms} + $$ = &ast.ShowStmt{Tp: ast.ShowStatsHistograms, Table: &ast.TableName{Name: model.NewCIStr("STATS_HISTOGRAMS"), Schema: model.NewCIStr(mysql.SystemDB)}} } | "STATS_TOPN" { @@ -10833,7 +10833,7 @@ ShowTargetFilterable: } | "STATS_BUCKETS" { - $$ = &ast.ShowStmt{Tp: ast.ShowStatsBuckets} + $$ = &ast.ShowStmt{Tp: ast.ShowStatsBuckets, Table: &ast.TableName{Name: model.NewCIStr("STATS_BUCKETS"), Schema: model.NewCIStr(mysql.SystemDB)}} } | "STATS_HEALTHY" { diff --git a/planner/core/planbuilder.go b/planner/core/planbuilder.go index 040573420a076..e4f60984a75b3 100644 --- a/planner/core/planbuilder.go +++ b/planner/core/planbuilder.go @@ -2986,13 +2986,18 @@ func (b *PlanBuilder) buildShow(ctx context.Context, show *ast.ShowStmt) (Plan, p.setSchemaAndNames(buildShowNextRowID()) b.visitInfo = appendVisitInfo(b.visitInfo, mysql.SelectPriv, show.Table.Schema.L, show.Table.Name.L, "", ErrPrivilegeCheckFail) return p, nil - case ast.ShowStatsBuckets, ast.ShowStatsHistograms, ast.ShowStatsMeta, ast.ShowStatsExtended, ast.ShowStatsHealthy, ast.ShowStatsTopN, ast.ShowHistogramsInFlight, ast.ShowColumnStatsUsage: - user := b.ctx.GetSessionVars().User + case ast.ShowStatsExtended, ast.ShowStatsHealthy, ast.ShowStatsTopN, ast.ShowHistogramsInFlight, ast.ShowColumnStatsUsage: var err error - if user != nil { + if user := b.ctx.GetSessionVars().User; user != nil { err = ErrDBaccessDenied.GenWithStackByArgs(user.AuthUsername, user.AuthHostname, mysql.SystemDB) } b.visitInfo = appendVisitInfo(b.visitInfo, mysql.SelectPriv, mysql.SystemDB, "", "", err) + case ast.ShowStatsBuckets, ast.ShowStatsHistograms, ast.ShowStatsMeta: + var err error + if user := b.ctx.GetSessionVars().User; user != nil { + err = ErrTableaccessDenied.GenWithStackByArgs("SHOW", user.AuthUsername, user.AuthHostname, show.Table.Name.L) + } + b.visitInfo = appendVisitInfo(b.visitInfo, mysql.SelectPriv, show.Table.Schema.L, show.Table.Name.L, "", err) case ast.ShowRegions: tableInfo, err := b.is.TableByName(show.Table.Schema, show.Table.Name) if err != nil { diff --git a/plugin/integration_test.go b/plugin/integration_test.go index 96bb5c3295a5f..1c62fa440da6d 100644 --- a/plugin/integration_test.go +++ b/plugin/integration_test.go @@ -485,11 +485,13 @@ func TestAuditLogNormal(t *testing.T) { sql: "show stats_histograms", stmtType: "Show", dbs: "mysql", + tables: "stats_histograms", }, { sql: "show stats_meta", stmtType: "Show", dbs: "mysql", + tables: "stats_meta", }, { sql: "show status",