diff mbox series

[meta-oe,kirkstone,1/1] postgresql: Fix CVE-2024-0985

Message ID 20240307113848.847275-1-soumya.sambu@windriver.com
State New
Headers show
Series [meta-oe,kirkstone,1/1] postgresql: Fix CVE-2024-0985 | expand

Commit Message

Sambu, Soumya March 7, 2024, 11:38 a.m. UTC
From: Soumya Sambu <soumya.sambu@windriver.com>

Late privilege drop in REFRESH MATERIALIZED VIEW CONCURRENTLY in PostgreSQL
allows an object creator to execute arbitrary SQL functions as the command
issuer. The command intends to run SQL functions as the owner of the
materialized view, enabling safe refresh of untrusted materialized views.
The victim is a superuser or member of one of the attacker's roles. The
attack requires luring the victim into running REFRESH MATERIALIZED VIEW
CONCURRENTLY on the attacker's materialized view. As part of exploiting
this vulnerability, the attacker creates functions that use CREATE RULE to
convert the internally-built temporary table to a view. Versions before
PostgreSQL 15.6, 14.11, 13.14, and 12.18 are affected. The only known
exploit does not work in PostgreSQL 16 and later. For defense in depth,
PostgreSQL 16.2 adds the protections that older branches are using to fix
their vulnerability.

Upstream commit have wrong CVE mentioned but the correct one is CVE-2024-0985

References:
https://nvd.nist.gov/vuln/detail/CVE-2024-0985
https://security-tracker.debian.org/tracker/CVE-2024-0985

Signed-off-by: Soumya Sambu <soumya.sambu@windriver.com>
---
 .../postgresql/files/CVE-2024-0985.patch      | 98 +++++++++++++++++++
 .../recipes-dbs/postgresql/postgresql_14.9.bb |  1 +
 2 files changed, 99 insertions(+)
 create mode 100644 meta-oe/recipes-dbs/postgresql/files/CVE-2024-0985.patch

Comments

Mittal, Anuj March 11, 2024, 2:48 a.m. UTC | #1
On Thu, 2024-03-07 at 03:39 -0800, Soumya via lists.openembedded.org
wrote:
> From: Soumya Sambu <soumya.sambu@windriver.com>
> 
> Late privilege drop in REFRESH MATERIALIZED VIEW CONCURRENTLY in
> PostgreSQL
> allows an object creator to execute arbitrary SQL functions as the
> command
> issuer. The command intends to run SQL functions as the owner of the
> materialized view, enabling safe refresh of untrusted materialized
> views.
> The victim is a superuser or member of one of the attacker's roles.
> The
> attack requires luring the victim into running REFRESH MATERIALIZED
> VIEW
> CONCURRENTLY on the attacker's materialized view. As part of
> exploiting
> this vulnerability, the attacker creates functions that use CREATE
> RULE to
> convert the internally-built temporary table to a view. Versions
> before
> PostgreSQL 15.6, 14.11, 13.14, and 12.18 are affected. The only known
> exploit does not work in PostgreSQL 16 and later. For defense in
> depth,
> PostgreSQL 16.2 adds the protections that older branches are using to
> fix
> their vulnerability.
> 
> Upstream commit have wrong CVE mentioned but the correct one is CVE-
> 2024-0985
> 
> References:
> https://nvd.nist.gov/vuln/detail/CVE-2024-0985
> https://security-tracker.debian.org/tracker/CVE-2024-0985

I think this should instead be upgraded to 14.11 bug fix release.

Thanks,

Anuj

> 
> Signed-off-by: Soumya Sambu <soumya.sambu@windriver.com>
> ---
>  .../postgresql/files/CVE-2024-0985.patch      | 98
> +++++++++++++++++++
>  .../recipes-dbs/postgresql/postgresql_14.9.bb |  1 +
>  2 files changed, 99 insertions(+)
>  create mode 100644 meta-oe/recipes-dbs/postgresql/files/CVE-2024-
> 0985.patch
> 
> diff --git a/meta-oe/recipes-dbs/postgresql/files/CVE-2024-0985.patch
> b/meta-oe/recipes-dbs/postgresql/files/CVE-2024-0985.patch
> new file mode 100644
> index 000000000..24245406c
> --- /dev/null
> +++ b/meta-oe/recipes-dbs/postgresql/files/CVE-2024-0985.patch
> @@ -0,0 +1,98 @@
> +From f2fdea198b3d0ab30b9e8478a762488ecebabd88 Mon Sep 17 00:00:00
> 2001
> +From: Heikki Linnakangas <heikki.linnakangas@iki.fi>
> +Date: Mon, 5 Feb 2024 11:01:23 +0200
> +Subject: [PATCH] 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-2023-5869
> +Reviewed-by: Noah Misch
> +
> +CVE: CVE-2024-0985
> +
> +Upstream-Status: Backport
> [https://git.postgresql.org/gitweb/?p=postgresql.git;a=patch;h=f2fdea
> 198b3d0ab30b9e8478a762488ecebabd88]
> +
> +Signed-off-by: Soumya Sambu <soumya.sambu@windriver.com>
> +---
> + src/backend/commands/matview.c | 33 ++++++++++++++++++++++++++-----
> --
> + 1 file changed, 26 insertions(+), 7 deletions(-)
> +
> +diff --git a/src/backend/commands/matview.c
> b/src/backend/commands/matview.c
> +index 3fc50e8..0aa0a74 100644
> +--- a/src/backend/commands/matview.c
> ++++ b/src/backend/commands/matview.c
> +@@ -655,13 +655,35 @@ 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);
> ++	resetStringInfo(&querybuf);
> ++	appendStringInfo(&querybuf,
> ++					 "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 creating the diff table. */
> ++	/* Start building the query for populating the diff table.
> */
> +	resetStringInfo(&querybuf);
> +	appendStringInfo(&querybuf,
> +-					 "CREATE TEMP TABLE %s AS "
> ++					 "INSERT INTO %s "
> +					 "SELECT mv.ctid AS tid,
> newdata.*::%s AS newdata "
> +					 "FROM %s mv FULL JOIN %s
> newdata ON (",
> +					 diffname, tempname,
> matviewname, tempname);
> +@@ -790,13 +812,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.
> +--
> +2.40.0
> diff --git a/meta-oe/recipes-dbs/postgresql/postgresql_14.9.bb
> b/meta-oe/recipes-dbs/postgresql/postgresql_14.9.bb
> index a879de20c..d9911fd4a 100644
> --- a/meta-oe/recipes-dbs/postgresql/postgresql_14.9.bb
> +++ b/meta-oe/recipes-dbs/postgresql/postgresql_14.9.bb
> @@ -12,6 +12,7 @@ SRC_URI += "\
>     file://CVE-2023-5868.patch \
>     file://CVE-2023-5869.patch \
>     file://CVE-2023-5870.patch \
> +   file://CVE-2024-0985.patch \
>  "
>  
>  SRC_URI[sha256sum] =
> "b1fe3ba9b1a7f3a9637dd1656dfdad2889016073fd4d35f13b50143cbbb6a8ef"
> 
> -=-=-=-=-=-=-=-=-=-=-=-
> Links: You receive all messages sent to this group.
> View/Reply Online (#109194):
> https://lists.openembedded.org/g/openembedded-devel/message/109194
> Mute This Topic: https://lists.openembedded.org/mt/104785281/3616702
> Group Owner: openembedded-devel+owner@lists.openembedded.org
> Unsubscribe:
> https://lists.openembedded.org/g/openembedded-devel/unsub [
> anuj.mittal@intel.com]
> -=-=-=-=-=-=-=-=-=-=-=-
>
Sambu, Soumya March 13, 2024, 7:01 a.m. UTC | #2
Got it. I will upgrade to 14.11.

Regards,
Soumya
diff mbox series

Patch

diff --git a/meta-oe/recipes-dbs/postgresql/files/CVE-2024-0985.patch b/meta-oe/recipes-dbs/postgresql/files/CVE-2024-0985.patch
new file mode 100644
index 000000000..24245406c
--- /dev/null
+++ b/meta-oe/recipes-dbs/postgresql/files/CVE-2024-0985.patch
@@ -0,0 +1,98 @@ 
+From f2fdea198b3d0ab30b9e8478a762488ecebabd88 Mon Sep 17 00:00:00 2001
+From: Heikki Linnakangas <heikki.linnakangas@iki.fi>
+Date: Mon, 5 Feb 2024 11:01:23 +0200
+Subject: [PATCH] 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-2023-5869
+Reviewed-by: Noah Misch
+
+CVE: CVE-2024-0985
+
+Upstream-Status: Backport [https://git.postgresql.org/gitweb/?p=postgresql.git;a=patch;h=f2fdea198b3d0ab30b9e8478a762488ecebabd88]
+
+Signed-off-by: Soumya Sambu <soumya.sambu@windriver.com>
+---
+ src/backend/commands/matview.c | 33 ++++++++++++++++++++++++++-------
+ 1 file changed, 26 insertions(+), 7 deletions(-)
+
+diff --git a/src/backend/commands/matview.c b/src/backend/commands/matview.c
+index 3fc50e8..0aa0a74 100644
+--- a/src/backend/commands/matview.c
++++ b/src/backend/commands/matview.c
+@@ -655,13 +655,35 @@ 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);
++	resetStringInfo(&querybuf);
++	appendStringInfo(&querybuf,
++					 "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 creating the diff table. */
++	/* Start building the query for populating the diff table. */
+	resetStringInfo(&querybuf);
+	appendStringInfo(&querybuf,
+-					 "CREATE TEMP TABLE %s AS "
++					 "INSERT INTO %s "
+					 "SELECT mv.ctid AS tid, newdata.*::%s AS newdata "
+					 "FROM %s mv FULL JOIN %s newdata ON (",
+					 diffname, tempname, matviewname, tempname);
+@@ -790,13 +812,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.
+--
+2.40.0
diff --git a/meta-oe/recipes-dbs/postgresql/postgresql_14.9.bb b/meta-oe/recipes-dbs/postgresql/postgresql_14.9.bb
index a879de20c..d9911fd4a 100644
--- a/meta-oe/recipes-dbs/postgresql/postgresql_14.9.bb
+++ b/meta-oe/recipes-dbs/postgresql/postgresql_14.9.bb
@@ -12,6 +12,7 @@  SRC_URI += "\
    file://CVE-2023-5868.patch \
    file://CVE-2023-5869.patch \
    file://CVE-2023-5870.patch \
+   file://CVE-2024-0985.patch \
 "
 
 SRC_URI[sha256sum] = "b1fe3ba9b1a7f3a9637dd1656dfdad2889016073fd4d35f13b50143cbbb6a8ef"