Re: ExecRTCheckPerms() and many prunable partitions

From: Amit Langote <amitlangote09(at)gmail(dot)com>
To: Tom Lane <tgl(at)sss(dot)pgh(dot)pa(dot)us>
Cc: David Rowley <dgrowleyml(at)gmail(dot)com>, Greg Stark <stark(at)mit(dot)edu>, Zhihong Yu <zyu(at)yugabyte(dot)com>, Julien Rouhaud <rjuju123(at)gmail(dot)com>, Alvaro Herrera <alvherre(at)alvh(dot)no-ip(dot)org>, PostgreSQL Hackers <pgsql-hackers(at)lists(dot)postgresql(dot)org>
Subject: Re: ExecRTCheckPerms() and many prunable partitions
Date: 2022-09-07 09:23:06
Message-ID: CA+HiwqEz4=cjQAYNu1_KU0uOJzaTbunTPjypFCMGNuSYTgCRuA@mail.gmail.com
Views: Raw Message | Whole Thread | Download mbox | Resend email
Thread:
Lists: pgsql-hackers

On Thu, Jul 28, 2022 at 6:04 AM Tom Lane <tgl(at)sss(dot)pgh(dot)pa(dot)us> wrote:
> Amit Langote <amitlangote09(at)gmail(dot)com> writes:
> > [ v16 patches ]
>
> I took a quick look at this ...

Thanks for the review and sorry about the delay.

> I think that the notion behind MergeRelPermissionInfos, ie that
> a single RelPermissionInfo can represent *all* the checks for
> a given table OID, is fundamentally wrong. For example, when
> merging a view into an outer query that references a table
> also used by the view, the checkAsUser fields might be different,
> and the permissions to check might be different, and the columns
> those permissions need to hold for might be different. Blindly
> bms_union'ing the column sets will lead to requiring far more
> permissions than the query should require. Conversely, this
> approach could lead to allowing cases we should reject, if you
> happen to "merge" checkAsUser in a way that ends in checking as a
> higher-privilege user than should be checked.
>
> I'm inclined to think that you should abandon the idea of
> merging RelPermissionInfos at all. It can only buy us much
> in the case of self-joins, which ought to be rare. It'd
> be better to just say "there is one RelPermissionInfo for
> each RTE requiring any sort of permissions check". Either
> that or you need to complicate RelPermissionInfo a lot, but
> I don't see the advantage.

OK, I agree that the complexity of sharing a RelPermissionInfo between
RTEs far exceeds any performance benefit to be had from it.

I have changed things so that there's one RelPermissionInfo for every
RTE_RELATION entry in the range table, except those that the planner
adds when expanding inheritance.

> It'd likely be better to rename ExecutorCheckPerms_hook,
> say to ExecCheckPermissions_hook given the rename of
> ExecCheckRTPerms. As it stands, it *looks* like the API
> of that hook has not changed, when it has. Better to
> break calling code visibly than to make people debug their
> way to an understanding that the List contents are no longer
> what they expected. A different idea could be to pass both
> the rangetable and relpermlist, again making the API break obvious
> (and who's to say a hook might not still want the rangetable?)

I agree it'd be better to break the API more explicitly. Actually, I
decided to adopt both of these suggestions: renamed the hook and kept
the rangeTable parameter.

> In parsenodes.h:
> + List *relpermlist; /* list of RTEPermissionInfo nodes for
> + * the RTE_RELATION entries in rtable */
>
> I find this comment not very future-proof, if indeed it's strictly
> correct even today. Maybe better "list of RelPermissionInfo nodes for
> rangetable entries having perminfoindex > 0". Likewise for the comment
> in RangeTableEntry: there's no compelling reason to assume that all and
> only RELATION RTEs will have RelPermissionInfo. Even if that remains
> true at parse time it's falsified during planning.

Ah right, inheritance children's RTE_RELATION entries don't have one.
I've fixed the comment.

> Also note typo in node name: that comment is the only reference to
> "RTEPermissionInfo" AFAICS. Although, given the redefinition I
> suggest above, arguably "RTEPermissionInfo" is the better name?

Agreed. I've renamed RelPermissionInfo to RTEPermissionInfo and
relpermlist to rtepermlist.

> I'm confused as to why RelPermissionInfo.inh exists. It doesn't
> seem to me that permissions checking should care about child rels.

I had to do this for contrib/sepgsql, sepgsql_dml_privileges() has this:

/*
* If this RangeTblEntry is also supposed to reference inherited
* tables, we need to check security label of the child tables. So, we
* expand rte->relid into list of OIDs of inheritance hierarchy, then
* checker routine will be invoked for each relations.
*/
if (!rte->inh)
tableIds = list_make1_oid(rte->relid);
else
tableIds = find_all_inheritors(rte->relid, NoLock, NULL);

> Why did you add checkAsUser to ForeignScan (and not any other scan
> plan nodes)? At best that's pretty asymmetric, but it seems mighty
> bogus: under what circumstances would an FDW need to know that but
> not any of the other RelPermissionInfo fields? This seems to
> indicate that someplace we should work harder at making the
> RelPermissionInfo list available to FDWs. (CustomScan providers
> might have similar issues, btw.)

I think I had tried doing what you are suggesting -- getting the
checkAsUser from a RelPermissionInfo rather than putting that in
ForeignScan -- though we can't do it, because we need the userid for
child foreign table relations, for which we don't create a
RelPermissionInfo. ForeignScan nodes for child relations don't store
their root parent's RT index, so we can't get the checkAsUser using
the root parent's RelPermissionInfo, like I could do for child foreign
table "result" relations using ResultRelInfo.ri_RootResultRelInfo.

As to why an FDW may not need to know any of the other
RelPermissionInfo fields, IIUC, ExecCheckPermissions() would have done
everything that ought to be done *locally* using that information.
Whatever the remote side needs to know wrt access permission checking
should have been put in fdw_private, no?

On Thu, Jul 28, 2022 at 6:18 AM Tom Lane <tgl(at)sss(dot)pgh(dot)pa(dot)us> wrote:
> ... One more thing: maybe we should rethink where to put
> extraUpdatedCols. Between the facts that it's not used for
> actual permissions checks, and that it's calculated by the
> rewriter not parser, it doesn't seem like it really belongs
> in RelPermissionInfo. Should we keep it in RangeTblEntry?
> Should it go somewhere else entirely? I'm just speculating,
> but now is a good time to think about it.

Indeed, extraUpdatedCols doesn't really seem to belong in
RelPermissionInfo, so I have left it in RangeTblEntry.

Attached updated patches.
--
Thanks, Amit Langote
EDB: http://www.enterprisedb.com

Attachment Content-Type Size
v17-0001-Rework-query-relation-permission-checking.patch application/octet-stream 145.6 KB
v17-0002-Do-not-add-hidden-OLD-NEW-RTEs-to-stored-view-ru.patch application/octet-stream 120.6 KB

In response to

Responses

Browse pgsql-hackers by date

  From Date Subject
Next Message Peter Eisentraut 2022-09-07 09:27:29 Re: build remaining Flex files standalone
Previous Message Justin Pryzby 2022-09-07 09:17:49 Re: [PATCH] Renumber confusing value for GUC_UNIT_BYTE