On Fri, Aug 9, 2024 at 10:18 AM Dmitry Koval <d.ko...@postgrespro.ru> wrote:
> > This breaks from the CVE-2014-0062 (commit 5f17304) principle of not 
> > repeating
> > name lookups.  The attached demo uses this defect to make one partition have
> > two parents.
>
> Thank you very much for information (especially for the demo)!
>
> I'm not sure that we can get the identifier of the newly created
> partition from the ProcessUtility() function...
> Maybe it would be enough to check that the new partition is located in
> the namespace in which we created it (see attachment)?

The new partition doesn't necessarily get created in the same
namespace as parent partition.  I think it would be better to somehow
open partition by its oid.

It would be quite unfortunate to replicate significant part of
ProcessUtilitySlow().  So, the question is how to get the oid of newly
created relation from ProcessUtility().  I don't like to change the
signature of ProcessUtility() especially as a part of backpatch.  So,
I tried to fit this into existing parameters.  Probably
QueryCompletion struct fits this purpose best from the existing
parameters.  Attached draft patch implements returning oid of newly
created relation as part of QueryCompletion.  Thoughts?

------
Regards,
Alexander Korotkov
Supabase
From 83b6d8e38d680daa952542f6ae4a41ae48491a62 Mon Sep 17 00:00:00 2001
From: Alexander Korotkov <akorotkov@postgresql.org>
Date: Sat, 10 Aug 2024 16:19:28 +0300
Subject: [PATCH v1] Fix createPartitionTable() security issue

---
 src/backend/commands/tablecmds.c | 6 ++++--
 src/backend/tcop/utility.c       | 2 ++
 src/include/tcop/cmdtag.h        | 3 +++
 3 files changed, 9 insertions(+), 2 deletions(-)

diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c
index 1f94f4fdbbc..c64b4953da8 100644
--- a/src/backend/commands/tablecmds.c
+++ b/src/backend/commands/tablecmds.c
@@ -20329,6 +20329,7 @@ createPartitionTable(RangeVar *newPartName, Relation modelRel,
 	TableLikeClause *tlc;
 	PlannedStmt *wrapper;
 	Relation	newRel;
+	QueryCompletion qc;
 
 	/* If existing rel is temp, it must belong to this session */
 	if (modelRel->rd_rel->relpersistence == RELPERSISTENCE_TEMP &&
@@ -20373,6 +20374,7 @@ createPartitionTable(RangeVar *newPartName, Relation modelRel,
 	wrapper->stmt_location = context->pstmt->stmt_location;
 	wrapper->stmt_len = context->pstmt->stmt_len;
 
+	qc.commandTag = CMDTAG_UNKNOWN;
 	ProcessUtility(wrapper,
 				   context->queryString,
 				   false,
@@ -20380,13 +20382,13 @@ createPartitionTable(RangeVar *newPartName, Relation modelRel,
 				   NULL,
 				   NULL,
 				   None_Receiver,
-				   NULL);
+				   &qc);
 
 	/*
 	 * Open the new partition with no lock, because we already have
 	 * AccessExclusiveLock placed there after creation.
 	 */
-	newRel = table_openrv(newPartName, NoLock);
+	newRel = table_open(qc.tableAddress.objectId, NoLock);
 
 	/*
 	 * We intended to create the partition with the same persistence as the
diff --git a/src/backend/tcop/utility.c b/src/backend/tcop/utility.c
index b2ea8125c92..e8a83e0c569 100644
--- a/src/backend/tcop/utility.c
+++ b/src/backend/tcop/utility.c
@@ -1165,6 +1165,8 @@ ProcessUtilitySlow(ParseState *pstate,
 													 RELKIND_RELATION,
 													 InvalidOid, NULL,
 													 queryString);
+							if (qc)
+								qc->tableAddress = address;
 							EventTriggerCollectSimpleCommand(address,
 															 secondaryObject,
 															 stmt);
diff --git a/src/include/tcop/cmdtag.h b/src/include/tcop/cmdtag.h
index 23c99d7eca6..a964a8c0cb7 100644
--- a/src/include/tcop/cmdtag.h
+++ b/src/include/tcop/cmdtag.h
@@ -13,6 +13,8 @@
 #ifndef CMDTAG_H
 #define CMDTAG_H
 
+#include "catalog/objectaddress.h"
+
 /* buffer size required for command completion tags */
 #define COMPLETION_TAG_BUFSIZE	64
 
@@ -29,6 +31,7 @@ typedef enum CommandTag
 typedef struct QueryCompletion
 {
 	CommandTag	commandTag;
+	ObjectAddress tableAddress;
 	uint64		nprocessed;
 } QueryCompletion;
 
-- 
2.39.3 (Apple Git-146)

Reply via email to