From 294e42443eb0b11f7d4e04b614e65195747b7fa4 Mon Sep 17 00:00:00 2001 From: shihao zhong Date: Mon, 2 Nov 2026 22:37:32 -0500 Subject: [PATCH 1/2] Ignore FORCE ROW LEVEL SECURITY in initial foreign key checks The owner's own policies could hide rows from these checks, so violations were missed or wrongly reported. Reported-by: Ludwig Kannicht Discussion: https://postgr.es/m/954644F5-A39B-4BC1-B698-56AB42F0316F@luline.de Backpatch-through: 14 --- src/backend/utils/adt/ri_triggers.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/src/backend/utils/adt/ri_triggers.c b/src/backend/utils/adt/ri_triggers.c index 7143a900fe0..35f7095d497 100644 --- a/src/backend/utils/adt/ri_triggers.c +++ b/src/backend/utils/adt/ri_triggers.c @@ -1619,6 +1619,8 @@ RI_Initial_Check(Trigger *trigger, Relation fk_rel, Relation pk_rel) char workmembuf[32]; int spi_result; SPIPlanPtr qplan; + Oid save_userid; + int save_sec_context; riinfo = ri_FetchConstraintInfo(trigger, fk_rel, false); @@ -1792,6 +1794,11 @@ RI_Initial_Check(Trigger *trigger, Relation fk_rel, Relation pk_rel) SPI_connect(); + /* Like the RI triggers, ignore FORCE ROW LEVEL SECURITY */ + GetUserIdAndSecContext(&save_userid, &save_sec_context); + SetUserIdAndSecContext(save_userid, + save_sec_context | SECURITY_NOFORCE_RLS); + /* * Generate the plan. We don't need to cache it, and there are no * arguments to the plan. @@ -1815,6 +1822,8 @@ RI_Initial_Check(Trigger *trigger, Relation fk_rel, Relation pk_rel) InvalidSnapshot, true, false, 1); + SetUserIdAndSecContext(save_userid, save_sec_context); + /* Check result */ if (spi_result != SPI_OK_SELECT) elog(ERROR, "SPI_execute_snapshot returned %s", SPI_result_code_string(spi_result)); @@ -1909,6 +1918,8 @@ RI_PartitionRemove_Check(Trigger *trigger, Relation fk_rel, Relation pk_rel) int spi_result; SPIPlanPtr qplan; int i; + Oid save_userid; + int save_sec_context; riinfo = ri_FetchConstraintInfo(trigger, fk_rel, false); @@ -2031,6 +2042,11 @@ RI_PartitionRemove_Check(Trigger *trigger, Relation fk_rel, Relation pk_rel) SPI_connect(); + /* Like the RI triggers, ignore FORCE ROW LEVEL SECURITY */ + GetUserIdAndSecContext(&save_userid, &save_sec_context); + SetUserIdAndSecContext(save_userid, + save_sec_context | SECURITY_NOFORCE_RLS); + /* * Generate the plan. We don't need to cache it, and there are no * arguments to the plan. @@ -2054,6 +2070,8 @@ RI_PartitionRemove_Check(Trigger *trigger, Relation fk_rel, Relation pk_rel) InvalidSnapshot, true, false, 1); + SetUserIdAndSecContext(save_userid, save_sec_context); + /* Check result */ if (spi_result != SPI_OK_SELECT) elog(ERROR, "SPI_execute_snapshot returned %s", SPI_result_code_string(spi_result)); -- 2.37.1 (Apple Git-137.1)