From 4af27a0a9c5eacab7e580fc015caec1e19586111 Mon Sep 17 00:00:00 2001 From: reshke kirill Date: Fri, 17 Feb 2023 16:05:37 +0000 Subject: [PATCH v1] Fix pg_init_prevs corruption. Drop some acl items from initprivs in pg_init_prevs while DROP ROLE. --- src/backend/catalog/dependency.c | 90 ++++++++++++++++++++++++++++++++ src/backend/commands/user.c | 5 ++ src/backend/utils/adt/acl.c | 3 +- src/include/catalog/dependency.h | 2 + src/include/utils/acl.h | 2 + 5 files changed, 100 insertions(+), 2 deletions(-) diff --git a/src/backend/catalog/dependency.c b/src/backend/catalog/dependency.c index f8a136ba0a..6bdfab5e06 100644 --- a/src/backend/catalog/dependency.c +++ b/src/backend/catalog/dependency.c @@ -3009,3 +3009,93 @@ DeleteInitPrivs(const ObjectAddress *object) table_close(relation, RowExclusiveLock); } + + + +#define ARRNELEMS(x) ArrayGetNItems( ARR_NDIM(x), ARR_DIMS(x)) + +/* + * modify pg_init_prevs ACL for extension objects on role delete + */ +void +DeleteInitPrivsRefs(Oid roleoid) +{ + Relation relation; + ScanKeyData key[1]; + SysScanDesc scan; + HeapTuple oldtuple; + HeapTuple newtuple; + Datum initprivs; + AclItem * acls; + Acl *iniprivsacl; + Acl *new_acl; + bool initprvis_isnull; + bool found; + int dim; + int new_acl_sz; + + Datum values[Natts_pg_init_privs] = {0}; + bool nulls[Natts_pg_init_privs] = {0}; + bool replaces[Natts_pg_init_privs] = {0}; + + + relation = table_open(InitPrivsRelationId, RowExclusiveLock); + + ScanKeyInit(&key[0], + Anum_pg_init_privs_privtype, + BTEqualStrategyNumber, F_CHAREQ, + INITPRIVS_EXTENSION); + + scan = systable_beginscan(relation, InitPrivsObjIndexId, false, + NULL, 1, key); + + while (HeapTupleIsValid(oldtuple = systable_getnext(scan))) { + initprivs = heap_getattr(oldtuple, Anum_pg_init_privs_initprivs, relation->rd_att, &initprvis_isnull); + + if (initprvis_isnull) { + continue; + } + + iniprivsacl = DatumGetAclP(initprivs); + found = false; + + acls = (AclItem *) ARR_DATA_PTR(iniprivsacl); + dim = ARRNELEMS(iniprivsacl); + new_acl_sz = 0; + + for (int i = 0; i < dim; ++ i) { + if (acls[i].ai_grantee == roleoid || acls[i].ai_grantor == roleoid) { + found = true; + continue; + } + new_acl_sz++; + } + + if (!found) { + continue; + } + + new_acl = allocacl(new_acl_sz); + + new_acl_sz = 0; + + for (int i = 0; i < dim; ++ i) { + if (acls[i].ai_grantee == roleoid || acls[i].ai_grantor == roleoid) { + continue; + } + ((AclItem *) ARR_DATA_PTR(new_acl))[new_acl_sz++] = acls[i]; + } + + replaces[Anum_pg_init_privs_initprivs - 1] = true; + values[Anum_pg_init_privs_initprivs - 1] = PointerGetDatum(new_acl); + + newtuple = heap_modify_tuple(oldtuple, RelationGetDescr(relation), + values, nulls, replaces); + + CatalogTupleUpdate(relation, &newtuple->t_self, newtuple); + } + + systable_endscan(scan); + + table_close(relation, RowExclusiveLock); +} \ No newline at end of file diff --git a/src/backend/commands/user.c b/src/backend/commands/user.c index 3a92e930c0..49616439ef 100644 --- a/src/backend/commands/user.c +++ b/src/backend/commands/user.c @@ -1283,6 +1283,11 @@ DropRole(DropRoleStmt *stmt) * Remove settings for this role. */ DropSetting(InvalidOid, roleid); + + /* + * Remove pg_init_privs enries for that role + */ + DeleteInitPrivsRefs(roleid); } /* diff --git a/src/backend/utils/adt/acl.c b/src/backend/utils/adt/acl.c index 8f7522d103..57485bb4dc 100644 --- a/src/backend/utils/adt/acl.c +++ b/src/backend/utils/adt/acl.c @@ -83,7 +83,6 @@ static uint32 cached_db_hash; static const char *getid(const char *s, char *n, Node *escontext); static void putid(char *p, const char *s); -static Acl *allocacl(int n); static void check_acl(const Acl *acl); static const char *aclparse(const char *s, AclItem *aip, Node *escontext); static bool aclitem_match(const AclItem *a1, const AclItem *a2); @@ -399,7 +398,7 @@ aclparse(const char *s, AclItem *aip, Node *escontext) * RETURNS: * the new Acl */ -static Acl * +Acl * allocacl(int n) { Acl *new_acl; diff --git a/src/include/catalog/dependency.h b/src/include/catalog/dependency.h index ffd5e9dc82..d2710968ca 100644 --- a/src/include/catalog/dependency.h +++ b/src/include/catalog/dependency.h @@ -267,4 +267,6 @@ extern void shdepDropOwned(List *roleids, DropBehavior behavior); extern void shdepReassignOwned(List *roleids, Oid newrole); +extern void DeleteInitPrivsRefs(Oid roleoid); + #endif /* DEPENDENCY_H */ diff --git a/src/include/utils/acl.h b/src/include/utils/acl.h index f8e1238fa2..dc8e3227a3 100644 --- a/src/include/utils/acl.h +++ b/src/include/utils/acl.h @@ -276,4 +276,6 @@ extern bool object_ownercheck(Oid classid, Oid objectid, Oid roleid); extern bool has_createrole_privilege(Oid roleid); extern bool has_bypassrls_privilege(Oid roleid); +extern Acl * allocacl(int n); + #endif /* ACL_H */ -- 2.25.1