Re: Fix RLS checks for UPDATE/DELETE FOR PORTION OF leftover rows

From: Dean Rasheed <dean(dot)a(dot)rasheed(at)gmail(dot)com>
To: Paul A Jungwirth <pj(at)illuminatedcomputing(dot)com>
Cc: Chao Li <li(dot)evan(dot)chao(at)gmail(dot)com>, Ayush Tiwari <ayushtiwari(dot)slg01(at)gmail(dot)com>, PostgreSQL-development <pgsql-hackers(at)postgresql(dot)org>, Peter Eisentraut <peter(at)eisentraut(dot)org>
Subject: Re: Fix RLS checks for UPDATE/DELETE FOR PORTION OF leftover rows
Date: 2026-07-15 23:40:20
Message-ID: CAEZATCXW3O9_cniVFtw76zFO5p9D06P1bwMvG8RU4_YFkm0iwA@mail.gmail.com
Views: Whole Thread | Raw Message | Download mbox | Resend email
Thread:
Lists: pgsql-hackers

On Wed, 15 Jul 2026 at 22:02, Paul A Jungwirth
<pj(at)illuminatedcomputing(dot)com> wrote:
>
> Thanks for taking a look! Here is a v4 with those additions.
>

+ <entry><command>UPDATE ... FOR PORTION OF</command></entry>
+ <entry>
+ Filter existing row&nbsp;<footnoteref linkend="rls-select-priv"/> &amp;
+ check new row&nbsp;<footnoteref linkend="rls-select-priv"/>
+ </entry>
+ <entry>

The footnote "rls-select-priv" reads "If read access is required to
either the existing or new row (for example, a WHERE or RETURNING
clause that refers to columns from the relation)." However, FOR
PORTION OF is guaranteed to require read access to the table, so as
with a few other entries in that column, the link to this footnote is
not needed -- it will unconditionally apply the SELECT policy to the
existing and new rows. Similarly for DELETE ... FOR PORTION OF.

+ /*
+ * As with regular INSERT/UPDATE above, if SELECT rights are needed
+ * for the statement, ensure the leftover row remains visible.
+ */
+ if (perminfo->requiredPerms & ACL_SELECT)
+ {
+ List *select_permissive_policies;
+ List *select_restrictive_policies;
+
+ get_policies_for_relation(rel, CMD_SELECT, user_id,
+ &select_permissive_policies,
+ &select_restrictive_policies);
+ add_with_check_options(rel, rt_index,
+ WCO_RLS_INSERT_CHECK,
+ select_permissive_policies,
+ select_restrictive_policies,
+ withCheckOptions,
+ hasSubLinks,
+ true);
+ }

Thinking some more about this, I'm not so sure it's right. For a plain
INSERT, we apply SELECT policies if SELECT permissions are required,
which only happens if there is a RETURNING clause. The reason is to
ensure the user has rights to see the row returned by the RETURNING
clause. However, for the auxiliary INSERTS for leftover portions in
UPDATE/DELETE ... FOR PORTION OF, even if there is a RETURNING clause,
it will only return the updated/deleted row, not the leftover rows.
The command never reads the leftover rows, so why do we need the
leftover rows to satisfy the SELECT policies?

Regards,
Dean

In response to

Responses

Browse pgsql-hackers by date

  From Date Subject
Next Message Masahiko Sawada 2026-07-16 00:09:15 Follow-up fixes for online wal_level change
Previous Message Zsolt Parragi 2026-07-15 23:09:45 Re: [DESIGN] Soft DROP TABLE, recoverable drops for PostgreSQL