Hi, While working on an unrelated RLS patch, I noticed that equalPolicy() in relcache.c doesn't compare the permissive field of RowSecurityPolicy. It compares polcmd, hassublinks, policy_name, roles, qual, and with_check_qual, but not permissive, so two policies that are identical in every other respect except their PERMISSIVE/RESTRICTIVE designation are reported as equal.
equalPolicy() is used (via equalRSDesc()) by RelationRebuildRelation() to decide whether an open relation's existing row-security descriptor can be kept as-is across a relcache rebuild, or must be treated as changed. ALTER POLICY has no way to flip a policy's PERMISSIVE/RESTRICTIVE designation, but DROP POLICY followed by CREATE POLICY of the same name, roles, command, and quals, differing only in AS PERMISSIVE/RESTRICTIVE, hits this exactly: the stale descriptor would be kept, leaving the relcache out of sync with how the policy should now combine with others (PERMISSIVE policies are ORed together; RESTRICTIVE policies are ANDed with the rest). I wasn't able to construct a simple SQL reproduction: RelationRebuildRelation() (and thus this comparison) is only reached while the relation is still open (refcount > 0) at the moment its invalidation is processed. Closing and reopening the relation between statements -- the usual behavior -- sidesteps the bug, and a second session can't hold the relation open across the DROP/CREATE either, since both need AccessExclusiveLock. This looks analogous to ab6d1cd26eb, which fixed the same kind of omission in this function for the USING qual and likewise shipped without a test. Patch attached. Regards, Andreas Lind
0001-Fix-relcache-s-equalPolicy-to-compare-the-permissive.patch
Description: Binary data
