Re: Fix races conditions in DropRole() and GrantRole()

From: Bertrand Drouvot <bertranddrouvot(dot)pg(at)gmail(dot)com>
To: surya poondla <suryapoondla4(at)gmail(dot)com>
Cc: pgsql-hackers(at)lists(dot)postgresql(dot)org
Subject: Re: Fix races conditions in DropRole() and GrantRole()
Date: 2026-07-09 07:05:54
Message-ID: ak9IUpaxNlhAflKU@bdtpg
Views: Whole Thread | Raw Message | Download mbox | Resend email
Thread:
Lists: pgsql-hackers

Hi Surya,

On Wed, Jul 08, 2026 at 09:45:34PM -0700, surya poondla wrote:
> Hi Bertrand,
>
>
> Thanks for the patch set. I agree the races are real, and reusing the
> RangeVarGetRelidExtended() invalidation-retry idiom is a good fit, the
> retry loop looks correct and closes the window for the covered paths.

Thanks for looking at it!

> Swapping a silent orphan for a detected deadlock is arguably fine, but it's
> a behavior change, could you document the lock ordering

Nice catch! I think that a rare deadlock is better than a rare orphaned entry,
so I added a note in the commit message.

>, and maybe have
> DROP ROLE lock in a canonical (OID-sorted) order?

That would add extra complexity and I'm not sure that sorting only in DROP ROLE
would fully solve it.

Also, I don't think there is precedent in the code tree. So I think we should keep
it simple and just mention it in the commit message.

> 2. DROP ROLE now blocks on unrelated long transactions. The
> AccessShareLock from
> roleSpecsToIds() is held to commit,
> so an open txn that ran GRANT/CREATE ROLE ... ROLE/REASSIGN OWNED touching
> X, blocks a concurrent DROP ROLE X. This is intended behavior, but worth a
> note in the commit message/docs.

Right, added in the commit message. Not sure it's worth an addition in the doc
given that existing locking behavior for role commands is not documented there
either.

> 3. For non-cstring role specs, the else-branch (CURRENT_USER/SESSION_USER)
> does:
> roleid = get_rolespec_oid(rolespec, false);
> LockSharedObject(AuthIdRelationId, roleid, 0, AccessShareLock);
> get_rolespec_oid() returns the backend's cached session OID (GetUserId())
> rather than re-resolving a name, so there is no retry mechanism and
> no post-lock existence check.
> Since DropRole() only blocks dropping the *dropping* session's own user,
> nothing stops another session from dropping this session's login role, so
> "GRANT g TO CURRENT_USER" can still orphan.
> RoleNameCallbackForDropRole() already does this by doing a re-check (a
> SearchSysCache1(AUTHOID) after resolving, erroring if the tuple is gone),
> so the else-branch could do the same after locking.

Good point, done in the attached.

>
> 4. In role-membership-drop-member.spec only checks that the concurrent DROP
> waits; it never asserts the outcome, so it would still pass if the locking
> left an orphan.

I'm not sure how an orphan could be created if we ensure proper locking. That
said this extra check does not hurt, so added for the permutations that would
produce orphans without the patch.

Regards,

--
Bertrand Drouvot
PostgreSQL Contributors Team
RDS Open Source Databases
Amazon Web Services: https://aws.amazon.com

Attachment Content-Type Size
v3-0001-Add-RoleNameGetOid-with-invalidation-based-retry-.patch text/x-diff 13.0 KB
v3-0002-Protect-role-resolution-in-roleSpecsToIds-against.patch text/x-diff 8.3 KB

In response to

Browse pgsql-hackers by date

  From Date Subject
Next Message Anthonin Bonnefoy 2026-07-09 07:09:25 Re: hang during shutdown
Previous Message Peter Eisentraut 2026-07-09 07:04:54 Re: [PATCH] ecpg: use memcpy in a few length-based copies