From 1a1aa7c374a6b8a72883768aab258d8b8cb8c9e4 Mon Sep 17 00:00:00 2001 From: Bertrand Drouvot Date: Thu, 25 Jun 2026 04:16:03 +0000 Subject: [PATCH v28 4/5] Discard ACL tracking entries from aborted subtransactions Store SubTransactionId in each AclCheckEntry at recording time. On subtransaction abort, AtEOSubXact_AclTrack() discards entries whose subxid is >= the aborting subtransaction's ID. Author: Bertrand Drouvot Discussion: https://postgr.es/m/ZiYjn0eVc7pxVY45@ip-10-97-1-34.eu-west-3.compute.internal --- src/backend/access/transam/xact.c | 2 ++ src/backend/catalog/aclchk.c | 24 ++++++++++++++++++++++++ src/include/catalog/aclcheck_track.h | 4 ++++ 3 files changed, 30 insertions(+) 9.0% src/backend/access/transam/ 73.2% src/backend/catalog/ 17.7% src/include/catalog/ diff --git a/src/backend/access/transam/xact.c b/src/backend/access/transam/xact.c index de4cf96eaa2..90bee71d670 100644 --- a/src/backend/access/transam/xact.c +++ b/src/backend/access/transam/xact.c @@ -32,6 +32,7 @@ #include "access/xlogrecovery.h" #include "access/xlogutils.h" #include "access/xlogwait.h" +#include "catalog/aclcheck_track.h" #include "catalog/index.h" #include "catalog/namespace.h" #include "catalog/pg_enum.h" @@ -5386,6 +5387,7 @@ AbortSubTransaction(void) if (FullTransactionIdIsValid(s->fullTransactionId)) AtSubAbort_childXids(); + AtEOSubXact_AclTrack(false, s->subTransactionId); CallSubXactCallbacks(SUBXACT_EVENT_ABORT_SUB, s->subTransactionId, s->parent->subTransactionId); diff --git a/src/backend/catalog/aclchk.c b/src/backend/catalog/aclchk.c index fb51ea2e869..5bd4ecf7130 100644 --- a/src/backend/catalog/aclchk.c +++ b/src/backend/catalog/aclchk.c @@ -5075,3 +5075,27 @@ FreeTrackAclTable(TrackAclTable *acltable) pfree(acltable->entries); pfree(acltable); } + +/* + * AtEOSubXact_AclTrack + * + * At subtransaction abort, discard any ACL tracking entries that were added + * during the aborted subtransaction. This prevents stale entries from causing + * false permission-denied errors in recheckAcl(). + * + * At subtransaction commit, do nothing, entries from committed subtransactions + * are valid and should be kept. + */ +void +AtEOSubXact_AclTrack(bool isCommit, SubTransactionId mySubid) +{ + TrackAclTable *acltable = CurrentTrackAclTable; + + if (acltable == NULL || isCommit) + return; + + /* Discard entries from the aborting subtransaction and any nested ones */ + while (acltable->count > 0 && + acltable->entries[acltable->count - 1].subxid >= mySubid) + acltable->count--; +} diff --git a/src/include/catalog/aclcheck_track.h b/src/include/catalog/aclcheck_track.h index 4ac65e4de5c..27f6c47eb43 100644 --- a/src/include/catalog/aclcheck_track.h +++ b/src/include/catalog/aclcheck_track.h @@ -23,6 +23,7 @@ #ifndef ACLCHECK_TRACK_H #define ACLCHECK_TRACK_H +#include "access/xact.h" #include "storage/sinval.h" #include "utils/acl.h" @@ -34,6 +35,7 @@ typedef struct AclCheckEntry Oid roleId; AclMode mode; uint64 inval_count; + SubTransactionId subxid; } AclCheckEntry; typedef struct TrackAclTable @@ -47,6 +49,7 @@ extern TrackAclTable *CurrentTrackAclTable; extern TrackAclTable *CreateTrackAclTable(void); extern void FreeTrackAclTable(TrackAclTable *acltable); +extern void AtEOSubXact_AclTrack(bool isCommit, SubTransactionId mySubid); /* * Record an aclcheck for later revalidation. @@ -79,6 +82,7 @@ aclcheck_track_record(Oid classId, Oid objectId, AttrNumber attnum, entry->roleId = roleId; entry->mode = mode; entry->inval_count = SharedInvalidMessageCounter; + entry->subxid = GetCurrentSubTransactionId(); } #endif /* ACLCHECK_TRACK_H */ -- 2.34.1