@@ -40,6 +40,10 @@ func isRestrictedRole(userName, hostname string) bool {
4040
4141// IsRestrictedStatement returns a non-nil error when strict SEM forbids stmt.
4242// It runs the check unconditionally; callers gate on IsStrictEnabled.
43+ //
44+ // The switch is a default-deny allow-list: any StmtNode not matched below is
45+ // rejected by the trailing notSupported call. When adding a new statement
46+ // type, decide explicitly whether it should be allowed or rejected.
4347func IsRestrictedStatement (stmt ast.Node ) error {
4448 switch x := stmt .(type ) {
4549 case * ast.DeallocateStmt ,
@@ -62,7 +66,28 @@ func IsRestrictedStatement(stmt ast.Node) error {
6266 * ast.CreateBindingStmt ,
6367 * ast.DropBindingStmt ,
6468 * ast.SetBindingStmt ,
65- * ast.CompactTableStmt :
69+ * ast.CompactTableStmt ,
70+ // Carried over from the previous default-allow fall-through. They are
71+ // preserved as allow here to keep behavior identical to before the
72+ // switch was tightened to default-deny; revisit each in a follow-up.
73+ * ast.AddQueryWatchStmt ,
74+ * ast.AlterRangeStmt ,
75+ * ast.CalibrateResourceStmt ,
76+ * ast.CallStmt ,
77+ * ast.CancelDistributionJobStmt ,
78+ * ast.CreateStatisticsStmt ,
79+ * ast.DistributeTableStmt ,
80+ * ast.DropProcedureStmt ,
81+ * ast.DropQueryWatchStmt ,
82+ * ast.DropStatisticsStmt ,
83+ * ast.GrantProxyStmt ,
84+ * ast.HelpStmt ,
85+ * ast.ImportIntoActionStmt ,
86+ * ast.ImportIntoStmt ,
87+ * ast.RecommendIndexStmt ,
88+ * ast.RefreshStatsStmt ,
89+ * ast.RestartStmt ,
90+ * ast.TrafficStmt :
6691 return nil
6792 case * ast.LoadDataStmt :
6893 return verifyLoadData (x )
@@ -87,7 +112,7 @@ func IsRestrictedStatement(stmt ast.Node) error {
87112 return notSupported ("SPLIT REGION" )
88113 }
89114
90- return nil
115+ return notSupported ( fmt . Sprintf ( "Unsupported statement: %T" , stmt ))
91116}
92117
93118func verifyDDL (stmt ast.DDLNode ) error {
@@ -158,7 +183,6 @@ func verifySimple(stmt ast.Node) error {
158183 * ast.KillStmt ,
159184 * ast.BinlogStmt ,
160185 * ast.DropStatsStmt ,
161- * ast.SetDefaultRoleStmt ,
162186 * ast.AdminStmt ,
163187 * ast.GrantStmt ,
164188 * ast.RevokeStmt ,
@@ -194,12 +218,50 @@ func verifySimple(stmt ast.Node) error {
194218 }
195219 return nil
196220 case * ast.SetRoleStmt :
221+ // SET ROLE DEFAULT|ALL|ALL EXCEPT can implicitly activate a granted
222+ // restricted role (cloud_admin), bypassing the RoleList-only check.
223+ // Reject those wildcard forms; allow NONE (deactivates everything)
224+ // and the regular form after the RoleList contains no restricted role.
225+ switch s .SetRoleOpt {
226+ case ast .SetRoleNone :
227+ return nil
228+ case ast .SetRoleDefault :
229+ return notSupported ("SET ROLE DEFAULT" )
230+ case ast .SetRoleAll :
231+ return notSupported ("SET ROLE ALL" )
232+ case ast .SetRoleAllExcept :
233+ return notSupported ("SET ROLE ALL EXCEPT" )
234+ }
197235 for _ , role := range s .RoleList {
198236 if isRestrictedRole (role .Username , role .Hostname ) {
199237 return notSupported (fmt .Sprintf ("SET ROLE %s" , role ))
200238 }
201239 }
202240 return nil
241+ case * ast.SetDefaultRoleStmt :
242+ // SET DEFAULT ROLE is the matching write-side: it persists the role
243+ // list a user activates via SET ROLE DEFAULT. Block any attempt to
244+ // (a) target a restricted account (root, cloud_admin) so its default
245+ // role set cannot be tampered with, (b) install a restricted role as
246+ // someone else's default, and (c) use ALL, which would silently
247+ // include cloud_admin when it has been granted to the target.
248+ for _ , user := range s .UserList {
249+ if isRestrictedUser (user .Username , user .Hostname ) {
250+ return notSupported (fmt .Sprintf ("SET DEFAULT ROLE TO %s" , user ))
251+ }
252+ }
253+ switch s .SetRoleOpt {
254+ case ast .SetRoleNone :
255+ return nil
256+ case ast .SetRoleAll :
257+ return notSupported ("SET DEFAULT ROLE ALL" )
258+ }
259+ for _ , role := range s .RoleList {
260+ if isRestrictedRole (role .Username , role .Hostname ) {
261+ return notSupported (fmt .Sprintf ("SET DEFAULT ROLE %s" , role ))
262+ }
263+ }
264+ return nil
203265 case * ast.AlterInstanceStmt :
204266 return notSupported ("ALTER INSTANCE" )
205267 case * ast.ShutdownStmt :
0 commit comments