public inbox for [email protected]
help / color / mirror / Atom feedFrom: Ayush Tiwari <[email protected]>
To: Jacob Champion <[email protected]>
Cc: PostgreSQL Hackers <[email protected]>
Subject: Re: REVOKE's CASCADE protection doesn't work with INHERITed table owners
Date: Mon, 6 Jul 2026 16:33:03 +0530
Message-ID: <CAJTYsWXbrewUuiMekCmah3V3fA+ZvcASyV6CJgaUQ2Wc-M0MLw@mail.gmail.com> (raw)
In-Reply-To: <CAOYmi+n_hw=SC5V1i3BmqfZPfPBRaUSJc+BeOXEKDwRue+WYrg@mail.gmail.com>
References: <CAOYmi+=KTLd+XsEP=TDiZ48iVf-CEc7JrZd5uhWPYWKEfOgyyQ@mail.gmail.com>
<CAOYmi+n_hw=SC5V1i3BmqfZPfPBRaUSJc+BeOXEKDwRue+WYrg@mail.gmail.com>
Hi,
On Fri, 26 Jun 2026 at 05:43, Jacob Champion <
[email protected]> wrote:
> [moving to -hackers]
>
> On Wed, Jun 24, 2026 at 2:57 PM Jacob Champion
> <[email protected]> wrote:
> > TL;DR: The protection in recursive_revoke() against broken GRANT
> > OPTION chains doesn't seem to work properly when the grantee also
> > holds the privileges of the grantor.
>
> More accurately: "when an intermediate grantor in the chain only
> indirectly holds the ability to grant."
>
> > I think the issue is in recursive_revoke()'s usage of aclmask(), which
> > in turn uses has_privs_of_role(). It doesn't seem like that's what was
> > wanted in this particular case... thoughts?
>
> I propose changing that to aclmask_direct(), as in the attached, and
> backpatching all the way down.
>
> To try to prove to myself that this works, I added tests to pin each
> of the three cases that are treated differently by aclmask_direct():
> 1. the grantor has indirect ownership privileges
> 2. the grantor has indirect grant options via INHERIT
> 3. the grantor has indirect grant options via PUBLIC (which is already
> disallowed in practice)
>
Thanks, this looks right to me. I traced recursive_revoke() and the
aclmask() -> aclmask_direct() switch makes sense to me, since a
grant is only ever attributed to a role that holds the option directly
(or the owner), it seems right that recursive_revoke() should judge
"still has it" the same way, rather than counting inherited/superuser
access? The three new test cases line up with that too.
I also tried to expand the existing comment, both to point out the
> pitfall and to explain why the short-circuit works. But I've rewritten
> it at least a dozen times, so if anyone can tell me whether I've made
> sense and/or used the terminology appropriately, I'd appreciate it.
One tiny comment question: the phrase "granted by any role on the chain"
in the new comment reads a little oddly to me, would something like
"still holds the option directly via another grantor" be closer to what
the code checks? Could just be me misreading it.
Apart from the above, patch LGTM.
> I'm pretty sure the following is unintended behavior. It looks
> > potentially related to [1] as well.
>
> (To fix [1] I suspect we need to make a similar tweak to
> check_circularity(), but I haven't looked into that yet.)
>
> [1]
> https://postgr.es/m/CAM6Zo8wD7RtQNhbQHODc9DobiW+GpT=tnqOSMz4+mnzA9m0zMg@mail.gmail.com
On check_circularity() for [1]: I tried the same aclmask_direct() swap,
but since it runs on every GRANT ... WITH GRANT OPTION, which
pg_dump/restore replays, erroring there could make restore/pg_upgrade of
an existing cluster (one already holding the [1] self-grant) fail. Feels
like it may need a companion dump/restore change first.
Regards,
Ayush
view thread (5+ messages) latest in thread
reply
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Reply to all the recipients using the --to and --cc options:
reply via email
To: [email protected]
Cc: [email protected], [email protected], [email protected]
Subject: Re: REVOKE's CASCADE protection doesn't work with INHERITed table owners
In-Reply-To: <CAJTYsWXbrewUuiMekCmah3V3fA+ZvcASyV6CJgaUQ2Wc-M0MLw@mail.gmail.com>
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
This inbox is served by agora; see mirroring instructions
for how to clone and mirror all data and code used for this inbox