From cfe1a262bc5d9ea5b8cd8eba6005c52b56e2ebbf Mon Sep 17 00:00:00 2001 From: jian he Date: Tue, 23 Dec 2025 09:56:30 +0800 Subject: [PATCH v2 1/3] add RangeTblEntry to CreatePolicyStmt MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Currently CreatePolicy is only directly called through parser.  But imagine copying policies from one table to another table (CREATE TABLE LIKE INCLUDING POLICIES) or changing a column's data type (ALTER COLUMN SET DATA TYPE). In these case, CreatePolicy will be called indirectly, either via the parser, or by constructing a CreatePolicyStmt node from catalog metadata. These indirectly called CreatePolicy may cause repeated lookup CreatePolicyStmt->table RangeVar.  (The relation already exists, but lookup up again via RangeVar). Generally we should avoid look up the same less-than-fully-qualified name multiple times, we might get different answers due to concurrent activity, and that might create a security vulnerability, along the lines of CVE-2014-0062. To avoid that, Add add a RangeTblEntry Node to CreatePolicyStmt, So we can record the Relation Oid advance. discussion: https://postgr.es/m/CACJufxE42vysVEDEmaoBGmGYLZTCgUAwh_h-c9dcSLDtD5jE3g@mail.gmail.com discussion: https://postgr.es/m/CACJufxFuEOB-i2z2qhyCG=dGwDf7g6Fs_o8cz=BUi76UuUFSOA@mail.gmail.com --- src/backend/commands/policy.c | 21 ++++++++++++++++----- src/backend/parser/gram.y | 1 + src/include/nodes/parsenodes.h | 10 ++++++++++ 3 files changed, 27 insertions(+), 5 deletions(-) diff --git a/src/backend/commands/policy.c b/src/backend/commands/policy.c index 5bd5f8c9968..a47744962e9 100644 --- a/src/backend/commands/policy.c +++ b/src/backend/commands/policy.c @@ -623,11 +623,22 @@ CreatePolicy(CreatePolicyStmt *stmt) memset(values, 0, sizeof(values)); memset(isnull, 0, sizeof(isnull)); - /* Get id of table. Also handles permissions checks. */ - table_id = RangeVarGetRelidExtended(stmt->table, AccessExclusiveLock, - 0, - RangeVarCallbackForPolicy, - stmt); + if (stmt->rte != NULL) + table_id = stmt->rte->relid; + else + { + /* Get id of table. Also handles permissions checks. */ + table_id = RangeVarGetRelidExtended(stmt->table, AccessExclusiveLock, + 0, + RangeVarCallbackForPolicy, + stmt); + + /* Create a range table entry. */ + stmt->rte = makeNode(RangeTblEntry); + stmt->rte->rtekind = RTE_RELATION; + stmt->rte->relid = table_id; + stmt->rte->rellockmode = AccessExclusiveLock; + } /* Open target_table to build quals. No additional lock is necessary. */ target_table = relation_open(table_id, NoLock); diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y index 28f4e11e30f..f6d46f08c22 100644 --- a/src/backend/parser/gram.y +++ b/src/backend/parser/gram.y @@ -6023,6 +6023,7 @@ CreatePolicyStmt: n->policy_name = $3; n->table = $5; + n->rte = NULL; n->permissive = $6; n->cmd_name = $7; n->roles = $8; diff --git a/src/include/nodes/parsenodes.h b/src/include/nodes/parsenodes.h index bc7adba4a0f..7acbd2bf72c 100644 --- a/src/include/nodes/parsenodes.h +++ b/src/include/nodes/parsenodes.h @@ -3094,6 +3094,16 @@ typedef struct CreatePolicyStmt NodeTag type; char *policy_name; /* Policy's name */ RangeVar *table; /* the table name the policy applies to */ + + /* + * RangeTblEntry for the table. This is useful for avoid repeated name + * lookups issue. If CreatePolicyStmt.table has been looked up, we should + * not rely on it to resolve the relation again, use this rte field + * instead. This is useful when calling CreatePolicy not directly from + * parser. + */ + RangeTblEntry *rte; + char *cmd_name; /* the command name the policy applies to */ bool permissive; /* restrictive or permissive policy */ List *roles; /* the roles associated with the policy */ -- 2.34.1