Skip to content

Commit 20b8356

Browse files
craig[bot]fqazi
andcommitted
Merge #156949
156949: sql: prevent mutation of synthetic privilege cache entries r=fqazi a=fqazi Previously, when GRANT / REVOKE were modifying synthetic privileges, they requested a copy of the privilege descriptor from the synthetic privilege cache, which would make a shallow copy. This meant that returned entries were not safe for mutations, since slices would be shared between copies. This could lead to unexpected behavior for concurrent transactions or schema change retries, since slices could get modified in unexpected ways. To address this, this patch marks the existing method as immutable and makes a variant aimed at modification that is labeled as mutable. Fixes: #156503 Fixes: #155822 Fixes: #155858 Fixes: #156393 Fixes: #142992 Release note (bug fix): Transactions running concurrently with a GRANT / REVOKE on virtual tables / external connections could observe modifications incorrectly. Co-authored-by: Faizan Qazi <[email protected]>
2 parents 99e7c38 + 0f2f665 commit 20b8356

File tree

5 files changed

+37
-12
lines changed

5 files changed

+37
-12
lines changed

pkg/sql/authorization.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -156,7 +156,7 @@ func (p *planner) HasPrivilege(
156156
// permission check).
157157
p.maybeAuditSensitiveTableAccessEvent(privilegeObject, privilegeKind)
158158

159-
privs, err := p.getPrivilegeDescriptor(ctx, privilegeObject)
159+
privs, err := p.getImmutablePrivilegeDescriptor(ctx, privilegeObject)
160160
if err != nil {
161161
return false, err
162162
}
@@ -209,7 +209,7 @@ func (p *planner) HasAnyPrivilege(
209209
return true, nil
210210
}
211211

212-
privs, err := p.getPrivilegeDescriptor(ctx, privilegeObject)
212+
privs, err := p.getImmutablePrivilegeDescriptor(ctx, privilegeObject)
213213
if err != nil {
214214
return false, err
215215
}
@@ -373,7 +373,7 @@ func (p *planner) getOwnerOfPrivilegeObject(
373373
if d, ok := privilegeObject.(catalog.TableDescriptor); ok && d.IsVirtualTable() {
374374
return username.NodeUserName(), nil
375375
}
376-
privDesc, err := p.getPrivilegeDescriptor(ctx, privilegeObject)
376+
privDesc, err := p.getImmutablePrivilegeDescriptor(ctx, privilegeObject)
377377
if err != nil {
378378
return username.SQLUsername{}, err
379379
}

pkg/sql/grant_revoke_system.go

Lines changed: 29 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ import (
2121
"github.com/cockroachdb/cockroach/pkg/sql/sem/tree"
2222
"github.com/cockroachdb/cockroach/pkg/sql/sessiondata"
2323
"github.com/cockroachdb/cockroach/pkg/sql/syntheticprivilege"
24+
"github.com/cockroachdb/cockroach/pkg/util/protoutil"
2425
"github.com/cockroachdb/errors"
2526
)
2627

@@ -48,7 +49,7 @@ func (n *changeNonDescriptorBackedPrivilegesNode) startExec(params runParams) er
4849
if err := catprivilege.ValidateSyntheticPrivilegeObject(systemPrivilegeObject); err != nil {
4950
return err
5051
}
51-
syntheticPrivDesc, err := params.p.getPrivilegeDescriptor(params.ctx, systemPrivilegeObject)
52+
syntheticPrivDesc, err := params.p.getMutablePrivilegeDescriptor(params.ctx, systemPrivilegeObject)
5253
if err != nil {
5354
return err
5455
}
@@ -255,10 +256,11 @@ func (n *changeNonDescriptorBackedPrivilegesNode) makeSystemPrivilegeObject(
255256
}
256257
}
257258

258-
// getPrivilegeDescriptor returns the privilege descriptor for the
259+
// getImmutablePrivilegeDescriptor returns the privilege descriptor for the
259260
// object. Note that for non-descriptor backed objects, we query the
260-
// system.privileges table to synthesize a PrivilegeDescriptor.
261-
func (p *planner) getPrivilegeDescriptor(
261+
// system.privileges table to synthesize a PrivilegeDescriptor. The returned
262+
// privilege descriptor is not safe for modification.
263+
func (p *planner) getImmutablePrivilegeDescriptor(
262264
ctx context.Context, po privilege.Object,
263265
) (*catpb.PrivilegeDescriptor, error) {
264266
switch d := po.(type) {
@@ -294,3 +296,26 @@ func (p *planner) getPrivilegeDescriptor(
294296
}
295297
return nil, errors.AssertionFailedf("unknown privilege.Object type %T", po)
296298
}
299+
300+
// getMutablePrivilegeDescriptor returns the privilege descriptor for the
301+
// object. Note that for non-descriptor backed objects, we query the
302+
// system.privileges table to synthesize a PrivilegeDescriptor. The returned
303+
// copy can be safely modified.
304+
func (p *planner) getMutablePrivilegeDescriptor(
305+
ctx context.Context, po privilege.Object,
306+
) (*catpb.PrivilegeDescriptor, error) {
307+
pd, err := p.getImmutablePrivilegeDescriptor(ctx, po)
308+
if err != nil {
309+
return nil, err
310+
}
311+
// No copy is needed for non-synthetic descriptors.
312+
switch d := po.(type) {
313+
case catalog.TableDescriptor:
314+
if !d.IsVirtualTable() {
315+
return pd, nil
316+
}
317+
case catalog.Descriptor:
318+
return pd, nil
319+
}
320+
return protoutil.Clone(pd).(*catpb.PrivilegeDescriptor), nil
321+
}

pkg/sql/information_schema.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -408,7 +408,7 @@ https://www.postgresql.org/docs/9.5/infoschema-column-privileges.html`,
408408
dbNameStr := tree.NewDString(db.GetName())
409409
scNameStr := tree.NewDString(sc.GetName())
410410
columndata := privilege.List{privilege.SELECT, privilege.INSERT, privilege.UPDATE} // privileges for column level granularity
411-
privDesc, err := p.getPrivilegeDescriptor(ctx, table)
411+
privDesc, err := p.getImmutablePrivilegeDescriptor(ctx, table)
412412
if err != nil {
413413
return err
414414
}
@@ -1610,7 +1610,7 @@ func populateTablePrivileges(
16101610
// TODO(knz): This should filter for the current user, see
16111611
// https://github.com/cockroachdb/cockroach/issues/35572
16121612
tableType := table.GetObjectType()
1613-
desc, err := p.getPrivilegeDescriptor(ctx, table)
1613+
desc, err := p.getImmutablePrivilegeDescriptor(ctx, table)
16141614
if err != nil {
16151615
return err
16161616
}
@@ -1623,7 +1623,7 @@ func populateTablePrivileges(
16231623
for _, priv := range u.Privileges {
16241624
// We use this function to check for the grant option so that the
16251625
// object owner also gets is_grantable=true.
1626-
privs, err := p.getPrivilegeDescriptor(ctx, table)
1626+
privs, err := p.getImmutablePrivilegeDescriptor(ctx, table)
16271627
if err != nil {
16281628
return err
16291629
}

pkg/sql/pg_catalog.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3246,7 +3246,7 @@ https://www.postgresql.org/docs/9.6/catalog-pg-shdepend.html`,
32463246
if err = forEachTableDesc(ctx, p, dbContext, opts,
32473247
func(ctx context.Context, descCtx tableDescContext) error {
32483248
db, table := descCtx.database, descCtx.table
3249-
privDesc, err := p.getPrivilegeDescriptor(ctx, table)
3249+
privDesc, err := p.getImmutablePrivilegeDescriptor(ctx, table)
32503250
if err != nil {
32513251
return err
32523252
}

pkg/sql/resolver.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -136,7 +136,7 @@ func (p *planner) HasAnyPrivilegeForSpecifier(
136136
}
137137

138138
if priv.GrantOption {
139-
privDesc, err := p.getPrivilegeDescriptor(ctx, privObject)
139+
privDesc, err := p.getImmutablePrivilegeDescriptor(ctx, privObject)
140140
if err != nil {
141141
return eval.HasNoPrivilege, err
142142
}

0 commit comments

Comments
 (0)