From patchwork Mon Oct 17 04:18:50 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Hitendra Prajapati X-Patchwork-Id: 13911 X-Patchwork-Delegate: akuster808@gmail.com Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from aws-us-west-2-korg-lkml-1.web.codeaurora.org (localhost.localdomain [127.0.0.1]) by smtp.lore.kernel.org (Postfix) with ESMTP id D5217C4332F for ; Mon, 17 Oct 2022 04:19:00 +0000 (UTC) Received: from mail-pj1-f54.google.com (mail-pj1-f54.google.com [209.85.216.54]) by mx.groups.io with SMTP id smtpd.web11.37226.1665980339410415948 for ; Sun, 16 Oct 2022 21:18:59 -0700 Authentication-Results: mx.groups.io; dkim=pass header.i=@mvista.com header.s=google header.b=bUJK5fq5; spf=pass (domain: mvista.com, ip: 209.85.216.54, mailfrom: hprajapati@mvista.com) Received: by mail-pj1-f54.google.com with SMTP id cl1so9796834pjb.1 for ; Sun, 16 Oct 2022 21:18:59 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=mvista.com; s=google; h=content-transfer-encoding:mime-version:message-id:date:subject:cc :to:from:from:to:cc:subject:date:message-id:reply-to; bh=kgXdkSlS8+zpMdMxnib8jKQffVt1sfGZny6tLE/UHAw=; b=bUJK5fq5RF9kuUwx5dFltUy3EV1p5+Tr8Ldn5BEEqEx/dxy7Tsn7AcKbz1sVDDdx04 nvPQ0l8RzrRTh1XkL/siVA3bMHNgMSXVXZyOl/D3XWT00Qnuq12JbGVWNvqrL8t+ifY/ 2kswaCRhCqC1lDH5hvVSpiny9RYCQc+MU3mWk= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=content-transfer-encoding:mime-version:message-id:date:subject:cc :to:from:x-gm-message-state:from:to:cc:subject:date:message-id :reply-to; bh=kgXdkSlS8+zpMdMxnib8jKQffVt1sfGZny6tLE/UHAw=; b=C7j03rp7HW9TU9cUKebfkKO7SqH7CU474pBMOewNBftb+m3rOdomZ1bVbyN3Xi2DPJ 1UuBxJ/+8wGncXG5TCu6QDq4tJnNuSVEmz02yC8DpNAUvAZHC6yWeXJO6yjuNemh0AX3 pJR9p9Y+VFEztCr62ZBTw7yNCma3K3/PQyYOz9uMynQCJnuV1v9sEqAZASmxlCANoHXv pQC4ze0OWTxIpqVtptdjue4J7dE1fmXf0W6Pczy9CPHpPAKC/cRqXjoMO68dsRQ94jKS IJpNy6vYXoTBb6ZaSqiKhO/s4oayGx55bdwphQN9+Gam3C3oWICxb3J3JHIPi75dxp8e rjtA== X-Gm-Message-State: ACrzQf2lbX9QWtK0r+ANek7yxpKsODO9C/wrpPZ/uHKW8e1TqkB4mA5V t600K6ELaCYuU+hf+JCpYsdnQcE5ZN9biw== X-Google-Smtp-Source: AMsMyM6Qeb6ruHyPYXIbXtGj/XzqGXXoHDcLDO+I0FG2YpwsfnkNa+4r2M1m9G9+F4EmcbTbNE5wrw== X-Received: by 2002:a17:90b:3ec3:b0:20d:9da6:56c1 with SMTP id rm3-20020a17090b3ec300b0020d9da656c1mr11629376pjb.156.1665980337813; Sun, 16 Oct 2022 21:18:57 -0700 (PDT) Received: from MVIN00024 ([43.249.234.167]) by smtp.gmail.com with ESMTPSA id i125-20020a625483000000b00561b53512b0sm5812463pfb.195.2022.10.16.21.18.55 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sun, 16 Oct 2022 21:18:57 -0700 (PDT) Received: by MVIN00024 (sSMTP sendmail emulation); Mon, 17 Oct 2022 09:48:52 +0530 From: Hitendra Prajapati To: openembedded-devel@lists.openembedded.org Cc: Hitendra Prajapati Subject: [meta-oe][dunfell][PATCH] postgresql: Fix CVE-2022-2625 Date: Mon, 17 Oct 2022 09:48:50 +0530 Message-Id: <20221017041850.6122-1-hprajapati@mvista.com> X-Mailer: git-send-email 2.25.1 MIME-Version: 1.0 List-Id: X-Webhook-Received: from li982-79.members.linode.com [45.33.32.79] by aws-us-west-2-korg-lkml-1.web.codeaurora.org with HTTPS for ; Mon, 17 Oct 2022 04:19:00 -0000 X-Groupsio-URL: https://lists.openembedded.org/g/openembedded-devel/message/99187 Upstream-Status: Backport from https://git.postgresql.org/gitweb/?p=postgresql.git;a=commit;h=5579726bd60a6e7afb04a3548bced348cd5ffd89 Description: CVE-2022-2625 postgresql: Extension scripts replace objects not belonging to the extension. Signed-off-by: Hitendra Prajapati --- .../postgresql/files/CVE-2022-2625.patch | 904 ++++++++++++++++++ .../recipes-dbs/postgresql/postgresql_12.9.bb | 1 + 2 files changed, 905 insertions(+) create mode 100644 meta-oe/recipes-dbs/postgresql/files/CVE-2022-2625.patch diff --git a/meta-oe/recipes-dbs/postgresql/files/CVE-2022-2625.patch b/meta-oe/recipes-dbs/postgresql/files/CVE-2022-2625.patch new file mode 100644 index 0000000000..6417d8a2b7 --- /dev/null +++ b/meta-oe/recipes-dbs/postgresql/files/CVE-2022-2625.patch @@ -0,0 +1,904 @@ +From 84375c1db25ef650902cf80712495fc514b0ff63 Mon Sep 17 00:00:00 2001 +From: Hitendra Prajapati +Date: Thu, 13 Oct 2022 10:35:32 +0530 +Subject: [PATCH] CVE-2022-2625 + +Upstream-Status: Backport [https://git.postgresql.org/gitweb/?p=postgresql.git;a=commit;h=5579726bd60a6e7afb04a3548bced348cd5ffd89] +CVE: CVE-2022-2625 +Signed-off-by: Hitendra Prajapati +--- + doc/src/sgml/extend.sgml | 11 -- + src/backend/catalog/pg_collation.c | 49 ++++-- + src/backend/catalog/pg_depend.c | 74 ++++++++- + src/backend/catalog/pg_operator.c | 2 +- + src/backend/catalog/pg_type.c | 7 +- + src/backend/commands/createas.c | 18 ++- + src/backend/commands/foreigncmds.c | 19 ++- + src/backend/commands/schemacmds.c | 25 ++- + src/backend/commands/sequence.c | 8 + + src/backend/commands/statscmds.c | 4 + + src/backend/commands/view.c | 16 +- + src/backend/parser/parse_utilcmd.c | 10 ++ + src/include/catalog/dependency.h | 2 + + src/test/modules/test_extensions/Makefile | 5 +- + .../expected/test_extensions.out | 153 ++++++++++++++++++ + .../test_extensions/sql/test_extensions.sql | 110 +++++++++++++ + .../test_ext_cine--1.0--1.1.sql | 26 +++ + .../test_extensions/test_ext_cine--1.0.sql | 25 +++ + .../test_extensions/test_ext_cine.control | 3 + + .../test_extensions/test_ext_cor--1.0.sql | 20 +++ + .../test_extensions/test_ext_cor.control | 3 + + 21 files changed, 540 insertions(+), 50 deletions(-) + create mode 100644 src/test/modules/test_extensions/test_ext_cine--1.0--1.1.sql + create mode 100644 src/test/modules/test_extensions/test_ext_cine--1.0.sql + create mode 100644 src/test/modules/test_extensions/test_ext_cine.control + create mode 100644 src/test/modules/test_extensions/test_ext_cor--1.0.sql + create mode 100644 src/test/modules/test_extensions/test_ext_cor.control + +diff --git a/doc/src/sgml/extend.sgml b/doc/src/sgml/extend.sgml +index 53f2638..bcc7a80 100644 +--- a/doc/src/sgml/extend.sgml ++++ b/doc/src/sgml/extend.sgml +@@ -1109,17 +1109,6 @@ SELECT * FROM pg_extension_update_paths('extension_namesearch_path. However, no mechanism currently exists + to require that. + +- +- +- Do not use CREATE OR REPLACE +- FUNCTION, except in an update script that must change the +- definition of a function that is known to be an extension member +- already. (Likewise for other OR REPLACE options.) +- Using OR REPLACE unnecessarily not only has a risk +- of accidentally overwriting someone else's function, but it creates a +- security hazard since the overwritten function would still be owned by +- its original owner, who could modify it. +- + + + +diff --git a/src/backend/catalog/pg_collation.c b/src/backend/catalog/pg_collation.c +index dd99d53..ba4c3ef 100644 +--- a/src/backend/catalog/pg_collation.c ++++ b/src/backend/catalog/pg_collation.c +@@ -78,15 +78,25 @@ CollationCreate(const char *collname, Oid collnamespace, + * friendlier error message. The unique index provides a backstop against + * race conditions. + */ +- if (SearchSysCacheExists3(COLLNAMEENCNSP, +- PointerGetDatum(collname), +- Int32GetDatum(collencoding), +- ObjectIdGetDatum(collnamespace))) ++ oid = GetSysCacheOid3(COLLNAMEENCNSP, ++ Anum_pg_collation_oid, ++ PointerGetDatum(collname), ++ Int32GetDatum(collencoding), ++ ObjectIdGetDatum(collnamespace)); ++ if (OidIsValid(oid)) + { + if (quiet) + return InvalidOid; + else if (if_not_exists) + { ++ /* ++ * If we are in an extension script, insist that the pre-existing ++ * object be a member of the extension, to avoid security risks. ++ */ ++ ObjectAddressSet(myself, CollationRelationId, oid); ++ checkMembershipInCurrentExtension(&myself); ++ ++ /* OK to skip */ + ereport(NOTICE, + (errcode(ERRCODE_DUPLICATE_OBJECT), + collencoding == -1 +@@ -116,16 +126,19 @@ CollationCreate(const char *collname, Oid collnamespace, + * so we take a ShareRowExclusiveLock earlier, to protect against + * concurrent changes fooling this check. + */ +- if ((collencoding == -1 && +- SearchSysCacheExists3(COLLNAMEENCNSP, +- PointerGetDatum(collname), +- Int32GetDatum(GetDatabaseEncoding()), +- ObjectIdGetDatum(collnamespace))) || +- (collencoding != -1 && +- SearchSysCacheExists3(COLLNAMEENCNSP, +- PointerGetDatum(collname), +- Int32GetDatum(-1), +- ObjectIdGetDatum(collnamespace)))) ++ if (collencoding == -1) ++ oid = GetSysCacheOid3(COLLNAMEENCNSP, ++ Anum_pg_collation_oid, ++ PointerGetDatum(collname), ++ Int32GetDatum(GetDatabaseEncoding()), ++ ObjectIdGetDatum(collnamespace)); ++ else ++ oid = GetSysCacheOid3(COLLNAMEENCNSP, ++ Anum_pg_collation_oid, ++ PointerGetDatum(collname), ++ Int32GetDatum(-1), ++ ObjectIdGetDatum(collnamespace)); ++ if (OidIsValid(oid)) + { + if (quiet) + { +@@ -134,6 +147,14 @@ CollationCreate(const char *collname, Oid collnamespace, + } + else if (if_not_exists) + { ++ /* ++ * If we are in an extension script, insist that the pre-existing ++ * object be a member of the extension, to avoid security risks. ++ */ ++ ObjectAddressSet(myself, CollationRelationId, oid); ++ checkMembershipInCurrentExtension(&myself); ++ ++ /* OK to skip */ + table_close(rel, NoLock); + ereport(NOTICE, + (errcode(ERRCODE_DUPLICATE_OBJECT), +diff --git a/src/backend/catalog/pg_depend.c b/src/backend/catalog/pg_depend.c +index 9ffadbb..71c7cef 100644 +--- a/src/backend/catalog/pg_depend.c ++++ b/src/backend/catalog/pg_depend.c +@@ -124,15 +124,23 @@ recordMultipleDependencies(const ObjectAddress *depender, + + /* + * If we are executing a CREATE EXTENSION operation, mark the given object +- * as being a member of the extension. Otherwise, do nothing. ++ * as being a member of the extension, or check that it already is one. ++ * Otherwise, do nothing. + * + * This must be called during creation of any user-definable object type + * that could be a member of an extension. + * +- * If isReplace is true, the object already existed (or might have already +- * existed), so we must check for a pre-existing extension membership entry. +- * Passing false is a guarantee that the object is newly created, and so +- * could not already be a member of any extension. ++ * isReplace must be true if the object already existed, and false if it is ++ * newly created. In the former case we insist that it already be a member ++ * of the current extension. In the latter case we can skip checking whether ++ * it is already a member of any extension. ++ * ++ * Note: isReplace = true is typically used when updating a object in ++ * CREATE OR REPLACE and similar commands. We used to allow the target ++ * object to not already be an extension member, instead silently absorbing ++ * it into the current extension. However, this was both error-prone ++ * (extensions might accidentally overwrite free-standing objects) and ++ * a security hazard (since the object would retain its previous ownership). + */ + void + recordDependencyOnCurrentExtension(const ObjectAddress *object, +@@ -150,6 +158,12 @@ recordDependencyOnCurrentExtension(const ObjectAddress *object, + { + Oid oldext; + ++ /* ++ * Side note: these catalog lookups are safe only because the ++ * object is a pre-existing one. In the not-isReplace case, the ++ * caller has most likely not yet done a CommandCounterIncrement ++ * that would make the new object visible. ++ */ + oldext = getExtensionOfObject(object->classId, object->objectId); + if (OidIsValid(oldext)) + { +@@ -163,6 +177,13 @@ recordDependencyOnCurrentExtension(const ObjectAddress *object, + getObjectDescription(object), + get_extension_name(oldext)))); + } ++ /* It's a free-standing object, so reject */ ++ ereport(ERROR, ++ (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE), ++ errmsg("%s is not a member of extension \"%s\"", ++ getObjectDescription(object), ++ get_extension_name(CurrentExtensionObject)), ++ errdetail("An extension is not allowed to replace an object that it does not own."))); + } + + /* OK, record it as a member of CurrentExtensionObject */ +@@ -174,6 +195,49 @@ recordDependencyOnCurrentExtension(const ObjectAddress *object, + } + } + ++/* ++ * If we are executing a CREATE EXTENSION operation, check that the given ++ * object is a member of the extension, and throw an error if it isn't. ++ * Otherwise, do nothing. ++ * ++ * This must be called whenever a CREATE IF NOT EXISTS operation (for an ++ * object type that can be an extension member) has found that an object of ++ * the desired name already exists. It is insecure for an extension to use ++ * IF NOT EXISTS except when the conflicting object is already an extension ++ * member; otherwise a hostile user could substitute an object with arbitrary ++ * properties. ++ */ ++void ++checkMembershipInCurrentExtension(const ObjectAddress *object) ++{ ++ /* ++ * This is actually the same condition tested in ++ * recordDependencyOnCurrentExtension; but we want to issue a ++ * differently-worded error, and anyway it would be pretty confusing to ++ * call recordDependencyOnCurrentExtension in these circumstances. ++ */ ++ ++ /* Only whole objects can be extension members */ ++ Assert(object->objectSubId == 0); ++ ++ if (creating_extension) ++ { ++ Oid oldext; ++ ++ oldext = getExtensionOfObject(object->classId, object->objectId); ++ /* If already a member of this extension, OK */ ++ if (oldext == CurrentExtensionObject) ++ return; ++ /* Else complain */ ++ ereport(ERROR, ++ (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE), ++ errmsg("%s is not a member of extension \"%s\"", ++ getObjectDescription(object), ++ get_extension_name(CurrentExtensionObject)), ++ errdetail("An extension may only use CREATE ... IF NOT EXISTS to skip object creation if the conflicting object is one that it already owns."))); ++ } ++} ++ + /* + * deleteDependencyRecordsFor -- delete all records with given depender + * classId/objectId. Returns the number of records deleted. +diff --git a/src/backend/catalog/pg_operator.c b/src/backend/catalog/pg_operator.c +index bcaa26c..84784e6 100644 +--- a/src/backend/catalog/pg_operator.c ++++ b/src/backend/catalog/pg_operator.c +@@ -867,7 +867,7 @@ makeOperatorDependencies(HeapTuple tuple, bool isUpdate) + oper->oprowner); + + /* Dependency on extension */ +- recordDependencyOnCurrentExtension(&myself, true); ++ recordDependencyOnCurrentExtension(&myself, isUpdate); + + return myself; + } +diff --git a/src/backend/catalog/pg_type.c b/src/backend/catalog/pg_type.c +index 2a51501..3ff017f 100644 +--- a/src/backend/catalog/pg_type.c ++++ b/src/backend/catalog/pg_type.c +@@ -528,10 +528,9 @@ TypeCreate(Oid newTypeOid, + * If rebuild is true, we remove existing dependencies and rebuild them + * from scratch. This is needed for ALTER TYPE, and also when replacing + * a shell type. We don't remove an existing extension dependency, though. +- * (That means an extension can't absorb a shell type created in another +- * extension, nor ALTER a type created by another extension. Also, if it +- * replaces a free-standing shell type or ALTERs a free-standing type, +- * that type will become a member of the extension.) ++ * That means an extension can't absorb a shell type that is free-standing ++ * or belongs to another extension, nor ALTER a type that is free-standing or ++ * belongs to another extension. + */ + void + GenerateTypeDependencies(Oid typeObjectId, +diff --git a/src/backend/commands/createas.c b/src/backend/commands/createas.c +index 4c1d909..a68d945 100644 +--- a/src/backend/commands/createas.c ++++ b/src/backend/commands/createas.c +@@ -243,15 +243,27 @@ ExecCreateTableAs(CreateTableAsStmt *stmt, const char *queryString, + if (stmt->if_not_exists) + { + Oid nspid; ++ Oid oldrelid; + +- nspid = RangeVarGetCreationNamespace(stmt->into->rel); ++ nspid = RangeVarGetCreationNamespace(into->rel); + +- if (get_relname_relid(stmt->into->rel->relname, nspid)) ++ oldrelid = get_relname_relid(into->rel->relname, nspid); ++ if (OidIsValid(oldrelid)) + { ++ /* ++ * The relation exists and IF NOT EXISTS has been specified. ++ * ++ * If we are in an extension script, insist that the pre-existing ++ * object be a member of the extension, to avoid security risks. ++ */ ++ ObjectAddressSet(address, RelationRelationId, oldrelid); ++ checkMembershipInCurrentExtension(&address); ++ ++ /* OK to skip */ + ereport(NOTICE, + (errcode(ERRCODE_DUPLICATE_TABLE), + errmsg("relation \"%s\" already exists, skipping", +- stmt->into->rel->relname))); ++ into->rel->relname))); + return InvalidObjectAddress; + } + } +diff --git a/src/backend/commands/foreigncmds.c b/src/backend/commands/foreigncmds.c +index d7bc6e3..bc583c6 100644 +--- a/src/backend/commands/foreigncmds.c ++++ b/src/backend/commands/foreigncmds.c +@@ -887,13 +887,22 @@ CreateForeignServer(CreateForeignServerStmt *stmt) + ownerId = GetUserId(); + + /* +- * Check that there is no other foreign server by this name. Do nothing if +- * IF NOT EXISTS was enforced. ++ * Check that there is no other foreign server by this name. If there is ++ * one, do nothing if IF NOT EXISTS was specified. + */ +- if (GetForeignServerByName(stmt->servername, true) != NULL) ++ srvId = get_foreign_server_oid(stmt->servername, true); ++ if (OidIsValid(srvId)) + { + if (stmt->if_not_exists) + { ++ /* ++ * If we are in an extension script, insist that the pre-existing ++ * object be a member of the extension, to avoid security risks. ++ */ ++ ObjectAddressSet(myself, ForeignServerRelationId, srvId); ++ checkMembershipInCurrentExtension(&myself); ++ ++ /* OK to skip */ + ereport(NOTICE, + (errcode(ERRCODE_DUPLICATE_OBJECT), + errmsg("server \"%s\" already exists, skipping", +@@ -1182,6 +1191,10 @@ CreateUserMapping(CreateUserMappingStmt *stmt) + { + if (stmt->if_not_exists) + { ++ /* ++ * Since user mappings aren't members of extensions (see comments ++ * below), no need for checkMembershipInCurrentExtension here. ++ */ + ereport(NOTICE, + (errcode(ERRCODE_DUPLICATE_OBJECT), + errmsg("user mapping for \"%s\" already exists for server \"%s\", skipping", +diff --git a/src/backend/commands/schemacmds.c b/src/backend/commands/schemacmds.c +index 6cf94a3..6bc4edc 100644 +--- a/src/backend/commands/schemacmds.c ++++ b/src/backend/commands/schemacmds.c +@@ -113,14 +113,25 @@ CreateSchemaCommand(CreateSchemaStmt *stmt, const char *queryString, + * the permissions checks, but since CREATE TABLE IF NOT EXISTS makes its + * creation-permission check first, we do likewise. + */ +- if (stmt->if_not_exists && +- SearchSysCacheExists1(NAMESPACENAME, PointerGetDatum(schemaName))) ++ if (stmt->if_not_exists) + { +- ereport(NOTICE, +- (errcode(ERRCODE_DUPLICATE_SCHEMA), +- errmsg("schema \"%s\" already exists, skipping", +- schemaName))); +- return InvalidOid; ++ namespaceId = get_namespace_oid(schemaName, true); ++ if (OidIsValid(namespaceId)) ++ { ++ /* ++ * If we are in an extension script, insist that the pre-existing ++ * object be a member of the extension, to avoid security risks. ++ */ ++ ObjectAddressSet(address, NamespaceRelationId, namespaceId); ++ checkMembershipInCurrentExtension(&address); ++ ++ /* OK to skip */ ++ ereport(NOTICE, ++ (errcode(ERRCODE_DUPLICATE_SCHEMA), ++ errmsg("schema \"%s\" already exists, skipping", ++ schemaName))); ++ return InvalidOid; ++ } + } + + /* +diff --git a/src/backend/commands/sequence.c b/src/backend/commands/sequence.c +index 0960b33..0577184 100644 +--- a/src/backend/commands/sequence.c ++++ b/src/backend/commands/sequence.c +@@ -149,6 +149,14 @@ DefineSequence(ParseState *pstate, CreateSeqStmt *seq) + RangeVarGetAndCheckCreationNamespace(seq->sequence, NoLock, &seqoid); + if (OidIsValid(seqoid)) + { ++ /* ++ * If we are in an extension script, insist that the pre-existing ++ * object be a member of the extension, to avoid security risks. ++ */ ++ ObjectAddressSet(address, RelationRelationId, seqoid); ++ checkMembershipInCurrentExtension(&address); ++ ++ /* OK to skip */ + ereport(NOTICE, + (errcode(ERRCODE_DUPLICATE_TABLE), + errmsg("relation \"%s\" already exists, skipping", +diff --git a/src/backend/commands/statscmds.c b/src/backend/commands/statscmds.c +index 5678d31..409cf28 100644 +--- a/src/backend/commands/statscmds.c ++++ b/src/backend/commands/statscmds.c +@@ -173,6 +173,10 @@ CreateStatistics(CreateStatsStmt *stmt) + { + if (stmt->if_not_exists) + { ++ /* ++ * Since stats objects aren't members of extensions (see comments ++ * below), no need for checkMembershipInCurrentExtension here. ++ */ + ereport(NOTICE, + (errcode(ERRCODE_DUPLICATE_OBJECT), + errmsg("statistics object \"%s\" already exists, skipping", +diff --git a/src/backend/commands/view.c b/src/backend/commands/view.c +index 87ed453..dd7cc97 100644 +--- a/src/backend/commands/view.c ++++ b/src/backend/commands/view.c +@@ -205,7 +205,7 @@ DefineVirtualRelation(RangeVar *relation, List *tlist, bool replace, + CommandCounterIncrement(); + + /* +- * Finally update the view options. ++ * Update the view's options. + * + * The new options list replaces the existing options list, even if + * it's empty. +@@ -218,8 +218,22 @@ DefineVirtualRelation(RangeVar *relation, List *tlist, bool replace, + /* EventTriggerAlterTableStart called by ProcessUtilitySlow */ + AlterTableInternal(viewOid, atcmds, true); + ++ /* ++ * There is very little to do here to update the view's dependencies. ++ * Most view-level dependency relationships, such as those on the ++ * owner, schema, and associated composite type, aren't changing. ++ * Because we don't allow changing type or collation of an existing ++ * view column, those dependencies of the existing columns don't ++ * change either, while the AT_AddColumnToView machinery took care of ++ * adding such dependencies for new view columns. The dependencies of ++ * the view's query could have changed arbitrarily, but that was dealt ++ * with inside StoreViewQuery. What remains is only to check that ++ * view replacement is allowed when we're creating an extension. ++ */ + ObjectAddressSet(address, RelationRelationId, viewOid); + ++ recordDependencyOnCurrentExtension(&address, true); ++ + /* + * Seems okay, so return the OID of the pre-existing view. + */ +diff --git a/src/backend/parser/parse_utilcmd.c b/src/backend/parser/parse_utilcmd.c +index 44aa38a..8f4d940 100644 +--- a/src/backend/parser/parse_utilcmd.c ++++ b/src/backend/parser/parse_utilcmd.c +@@ -206,6 +206,16 @@ transformCreateStmt(CreateStmt *stmt, const char *queryString) + */ + if (stmt->if_not_exists && OidIsValid(existing_relid)) + { ++ /* ++ * If we are in an extension script, insist that the pre-existing ++ * object be a member of the extension, to avoid security risks. ++ */ ++ ObjectAddress address; ++ ++ ObjectAddressSet(address, RelationRelationId, existing_relid); ++ checkMembershipInCurrentExtension(&address); ++ ++ /* OK to skip */ + ereport(NOTICE, + (errcode(ERRCODE_DUPLICATE_TABLE), + errmsg("relation \"%s\" already exists, skipping", +diff --git a/src/include/catalog/dependency.h b/src/include/catalog/dependency.h +index 8b1e3aa..27c7509 100644 +--- a/src/include/catalog/dependency.h ++++ b/src/include/catalog/dependency.h +@@ -201,6 +201,8 @@ extern void recordMultipleDependencies(const ObjectAddress *depender, + extern void recordDependencyOnCurrentExtension(const ObjectAddress *object, + bool isReplace); + ++extern void checkMembershipInCurrentExtension(const ObjectAddress *object); ++ + extern long deleteDependencyRecordsFor(Oid classId, Oid objectId, + bool skipExtensionDeps); + +diff --git a/src/test/modules/test_extensions/Makefile b/src/test/modules/test_extensions/Makefile +index d18108e..7428f15 100644 +--- a/src/test/modules/test_extensions/Makefile ++++ b/src/test/modules/test_extensions/Makefile +@@ -4,10 +4,13 @@ MODULE = test_extensions + PGFILEDESC = "test_extensions - regression testing for EXTENSION support" + + EXTENSION = test_ext1 test_ext2 test_ext3 test_ext4 test_ext5 test_ext6 \ +- test_ext7 test_ext8 test_ext_cyclic1 test_ext_cyclic2 ++ test_ext7 test_ext8 test_ext_cine test_ext_cor \ ++ test_ext_cyclic1 test_ext_cyclic2 + DATA = test_ext1--1.0.sql test_ext2--1.0.sql test_ext3--1.0.sql \ + test_ext4--1.0.sql test_ext5--1.0.sql test_ext6--1.0.sql \ + test_ext7--1.0.sql test_ext7--1.0--2.0.sql test_ext8--1.0.sql \ ++ test_ext_cine--1.0.sql test_ext_cine--1.0--1.1.sql \ ++ test_ext_cor--1.0.sql \ + test_ext_cyclic1--1.0.sql test_ext_cyclic2--1.0.sql + + REGRESS = test_extensions test_extdepend +diff --git a/src/test/modules/test_extensions/expected/test_extensions.out b/src/test/modules/test_extensions/expected/test_extensions.out +index b5cbdfc..1e91640 100644 +--- a/src/test/modules/test_extensions/expected/test_extensions.out ++++ b/src/test/modules/test_extensions/expected/test_extensions.out +@@ -154,3 +154,156 @@ DROP TABLE test_ext4_tab; + DROP FUNCTION create_extension_with_temp_schema(); + RESET client_min_messages; + \unset SHOW_CONTEXT ++-- It's generally bad style to use CREATE OR REPLACE unnecessarily. ++-- Test what happens if an extension does it anyway. ++-- Replacing a shell type or operator is sort of like CREATE OR REPLACE; ++-- check that too. ++CREATE FUNCTION ext_cor_func() RETURNS text ++ AS $$ SELECT 'ext_cor_func: original'::text $$ LANGUAGE sql; ++CREATE EXTENSION test_ext_cor; -- fail ++ERROR: function ext_cor_func() is not a member of extension "test_ext_cor" ++DETAIL: An extension is not allowed to replace an object that it does not own. ++SELECT ext_cor_func(); ++ ext_cor_func ++------------------------ ++ ext_cor_func: original ++(1 row) ++ ++DROP FUNCTION ext_cor_func(); ++CREATE VIEW ext_cor_view AS ++ SELECT 'ext_cor_view: original'::text AS col; ++CREATE EXTENSION test_ext_cor; -- fail ++ERROR: view ext_cor_view is not a member of extension "test_ext_cor" ++DETAIL: An extension is not allowed to replace an object that it does not own. ++SELECT ext_cor_func(); ++ERROR: function ext_cor_func() does not exist ++LINE 1: SELECT ext_cor_func(); ++ ^ ++HINT: No function matches the given name and argument types. You might need to add explicit type casts. ++SELECT * FROM ext_cor_view; ++ col ++------------------------ ++ ext_cor_view: original ++(1 row) ++ ++DROP VIEW ext_cor_view; ++CREATE TYPE test_ext_type; ++CREATE EXTENSION test_ext_cor; -- fail ++ERROR: type test_ext_type is not a member of extension "test_ext_cor" ++DETAIL: An extension is not allowed to replace an object that it does not own. ++DROP TYPE test_ext_type; ++-- this makes a shell "point <<@@ polygon" operator too ++CREATE OPERATOR @@>> ( PROCEDURE = poly_contain_pt, ++ LEFTARG = polygon, RIGHTARG = point, ++ COMMUTATOR = <<@@ ); ++CREATE EXTENSION test_ext_cor; -- fail ++ERROR: operator <<@@(point,polygon) is not a member of extension "test_ext_cor" ++DETAIL: An extension is not allowed to replace an object that it does not own. ++DROP OPERATOR <<@@ (point, polygon); ++CREATE EXTENSION test_ext_cor; -- now it should work ++SELECT ext_cor_func(); ++ ext_cor_func ++------------------------------ ++ ext_cor_func: from extension ++(1 row) ++ ++SELECT * FROM ext_cor_view; ++ col ++------------------------------ ++ ext_cor_view: from extension ++(1 row) ++ ++SELECT 'x'::test_ext_type; ++ test_ext_type ++--------------- ++ x ++(1 row) ++ ++SELECT point(0,0) <<@@ polygon(circle(point(0,0),1)); ++ ?column? ++---------- ++ t ++(1 row) ++ ++\dx+ test_ext_cor ++Objects in extension "test_ext_cor" ++ Object description ++------------------------------ ++ function ext_cor_func() ++ operator <<@@(point,polygon) ++ type test_ext_type ++ view ext_cor_view ++(4 rows) ++ ++-- ++-- CREATE IF NOT EXISTS is an entirely unsound thing for an extension ++-- to be doing, but let's at least plug the major security hole in it. ++-- ++CREATE COLLATION ext_cine_coll ++ ( LC_COLLATE = "C", LC_CTYPE = "C" ); ++CREATE EXTENSION test_ext_cine; -- fail ++ERROR: collation ext_cine_coll is not a member of extension "test_ext_cine" ++DETAIL: An extension may only use CREATE ... IF NOT EXISTS to skip object creation if the conflicting object is one that it already owns. ++DROP COLLATION ext_cine_coll; ++CREATE MATERIALIZED VIEW ext_cine_mv AS SELECT 11 AS f1; ++CREATE EXTENSION test_ext_cine; -- fail ++ERROR: materialized view ext_cine_mv is not a member of extension "test_ext_cine" ++DETAIL: An extension may only use CREATE ... IF NOT EXISTS to skip object creation if the conflicting object is one that it already owns. ++DROP MATERIALIZED VIEW ext_cine_mv; ++CREATE FOREIGN DATA WRAPPER dummy; ++CREATE SERVER ext_cine_srv FOREIGN DATA WRAPPER dummy; ++CREATE EXTENSION test_ext_cine; -- fail ++ERROR: server ext_cine_srv is not a member of extension "test_ext_cine" ++DETAIL: An extension may only use CREATE ... IF NOT EXISTS to skip object creation if the conflicting object is one that it already owns. ++DROP SERVER ext_cine_srv; ++CREATE SCHEMA ext_cine_schema; ++CREATE EXTENSION test_ext_cine; -- fail ++ERROR: schema ext_cine_schema is not a member of extension "test_ext_cine" ++DETAIL: An extension may only use CREATE ... IF NOT EXISTS to skip object creation if the conflicting object is one that it already owns. ++DROP SCHEMA ext_cine_schema; ++CREATE SEQUENCE ext_cine_seq; ++CREATE EXTENSION test_ext_cine; -- fail ++ERROR: sequence ext_cine_seq is not a member of extension "test_ext_cine" ++DETAIL: An extension may only use CREATE ... IF NOT EXISTS to skip object creation if the conflicting object is one that it already owns. ++DROP SEQUENCE ext_cine_seq; ++CREATE TABLE ext_cine_tab1 (x int); ++CREATE EXTENSION test_ext_cine; -- fail ++ERROR: table ext_cine_tab1 is not a member of extension "test_ext_cine" ++DETAIL: An extension may only use CREATE ... IF NOT EXISTS to skip object creation if the conflicting object is one that it already owns. ++DROP TABLE ext_cine_tab1; ++CREATE TABLE ext_cine_tab2 AS SELECT 42 AS y; ++CREATE EXTENSION test_ext_cine; -- fail ++ERROR: table ext_cine_tab2 is not a member of extension "test_ext_cine" ++DETAIL: An extension may only use CREATE ... IF NOT EXISTS to skip object creation if the conflicting object is one that it already owns. ++DROP TABLE ext_cine_tab2; ++CREATE EXTENSION test_ext_cine; ++\dx+ test_ext_cine ++Objects in extension "test_ext_cine" ++ Object description ++----------------------------------- ++ collation ext_cine_coll ++ foreign-data wrapper ext_cine_fdw ++ materialized view ext_cine_mv ++ schema ext_cine_schema ++ sequence ext_cine_seq ++ server ext_cine_srv ++ table ext_cine_tab1 ++ table ext_cine_tab2 ++(8 rows) ++ ++ALTER EXTENSION test_ext_cine UPDATE TO '1.1'; ++\dx+ test_ext_cine ++Objects in extension "test_ext_cine" ++ Object description ++----------------------------------- ++ collation ext_cine_coll ++ foreign-data wrapper ext_cine_fdw ++ materialized view ext_cine_mv ++ schema ext_cine_schema ++ sequence ext_cine_seq ++ server ext_cine_srv ++ table ext_cine_tab1 ++ table ext_cine_tab2 ++ table ext_cine_tab3 ++(9 rows) ++ +diff --git a/src/test/modules/test_extensions/sql/test_extensions.sql b/src/test/modules/test_extensions/sql/test_extensions.sql +index f505466..b3d4579 100644 +--- a/src/test/modules/test_extensions/sql/test_extensions.sql ++++ b/src/test/modules/test_extensions/sql/test_extensions.sql +@@ -93,3 +93,113 @@ DROP TABLE test_ext4_tab; + DROP FUNCTION create_extension_with_temp_schema(); + RESET client_min_messages; + \unset SHOW_CONTEXT ++ ++-- It's generally bad style to use CREATE OR REPLACE unnecessarily. ++-- Test what happens if an extension does it anyway. ++-- Replacing a shell type or operator is sort of like CREATE OR REPLACE; ++-- check that too. ++ ++CREATE FUNCTION ext_cor_func() RETURNS text ++ AS $$ SELECT 'ext_cor_func: original'::text $$ LANGUAGE sql; ++ ++CREATE EXTENSION test_ext_cor; -- fail ++ ++SELECT ext_cor_func(); ++ ++DROP FUNCTION ext_cor_func(); ++ ++CREATE VIEW ext_cor_view AS ++ SELECT 'ext_cor_view: original'::text AS col; ++ ++CREATE EXTENSION test_ext_cor; -- fail ++ ++SELECT ext_cor_func(); ++ ++SELECT * FROM ext_cor_view; ++ ++DROP VIEW ext_cor_view; ++ ++CREATE TYPE test_ext_type; ++ ++CREATE EXTENSION test_ext_cor; -- fail ++ ++DROP TYPE test_ext_type; ++ ++-- this makes a shell "point <<@@ polygon" operator too ++CREATE OPERATOR @@>> ( PROCEDURE = poly_contain_pt, ++ LEFTARG = polygon, RIGHTARG = point, ++ COMMUTATOR = <<@@ ); ++ ++CREATE EXTENSION test_ext_cor; -- fail ++ ++DROP OPERATOR <<@@ (point, polygon); ++ ++CREATE EXTENSION test_ext_cor; -- now it should work ++ ++SELECT ext_cor_func(); ++ ++SELECT * FROM ext_cor_view; ++ ++SELECT 'x'::test_ext_type; ++ ++SELECT point(0,0) <<@@ polygon(circle(point(0,0),1)); ++ ++\dx+ test_ext_cor ++ ++-- ++-- CREATE IF NOT EXISTS is an entirely unsound thing for an extension ++-- to be doing, but let's at least plug the major security hole in it. ++-- ++ ++CREATE COLLATION ext_cine_coll ++ ( LC_COLLATE = "C", LC_CTYPE = "C" ); ++ ++CREATE EXTENSION test_ext_cine; -- fail ++ ++DROP COLLATION ext_cine_coll; ++ ++CREATE MATERIALIZED VIEW ext_cine_mv AS SELECT 11 AS f1; ++ ++CREATE EXTENSION test_ext_cine; -- fail ++ ++DROP MATERIALIZED VIEW ext_cine_mv; ++ ++CREATE FOREIGN DATA WRAPPER dummy; ++ ++CREATE SERVER ext_cine_srv FOREIGN DATA WRAPPER dummy; ++ ++CREATE EXTENSION test_ext_cine; -- fail ++ ++DROP SERVER ext_cine_srv; ++ ++CREATE SCHEMA ext_cine_schema; ++ ++CREATE EXTENSION test_ext_cine; -- fail ++ ++DROP SCHEMA ext_cine_schema; ++ ++CREATE SEQUENCE ext_cine_seq; ++ ++CREATE EXTENSION test_ext_cine; -- fail ++ ++DROP SEQUENCE ext_cine_seq; ++ ++CREATE TABLE ext_cine_tab1 (x int); ++ ++CREATE EXTENSION test_ext_cine; -- fail ++ ++DROP TABLE ext_cine_tab1; ++ ++CREATE TABLE ext_cine_tab2 AS SELECT 42 AS y; ++ ++CREATE EXTENSION test_ext_cine; -- fail ++ ++DROP TABLE ext_cine_tab2; ++ ++CREATE EXTENSION test_ext_cine; ++ ++\dx+ test_ext_cine ++ ++ALTER EXTENSION test_ext_cine UPDATE TO '1.1'; ++ ++\dx+ test_ext_cine +diff --git a/src/test/modules/test_extensions/test_ext_cine--1.0--1.1.sql b/src/test/modules/test_extensions/test_ext_cine--1.0--1.1.sql +new file mode 100644 +index 0000000..6dadfd2 +--- /dev/null ++++ b/src/test/modules/test_extensions/test_ext_cine--1.0--1.1.sql +@@ -0,0 +1,26 @@ ++/* src/test/modules/test_extensions/test_ext_cine--1.0--1.1.sql */ ++-- complain if script is sourced in psql, rather than via ALTER EXTENSION ++\echo Use "ALTER EXTENSION test_ext_cine UPDATE TO '1.1'" to load this file. \quit ++ ++-- ++-- These are the same commands as in the 1.0 script; we expect them ++-- to do nothing. ++-- ++ ++CREATE COLLATION IF NOT EXISTS ext_cine_coll ++ ( LC_COLLATE = "POSIX", LC_CTYPE = "POSIX" ); ++ ++CREATE MATERIALIZED VIEW IF NOT EXISTS ext_cine_mv AS SELECT 42 AS f1; ++ ++CREATE SERVER IF NOT EXISTS ext_cine_srv FOREIGN DATA WRAPPER ext_cine_fdw; ++ ++CREATE SCHEMA IF NOT EXISTS ext_cine_schema; ++ ++CREATE SEQUENCE IF NOT EXISTS ext_cine_seq; ++ ++CREATE TABLE IF NOT EXISTS ext_cine_tab1 (x int); ++ ++CREATE TABLE IF NOT EXISTS ext_cine_tab2 AS SELECT 42 AS y; ++ ++-- just to verify the script ran ++CREATE TABLE ext_cine_tab3 (z int); +diff --git a/src/test/modules/test_extensions/test_ext_cine--1.0.sql b/src/test/modules/test_extensions/test_ext_cine--1.0.sql +new file mode 100644 +index 0000000..01408ff +--- /dev/null ++++ b/src/test/modules/test_extensions/test_ext_cine--1.0.sql +@@ -0,0 +1,25 @@ ++/* src/test/modules/test_extensions/test_ext_cine--1.0.sql */ ++-- complain if script is sourced in psql, rather than via CREATE EXTENSION ++\echo Use "CREATE EXTENSION test_ext_cine" to load this file. \quit ++ ++-- ++-- CREATE IF NOT EXISTS is an entirely unsound thing for an extension ++-- to be doing, but let's at least plug the major security hole in it. ++-- ++ ++CREATE COLLATION IF NOT EXISTS ext_cine_coll ++ ( LC_COLLATE = "POSIX", LC_CTYPE = "POSIX" ); ++ ++CREATE MATERIALIZED VIEW IF NOT EXISTS ext_cine_mv AS SELECT 42 AS f1; ++ ++CREATE FOREIGN DATA WRAPPER ext_cine_fdw; ++ ++CREATE SERVER IF NOT EXISTS ext_cine_srv FOREIGN DATA WRAPPER ext_cine_fdw; ++ ++CREATE SCHEMA IF NOT EXISTS ext_cine_schema; ++ ++CREATE SEQUENCE IF NOT EXISTS ext_cine_seq; ++ ++CREATE TABLE IF NOT EXISTS ext_cine_tab1 (x int); ++ ++CREATE TABLE IF NOT EXISTS ext_cine_tab2 AS SELECT 42 AS y; +diff --git a/src/test/modules/test_extensions/test_ext_cine.control b/src/test/modules/test_extensions/test_ext_cine.control +new file mode 100644 +index 0000000..ced713b +--- /dev/null ++++ b/src/test/modules/test_extensions/test_ext_cine.control +@@ -0,0 +1,3 @@ ++comment = 'Test extension using CREATE IF NOT EXISTS' ++default_version = '1.0' ++relocatable = true +diff --git a/src/test/modules/test_extensions/test_ext_cor--1.0.sql b/src/test/modules/test_extensions/test_ext_cor--1.0.sql +new file mode 100644 +index 0000000..2e8d89c +--- /dev/null ++++ b/src/test/modules/test_extensions/test_ext_cor--1.0.sql +@@ -0,0 +1,20 @@ ++/* src/test/modules/test_extensions/test_ext_cor--1.0.sql */ ++-- complain if script is sourced in psql, rather than via CREATE EXTENSION ++\echo Use "CREATE EXTENSION test_ext_cor" to load this file. \quit ++ ++-- It's generally bad style to use CREATE OR REPLACE unnecessarily. ++-- Test what happens if an extension does it anyway. ++ ++CREATE OR REPLACE FUNCTION ext_cor_func() RETURNS text ++ AS $$ SELECT 'ext_cor_func: from extension'::text $$ LANGUAGE sql; ++ ++CREATE OR REPLACE VIEW ext_cor_view AS ++ SELECT 'ext_cor_view: from extension'::text AS col; ++ ++-- These are for testing replacement of a shell type/operator, which works ++-- enough like an implicit OR REPLACE to be important to check. ++ ++CREATE TYPE test_ext_type AS ENUM('x', 'y'); ++ ++CREATE OPERATOR <<@@ ( PROCEDURE = pt_contained_poly, ++ LEFTARG = point, RIGHTARG = polygon ); +diff --git a/src/test/modules/test_extensions/test_ext_cor.control b/src/test/modules/test_extensions/test_ext_cor.control +new file mode 100644 +index 0000000..0e972e5 +--- /dev/null ++++ b/src/test/modules/test_extensions/test_ext_cor.control +@@ -0,0 +1,3 @@ ++comment = 'Test extension using CREATE OR REPLACE' ++default_version = '1.0' ++relocatable = true +-- +2.25.1 + diff --git a/meta-oe/recipes-dbs/postgresql/postgresql_12.9.bb b/meta-oe/recipes-dbs/postgresql/postgresql_12.9.bb index 67bf2b9604..4b7c1d69fc 100644 --- a/meta-oe/recipes-dbs/postgresql/postgresql_12.9.bb +++ b/meta-oe/recipes-dbs/postgresql/postgresql_12.9.bb @@ -7,6 +7,7 @@ SRC_URI += "\ file://0001-Add-support-for-RISC-V.patch \ file://0001-Improve-reproducibility.patch \ file://remove_duplicate.patch \ + file://CVE-2022-2625.patch \ " SRC_URI[sha256sum] = "89fda2de33ed04a98548e43f3ee5f15b882be17505d631fe0dd1a540a2b56dce"