Skip to content

Commit

Permalink
cherrypick executor, privilege: require CONFIG or Process privilege f…
Browse files Browse the repository at this point in the history
…or is.cluster_* (pingcap#26220)

Signed-off-by: ailinkid <314806019@qq.com>
  • Loading branch information
AilinKid committed Jul 16, 2021
1 parent 4150216 commit cd38815
Show file tree
Hide file tree
Showing 3 changed files with 97 additions and 8 deletions.
22 changes: 18 additions & 4 deletions executor/infoschema_reader.go
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,9 @@ type memtableRetriever struct {

// retrieve implements the infoschemaRetriever interface
func (e *memtableRetriever) retrieve(ctx context.Context, sctx sessionctx.Context) ([][]types.Datum, error) {
if e.table.Name.O == infoschema.TableClusterInfo && !hasPriv(sctx, mysql.ProcessPriv) {
return nil, plannercore.ErrSpecificAccessDenied.GenWithStackByArgs("PROCESS")
}
if e.retrieved {
return nil, nil
}
Expand Down Expand Up @@ -1014,10 +1017,21 @@ func (e *memtableRetriever) dataForTiKVStoreStatus(ctx sessionctx.Context) (err
}

func hasPriv(ctx sessionctx.Context, priv mysql.PrivilegeType) bool {
if pm := privilege.GetPrivilegeManager(ctx); pm != nil {
return pm.RequestVerification(ctx.GetSessionVars().ActiveRoles, "", "", "", priv)
}
return false
pm := privilege.GetPrivilegeManager(ctx)
if pm == nil {
// internal session created with createSession doesn't has the PrivilegeManager. For most experienced cases before,
// we use it like this:
// ```
// checker := privilege.GetPrivilegeManager(ctx)
// if checker != nil && !checker.RequestVerification(ctx.GetSessionVars().ActiveRoles, schema.Name.L, table.Name.L, "", mysql.AllPrivMask) {
// continue
// }
// do something.
// ```
// So once the privilege manager is nil, it's a signature of internal sql, so just passing the checker through.
return true
}
return pm.RequestVerification(ctx.GetSessionVars().ActiveRoles, "", "", "", priv)
}

func (e *memtableRetriever) setDataForTableDataLockWaits(ctx sessionctx.Context) error {
Expand Down
14 changes: 14 additions & 0 deletions executor/memtable_reader.go
Original file line number Diff line number Diff line change
Expand Up @@ -293,6 +293,17 @@ type clusterServerInfoRetriever struct {

// retrieve implements the memTableRetriever interface
func (e *clusterServerInfoRetriever) retrieve(ctx context.Context, sctx sessionctx.Context) ([][]types.Datum, error) {
switch e.serverInfoType {
case diagnosticspb.ServerInfoType_LoadInfo,
diagnosticspb.ServerInfoType_SystemInfo:
if !hasPriv(sctx, mysql.ProcessPriv) {
return nil, plannercore.ErrSpecificAccessDenied.GenWithStackByArgs("PROCESS")
}
case diagnosticspb.ServerInfoType_HardwareInfo:
if !hasPriv(sctx, mysql.ConfigPriv) {
return nil, plannercore.ErrSpecificAccessDenied.GenWithStackByArgs("CONFIG")
}
}
if e.extractor.SkipRequest || e.retrieved {
return nil, nil
}
Expand Down Expand Up @@ -485,6 +496,9 @@ func (h *logResponseHeap) Pop() interface{} {
}

func (e *clusterLogRetriever) initialize(ctx context.Context, sctx sessionctx.Context) ([]chan logStreamResult, error) {
if !hasPriv(sctx, mysql.ProcessPriv) {
return nil, plannercore.ErrSpecificAccessDenied.GenWithStackByArgs("PROCESS")
}
serversInfo, err := infoschema.GetClusterServerInfo(sctx)
failpoint.Inject("mockClusterLogServerInfo", func(val failpoint.Value) {
// erase the error
Expand Down
69 changes: 65 additions & 4 deletions privilege/privileges/privileges_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1458,7 +1458,9 @@ func (s *testPrivilegeSuite) TestSecurityEnhancedModeInfoschema(c *C) {

// Even though we have super, we still can't read protected information from tidb_servers_info, cluster_* tables
tk.MustQuery(`SELECT COUNT(*) FROM information_schema.tidb_servers_info WHERE ip IS NOT NULL`).Check(testkit.Rows("0"))
tk.MustQuery(`SELECT COUNT(*) FROM information_schema.cluster_info WHERE status_address IS NOT NULL`).Check(testkit.Rows("0"))
err := tk.QueryToErr(`SELECT COUNT(*) FROM information_schema.cluster_info WHERE status_address IS NOT NULL`)
c.Assert(err, NotNil)
c.Assert(err.Error(), Equals, "[planner:1227]Access denied; you need (at least one of) the PROCESS privilege(s) for this operation")
// 36 = a UUID. Normally it is an IP address.
tk.MustQuery(`SELECT COUNT(*) FROM information_schema.CLUSTER_STATEMENTS_SUMMARY WHERE length(instance) != 36`).Check(testkit.Rows("0"))

Expand All @@ -1476,24 +1478,83 @@ func (s *testPrivilegeSuite) TestSecurityEnhancedModeInfoschema(c *C) {

func (s *testPrivilegeSuite) TestClusterConfigInfoschema(c *C) {
tk := testkit.NewTestKit(c, s.store)
tk.MustExec("CREATE USER ccnobody, ccconfig")
tk.MustExec("CREATE USER ccnobody, ccconfig, ccprocess")
tk.MustExec("GRANT CONFIG ON *.* TO ccconfig")
tk.MustExec("GRANT Process ON *.* TO ccprocess")

// incorrect permissions
// incorrect/no permissions
tk.Se.Auth(&auth.UserIdentity{
Username: "ccnobody",
Hostname: "localhost",
}, nil, nil)
tk.MustQuery("SHOW GRANTS").Check(testkit.Rows("GRANT USAGE ON *.* TO 'ccnobody'@'%'"))

err := tk.QueryToErr("SELECT * FROM information_schema.cluster_config")
c.Assert(err, NotNil)
c.Assert(err.Error(), Equals, "[planner:1227]Access denied; you need (at least one of) the CONFIG privilege(s) for this operation")

// With correct permissions
err = tk.QueryToErr("SELECT * FROM information_schema.cluster_hardware")
c.Assert(err, NotNil)
c.Assert(err.Error(), Equals, "[planner:1227]Access denied; you need (at least one of) the CONFIG privilege(s) for this operation")

err = tk.QueryToErr("SELECT * FROM information_schema.cluster_info")
c.Assert(err, NotNil)
c.Assert(err.Error(), Equals, "[planner:1227]Access denied; you need (at least one of) the PROCESS privilege(s) for this operation")

err = tk.QueryToErr("SELECT * FROM information_schema.cluster_load")
c.Assert(err, NotNil)
c.Assert(err.Error(), Equals, "[planner:1227]Access denied; you need (at least one of) the PROCESS privilege(s) for this operation")

err = tk.QueryToErr("SELECT * FROM information_schema.cluster_systeminfo")
c.Assert(err, NotNil)
c.Assert(err.Error(), Equals, "[planner:1227]Access denied; you need (at least one of) the PROCESS privilege(s) for this operation")

err = tk.QueryToErr("SELECT * FROM information_schema.cluster_log WHERE time BETWEEN '2021-07-13 00:00:00' AND '2021-07-13 02:00:00' AND message like '%'")
c.Assert(err, NotNil)
c.Assert(err.Error(), Equals, "[planner:1227]Access denied; you need (at least one of) the PROCESS privilege(s) for this operation")

// With correct/CONFIG permissions
tk.Se.Auth(&auth.UserIdentity{
Username: "ccconfig",
Hostname: "localhost",
}, nil, nil)

tk.MustQuery("SHOW GRANTS").Check(testkit.Rows("GRANT CONFIG ON *.* TO 'ccconfig'@'%'"))
// Needs CONFIG privilege
tk.MustQuery("SELECT * FROM information_schema.cluster_config")
tk.MustQuery("SELECT * FROM information_schema.cluster_HARDWARE")
// Missing Process privilege
err = tk.QueryToErr("SELECT * FROM information_schema.cluster_INFO")
c.Assert(err, NotNil)
c.Assert(err.Error(), Equals, "[planner:1227]Access denied; you need (at least one of) the PROCESS privilege(s) for this operation")
err = tk.QueryToErr("SELECT * FROM information_schema.cluster_LOAD")
c.Assert(err, NotNil)
c.Assert(err.Error(), Equals, "[planner:1227]Access denied; you need (at least one of) the PROCESS privilege(s) for this operation")
err = tk.QueryToErr("SELECT * FROM information_schema.cluster_SYSTEMINFO")
c.Assert(err, NotNil)
c.Assert(err.Error(), Equals, "[planner:1227]Access denied; you need (at least one of) the PROCESS privilege(s) for this operation")
err = tk.QueryToErr("SELECT * FROM information_schema.cluster_LOG WHERE time BETWEEN '2021-07-13 00:00:00' AND '2021-07-13 02:00:00' AND message like '%'")
c.Assert(err, NotNil)
c.Assert(err.Error(), Equals, "[planner:1227]Access denied; you need (at least one of) the PROCESS privilege(s) for this operation")

// With correct/Process permissions
tk.Se.Auth(&auth.UserIdentity{
Username: "ccprocess",
Hostname: "localhost",
}, nil, nil)
tk.MustQuery("SHOW GRANTS").Check(testkit.Rows("GRANT Process ON *.* TO 'ccprocess'@'%'"))
// Needs Process privilege
tk.MustQuery("SELECT * FROM information_schema.CLUSTER_info")
tk.MustQuery("SELECT * FROM information_schema.CLUSTER_load")
tk.MustQuery("SELECT * FROM information_schema.CLUSTER_systeminfo")
tk.MustQuery("SELECT * FROM information_schema.CLUSTER_log WHERE time BETWEEN '1970-07-13 00:00:00' AND '1970-07-13 02:00:00' AND message like '%'")
// Missing CONFIG privilege
err = tk.QueryToErr("SELECT * FROM information_schema.CLUSTER_config")
c.Assert(err, NotNil)
c.Assert(err.Error(), Equals, "[planner:1227]Access denied; you need (at least one of) the CONFIG privilege(s) for this operation")
err = tk.QueryToErr("SELECT * FROM information_schema.CLUSTER_hardware")
c.Assert(err, NotNil)
c.Assert(err.Error(), Equals, "[planner:1227]Access denied; you need (at least one of) the CONFIG privilege(s) for this operation")
}

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

0 comments on commit cd38815

Please sign in to comment.