You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cloudberry.apache.org by re...@apache.org on 2025/02/20 08:48:24 UTC

(cloudberry) 05/06: Run REFRESH MATERIALIZED VIEW CONCURRENTLY in right security context

This is an automated email from the ASF dual-hosted git repository.

reshke pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/cloudberry.git

commit d42418a3457e7e968d4358faa5949536cc3c2410
Author: Heikki Linnakangas <he...@iki.fi>
AuthorDate: Mon Feb 5 11:01:23 2024 +0200

    Run REFRESH MATERIALIZED VIEW CONCURRENTLY in right security context
    
    The internal commands in REFRESH MATERIALIZED VIEW CONCURRENTLY are
    correctly executed in SECURITY_RESTRICTED_OPERATION mode, except for
    creating the temporary "diff" table, because you cannot create
    temporary tables in SRO mode. But creating the temporary "diff" table
    is a pretty complex CTAS command that selects from another temporary
    table created earlier in the command. If you can cajole that CTAS
    command to execute code defined by the table owner, the table owner
    can run code with the privileges of the user running the REFRESH
    command.
    
    The proof-of-concept reported to the security team relied on CREATE
    RULE to convert the internally-built temp table to a view. That's not
    possible since commit b23cd185fd, and I was not able to find a
    different way to turn the SELECT on the temp table into code
    execution, so as far as I know this is only exploitable in v15 and
    below. That's a fiddly assumption though, so apply this patch to
    master and all stable versions.
    
    Thanks to Pedro Gallegos for the report.
    
    Security: CVE-2024-0985 (not CVE-2023-5869 as claimed in original commit msg)
    Reviewed-by: Noah Misch
    (cherry picked from commit 2699fc035a75d0774c1f013e9320882287f78adb)
---
 src/backend/commands/matview.c | 38 +++++++++++++++++++++++++++++---------
 1 file changed, 29 insertions(+), 9 deletions(-)

diff --git a/src/backend/commands/matview.c b/src/backend/commands/matview.c
index 0d3e9f407d..7a4d0a77c8 100644
--- a/src/backend/commands/matview.c
+++ b/src/backend/commands/matview.c
@@ -1189,17 +1189,40 @@ refresh_by_match_merge(Oid matviewOid, Oid tempOid, Oid relowner,
 						   SPI_getvalue(SPI_tuptable->vals[0], SPI_tuptable->tupdesc, 1))));
 	}
 
+	/*
+	 * Create the temporary "diff" table.
+	 *
+	 * Temporarily switch out of the SECURITY_RESTRICTED_OPERATION context,
+	 * because you cannot create temp tables in SRO context.  For extra
+	 * paranoia, add the composite type column only after switching back to
+	 * SRO context.
+	 */
 	SetUserIdAndSecContext(relowner,
 						   save_sec_context | SECURITY_LOCAL_USERID_CHANGE);
 
-	/* Start building the query for creating the diff table. */
 	resetStringInfo(&querybuf);
 
 	appendStringInfo(&querybuf,
-					 "CREATE TEMP TABLE %s AS "
-					 "SELECT mv.ctid AS tid, mv.gp_segment_id as sid, newdata.*::%s AS newdata "
+					 "CREATE TEMP TABLE %s (tid pg_catalog.tid)",
+					 diffname);
+	if (SPI_exec(querybuf.data, 0) != SPI_OK_UTILITY)
+		elog(ERROR, "SPI_exec failed: %s", querybuf.data);
+	SetUserIdAndSecContext(relowner,
+						   save_sec_context | SECURITY_RESTRICTED_OPERATION);
+	resetStringInfo(&querybuf);
+	appendStringInfo(&querybuf,
+					 "ALTER TABLE %s ADD COLUMN newdata %s",
+					 diffname, tempname);
+	if (SPI_exec(querybuf.data, 0) != SPI_OK_UTILITY)
+		elog(ERROR, "SPI_exec failed: %s", querybuf.data);
+
+	/* Start building the query for populating the diff table. */
+	resetStringInfo(&querybuf);
+	appendStringInfo(&querybuf,
+					 "INSERT INTO %s "
+					 "SELECT mv.ctid AS tid, mv.gp_segment_id as sid, newdata.* "
 					 "FROM %s mv FULL JOIN %s newdata ON (",
-					 diffname, tempname, matviewname, tempname);
+					 diffname, matviewname, tempname);
 
 	/*
 	 * Get the list of index OIDs for the table from the relcache, and look up
@@ -1327,13 +1350,10 @@ refresh_by_match_merge(Oid matviewOid, Oid tempOid, Oid relowner,
 						   "WHERE newdata.* IS NULL OR mv.* IS NULL "
 						   "ORDER BY tid");
 
-	/* Create the temporary "diff" table. */
-	if (SPI_exec(querybuf.data, 0) != SPI_OK_UTILITY)
+	/* Populate the temporary "diff" table. */
+	if (SPI_exec(querybuf.data, 0) != SPI_OK_INSERT)
 		elog(ERROR, "SPI_exec failed: %s", querybuf.data);
 
-	SetUserIdAndSecContext(relowner,
-						   save_sec_context | SECURITY_RESTRICTED_OPERATION);
-
 	/*
 	 * We have no further use for data from the "full-data" temp table, but we
 	 * must keep it around because its type is referenced from the diff table.


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@cloudberry.apache.org
For additional commands, e-mail: commits-help@cloudberry.apache.org