From 09180fde374270382ef41fca75a0cec65d8a9571 Mon Sep 17 00:00:00 2001 From: Weizhen Wang Date: Mon, 5 Sep 2022 20:08:55 +0800 Subject: [PATCH] planner: fix show View Privilege behave for view table (#37343) close pingcap/tidb#34326 --- executor/explain_test.go | 20 ++++++++++++++++++++ planner/core/logical_plan_builder.go | 15 ++++++++++++--- sessionctx/stmtctx/stmtctx.go | 1 + 3 files changed, 33 insertions(+), 3 deletions(-) diff --git a/executor/explain_test.go b/executor/explain_test.go index a05c0e044249c..4899f8a354403 100644 --- a/executor/explain_test.go +++ b/executor/explain_test.go @@ -24,6 +24,7 @@ import ( "time" "github.com/pingcap/tidb/config" + "github.com/pingcap/tidb/errno" "github.com/pingcap/tidb/parser/auth" plannercore "github.com/pingcap/tidb/planner/core" "github.com/pingcap/tidb/session" @@ -66,6 +67,25 @@ func TestExplainPrivileges(t *testing.T) { err = tk1.ExecToErr("explain format = 'brief' select * from v") require.Equal(t, plannercore.ErrTableaccessDenied.GenWithStackByArgs("SELECT", "explain", "%", "v").Error(), err.Error()) + + // https://github.com/pingcap/tidb/issues/34326 + tk.MustExec("create table t1 (i int)") + tk.MustExec("create table t2 (j int)") + tk.MustExec("create table t3 (k int, secret int)") + + tk.MustExec("create view v1 as select * from t1") + tk.MustExec("create view v2 as select * from v1, t2") + tk.MustExec("create view v3 as select k from t3") + + tk.MustExec("grant select, show view on explaindatabase.v2 to 'explain'@'%'") + tk.MustExec("grant show view on explaindatabase.v1 to 'explain'@'%'") + tk.MustExec("grant select, show view on explaindatabase.t3 to 'explain'@'%'") + tk.MustExec("grant select, show view on explaindatabase.v3 to 'explain'@'%'") + + tk1.MustGetErrMsg("explain select * from v1", "[planner:1142]SELECT command denied to user 'explain'@'%' for table 'v1'") + tk1.MustGetErrCode("explain select * from v2", errno.ErrViewNoExplain) + tk1.MustQuery("explain select * from t3") + tk1.MustQuery("explain select * from v3") } func TestExplainCartesianJoin(t *testing.T) { diff --git a/planner/core/logical_plan_builder.go b/planner/core/logical_plan_builder.go index 50b555db9ad04..e57d951959054 100644 --- a/planner/core/logical_plan_builder.go +++ b/planner/core/logical_plan_builder.go @@ -4874,6 +4874,8 @@ func (b *PlanBuilder) checkRecursiveView(dbName model.CIStr, tableName model.CIS // BuildDataSourceFromView is used to build LogicalPlan from view func (b *PlanBuilder) BuildDataSourceFromView(ctx context.Context, dbName model.CIStr, tableInfo *model.TableInfo) (LogicalPlan, error) { + viewDepth := b.ctx.GetSessionVars().StmtCtx.ViewDepth + b.ctx.GetSessionVars().StmtCtx.ViewDepth++ deferFunc, err := b.checkRecursiveView(dbName, tableInfo.Name) if err != nil { return nil, err @@ -4912,14 +4914,21 @@ func (b *PlanBuilder) BuildDataSourceFromView(ctx context.Context, dbName model. terror.ErrorNotEqual(err, ErrNoSuchTable) && terror.ErrorNotEqual(err, ErrInternal) && terror.ErrorNotEqual(err, ErrFieldNotInGroupBy) && - terror.ErrorNotEqual(err, ErrMixOfGroupFuncAndFields) { + terror.ErrorNotEqual(err, ErrMixOfGroupFuncAndFields) && + terror.ErrorNotEqual(err, ErrViewNoExplain) { err = ErrViewInvalid.GenWithStackByArgs(dbName.O, tableInfo.Name.O) } return nil, err } - + pm := privilege.GetPrivilegeManager(b.ctx) + if viewDepth != 0 && + b.ctx.GetSessionVars().StmtCtx.InExplainStmt && + pm != nil && + !pm.RequestVerification(b.ctx.GetSessionVars().ActiveRoles, dbName.L, tableInfo.Name.L, "", mysql.SelectPriv) { + return nil, ErrViewNoExplain + } if tableInfo.View.Security == model.SecurityDefiner { - if pm := privilege.GetPrivilegeManager(b.ctx); pm != nil { + if pm != nil { for _, v := range b.visitInfo { if !pm.RequestVerificationWithUser(v.db, v.table, v.column, v.privilege, tableInfo.View.Definer) { return nil, ErrViewInvalid.GenWithStackByArgs(dbName.O, tableInfo.Name.O) diff --git a/sessionctx/stmtctx/stmtctx.go b/sessionctx/stmtctx/stmtctx.go index 7a290b264edc9..18945a9e5fb81 100644 --- a/sessionctx/stmtctx/stmtctx.go +++ b/sessionctx/stmtctx/stmtctx.go @@ -145,6 +145,7 @@ type StatementContext struct { // in stmtCtx IsStaleness bool InRestrictedSQL bool + ViewDepth int32 // mu struct holds variables that change during execution. mu struct { sync.Mutex