diff --git a/CVE-2022-1552-1.patch b/CVE-2022-1552-1.patch new file mode 100644 index 0000000000000000000000000000000000000000..9dbb468c34783e9fe3b76ced4b6e2059ffd4babe --- /dev/null +++ b/CVE-2022-1552-1.patch @@ -0,0 +1,107 @@ +diff -urN postgresql-10.5/src/backend/commands/matview.c postgresql-10.5.new/src/backend/commands/matview.c +--- postgresql-10.5/src/backend/commands/matview.c 2018-08-07 04:05:31.000000000 +0800 ++++ postgresql-10.5.new/src/backend/commands/matview.c 2023-11-06 17:40:08.589735005 +0800 +@@ -164,6 +164,17 @@ + lockmode, false, false, + RangeVarCallbackOwnsTable, NULL); + matviewRel = heap_open(matviewOid, NoLock); ++ relowner = matviewRel->rd_rel->relowner; ++ ++ /* ++ * Switch to the owner's userid, so that any functions are run as that ++ * user. Also lock down security-restricted operations and arrange to ++ * make GUC variable changes local to this command. ++ */ ++ GetUserIdAndSecContext(&save_userid, &save_sec_context); ++ SetUserIdAndSecContext(relowner, ++ save_sec_context | SECURITY_RESTRICTED_OPERATION); ++ save_nestlevel = NewGUCNestLevel(); + + /* Make sure it is a materialized view. */ + if (matviewRel->rd_rel->relkind != RELKIND_MATVIEW) +@@ -268,19 +279,6 @@ + */ + SetMatViewPopulatedState(matviewRel, !stmt->skipData); + +- relowner = matviewRel->rd_rel->relowner; +- +- /* +- * Switch to the owner's userid, so that any functions are run as that +- * user. Also arrange to make GUC variable changes local to this command. +- * Don't lock it down too tight to create a temporary table just yet. We +- * will switch modes when we are about to execute user code. +- */ +- GetUserIdAndSecContext(&save_userid, &save_sec_context); +- SetUserIdAndSecContext(relowner, +- save_sec_context | SECURITY_LOCAL_USERID_CHANGE); +- save_nestlevel = NewGUCNestLevel(); +- + /* Concurrent refresh builds new data in temp tablespace, and does diff. */ + if (concurrent) + { +@@ -303,12 +301,6 @@ + LockRelationOid(OIDNewHeap, AccessExclusiveLock); + dest = CreateTransientRelDestReceiver(OIDNewHeap); + +- /* +- * Now lock down security-restricted operations. +- */ +- SetUserIdAndSecContext(relowner, +- save_sec_context | SECURITY_RESTRICTED_OPERATION); +- + /* Generate the data, if wanted. */ + if (!stmt->skipData) + processed = refresh_matview_datafill(dest, dataQuery, queryString); +diff -urN postgresql-10.5/src/test/regress/expected/privileges.out postgresql-10.5.new/src/test/regress/expected/privileges.out +--- postgresql-10.5/src/test/regress/expected/privileges.out 2023-11-01 16:06:35.140329723 +0800 ++++ postgresql-10.5.new/src/test/regress/expected/privileges.out 2023-11-06 17:42:25.840402235 +0800 +@@ -1178,6 +1178,22 @@ + SQL statement "SELECT unwanted_grant()" + PL/pgSQL function sro_trojan() line 1 at PERFORM + SQL function "mv_action" statement 1 ++-- REFRESH MATERIALIZED VIEW CONCURRENTLY use of eval_const_expressions() ++SET SESSION AUTHORIZATION regress_sro_user; ++CREATE FUNCTION unwanted_grant_nofail(int) RETURNS int ++ IMMUTABLE LANGUAGE plpgsql AS $$ ++BEGIN ++ PERFORM unwanted_grant(); ++ RAISE WARNING 'owned'; ++ RETURN 1; ++EXCEPTION WHEN OTHERS THEN ++ RETURN 2; ++END$$; ++CREATE MATERIALIZED VIEW sro_index_mv AS SELECT 1 AS c; ++CREATE UNIQUE INDEX ON sro_index_mv (c) WHERE unwanted_grant_nofail(1) > 0; ++\c - ++REFRESH MATERIALIZED VIEW CONCURRENTLY sro_index_mv; ++REFRESH MATERIALIZED VIEW sro_index_mv; + DROP OWNED BY regress_sro_user; + DROP ROLE regress_sro_user; + -- Admin options +diff -urN postgresql-10.5/src/test/regress/sql/privileges.sql postgresql-10.5.new/src/test/regress/sql/privileges.sql +--- postgresql-10.5/src/test/regress/sql/privileges.sql 2023-11-01 16:06:35.140329723 +0800 ++++ postgresql-10.5.new/src/test/regress/sql/privileges.sql 2023-11-06 17:43:27.690109224 +0800 +@@ -756,6 +756,23 @@ + REFRESH MATERIALIZED VIEW sro_mv; + BEGIN; SET CONSTRAINTS ALL IMMEDIATE; REFRESH MATERIALIZED VIEW sro_mv; COMMIT; + ++-- REFRESH MATERIALIZED VIEW CONCURRENTLY use of eval_const_expressions() ++SET SESSION AUTHORIZATION regress_sro_user; ++CREATE FUNCTION unwanted_grant_nofail(int) RETURNS int ++ IMMUTABLE LANGUAGE plpgsql AS $$ ++BEGIN ++ PERFORM unwanted_grant(); ++ RAISE WARNING 'owned'; ++ RETURN 1; ++EXCEPTION WHEN OTHERS THEN ++ RETURN 2; ++END$$; ++CREATE MATERIALIZED VIEW sro_index_mv AS SELECT 1 AS c; ++CREATE UNIQUE INDEX ON sro_index_mv (c) WHERE unwanted_grant_nofail(1) > 0; ++\c - ++REFRESH MATERIALIZED VIEW CONCURRENTLY sro_index_mv; ++REFRESH MATERIALIZED VIEW sro_index_mv; ++ + DROP OWNED BY regress_sro_user; + DROP ROLE regress_sro_user; + diff --git a/CVE-2022-1552-2.patch b/CVE-2022-1552-2.patch new file mode 100644 index 0000000000000000000000000000000000000000..c1d34ea12b8af3a1529ac9909bff2065b246b117 --- /dev/null +++ b/CVE-2022-1552-2.patch @@ -0,0 +1,646 @@ +diff -urN postgresql-10.5/contrib/amcheck/expected/check_btree.out postgresql-10.5.new/contrib/amcheck/expected/check_btree.out +--- postgresql-10.5/contrib/amcheck/expected/check_btree.out 2018-08-07 04:05:31.000000000 +0800 ++++ postgresql-10.5.new/contrib/amcheck/expected/check_btree.out 2023-11-06 17:47:57.363488751 +0800 +@@ -85,8 +85,31 @@ + (0 rows) + + COMMIT; ++-- ++-- Check that index expressions and predicates are run as the table's owner ++-- ++TRUNCATE bttest_a; ++INSERT INTO bttest_a SELECT * FROM generate_series(1, 1000); ++ALTER TABLE bttest_a OWNER TO regress_bttest_role; ++-- A dummy index function checking current_user ++CREATE FUNCTION ifun(int8) RETURNS int8 AS $$ ++BEGIN ++ ASSERT current_user = 'regress_bttest_role', ++ format('ifun(%s) called by %s', $1, current_user); ++ RETURN $1; ++END; ++$$ LANGUAGE plpgsql IMMUTABLE; ++CREATE INDEX bttest_a_expr_idx ON bttest_a ((ifun(id) + ifun(0))) ++ WHERE ifun(id + 10) > ifun(10); ++SELECT bt_index_check('bttest_a_expr_idx'); ++ bt_index_check ++---------------- ++ ++(1 row) ++ + -- cleanup + DROP TABLE bttest_a; + DROP TABLE bttest_b; ++DROP FUNCTION ifun(int8); + DROP OWNED BY bttest_role; -- permissions + DROP ROLE bttest_role; +diff -urN postgresql-10.5/contrib/amcheck/sql/check_btree.sql postgresql-10.5.new/contrib/amcheck/sql/check_btree.sql +--- postgresql-10.5/contrib/amcheck/sql/check_btree.sql 2018-08-07 04:05:31.000000000 +0800 ++++ postgresql-10.5.new/contrib/amcheck/sql/check_btree.sql 2023-11-06 17:49:04.723712157 +0800 +@@ -54,8 +54,29 @@ + AND pid = pg_backend_pid(); + COMMIT; + ++-- ++-- Check that index expressions and predicates are run as the table's owner ++-- ++TRUNCATE bttest_a; ++INSERT INTO bttest_a SELECT * FROM generate_series(1, 1000); ++ALTER TABLE bttest_a OWNER TO regress_bttest_role; ++-- A dummy index function checking current_user ++CREATE FUNCTION ifun(int8) RETURNS int8 AS $$ ++BEGIN ++ ASSERT current_user = 'regress_bttest_role', ++ format('ifun(%s) called by %s', $1, current_user); ++ RETURN $1; ++END; ++$$ LANGUAGE plpgsql IMMUTABLE; ++ ++CREATE INDEX bttest_a_expr_idx ON bttest_a ((ifun(id) + ifun(0))) ++ WHERE ifun(id + 10) > ifun(10); ++ ++SELECT bt_index_check('bttest_a_expr_idx'); ++ + -- cleanup + DROP TABLE bttest_a; + DROP TABLE bttest_b; ++DROP FUNCTION ifun(int8); + DROP OWNED BY bttest_role; -- permissions + DROP ROLE bttest_role; +diff -urN postgresql-10.5/contrib/amcheck/verify_nbtree.c postgresql-10.5.new/contrib/amcheck/verify_nbtree.c +--- postgresql-10.5/contrib/amcheck/verify_nbtree.c 2018-08-07 04:05:31.000000000 +0800 ++++ postgresql-10.5.new/contrib/amcheck/verify_nbtree.c 2023-11-06 17:51:56.211038016 +0800 +@@ -161,6 +161,9 @@ + Relation indrel; + Relation heaprel; + LOCKMODE lockmode; ++ Oid save_userid; ++ int save_sec_context; ++ int save_nestlevel; + + if (parentcheck) + lockmode = ShareLock; +@@ -177,9 +180,27 @@ + */ + heapid = IndexGetRelation(indrelid, true); + if (OidIsValid(heapid)) ++ { + heaprel = heap_open(heapid, lockmode); ++ ++ /* ++ * Switch to the table owner's userid, so that any index functions are ++ * run as that user. Also lock down security-restricted operations ++ * and arrange to make GUC variable changes local to this command. ++ */ ++ GetUserIdAndSecContext(&save_userid, &save_sec_context); ++ SetUserIdAndSecContext(heaprel->rd_rel->relowner, ++ save_sec_context | SECURITY_RESTRICTED_OPERATION); ++ save_nestlevel = NewGUCNestLevel(); ++ } + else ++ { + heaprel = NULL; ++ /* Set these just to suppress "uninitialized variable" warnings */ ++ save_userid = InvalidOid; ++ save_sec_context = -1; ++ save_nestlevel = -1; ++ } + + /* + * Open the target index relations separately (like relation_openrv(), but +@@ -206,6 +227,11 @@ + + /* Check index */ + bt_check_every_level(indrel, parentcheck); ++ /* Roll back any GUC changes executed by index functions */ ++ AtEOXact_GUC(false, save_nestlevel); ++ ++ /* Restore userid and security context */ ++ SetUserIdAndSecContext(save_userid, save_sec_context); + + /* + * Release locks early. That's ok here because nothing in the called +diff -urN postgresql-10.5/src/backend/access/brin/brin.c postgresql-10.5.new/src/backend/access/brin/brin.c +--- postgresql-10.5/src/backend/access/brin/brin.c 2018-08-07 04:05:31.000000000 +0800 ++++ postgresql-10.5.new/src/backend/access/brin/brin.c 2023-11-06 17:59:08.451643280 +0800 +@@ -866,6 +866,9 @@ + Oid heapoid; + Relation indexRel; + Relation heapRel; ++ Oid save_userid; ++ int save_sec_context; ++ int save_nestlevel; + double numSummarized = 0; + + if (RecoveryInProgress()) +@@ -892,7 +895,22 @@ + */ + heapoid = IndexGetRelation(indexoid, true); + if (OidIsValid(heapoid)) ++ { + heapRel = heap_open(heapoid, ShareUpdateExclusiveLock); ++ ++ /* ++ * Autovacuum calls us. For its benefit, switch to the table owner's ++ * userid, so that any index functions are run as that user. Also ++ * lock down security-restricted operations and arrange to make GUC ++ * variable changes local to this command. This is harmless, albeit ++ * unnecessary, when called from SQL, because we fail shortly if the ++ * user does not own the index. ++ */ ++ GetUserIdAndSecContext(&save_userid, &save_sec_context); ++ SetUserIdAndSecContext(heapRel->rd_rel->relowner, ++ save_sec_context | SECURITY_RESTRICTED_OPERATION); ++ save_nestlevel = NewGUCNestLevel(); ++ } + else + heapRel = NULL; + +@@ -907,7 +925,7 @@ + RelationGetRelationName(indexRel)))); + + /* User must own the index (comparable to privileges needed for VACUUM) */ +- if (!pg_class_ownercheck(indexoid, GetUserId())) ++ if (heapRel != NULL && !pg_class_ownercheck(indexoid, save_userid)) + aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_CLASS, + RelationGetRelationName(indexRel)); + +@@ -925,6 +943,12 @@ + /* OK, do it */ + brinsummarize(indexRel, heapRel, heapBlk, true, &numSummarized, NULL); + ++ /* Roll back any GUC changes executed by index functions */ ++ AtEOXact_GUC(false, save_nestlevel); ++ ++ /* Restore userid and security context */ ++ SetUserIdAndSecContext(save_userid, save_sec_context); ++ + relation_close(indexRel, ShareUpdateExclusiveLock); + relation_close(heapRel, ShareUpdateExclusiveLock); + +@@ -966,6 +990,9 @@ + * passed indexoid isn't an index then IndexGetRelation() will fail. + * Rather than emitting a not-very-helpful error message, postpone + * complaining, expecting that the is-it-an-index test below will fail. ++ * ++ * Unlike brin_summarize_range(), autovacuum never calls this. Hence, we ++ * don't switch userid. + */ + heapoid = IndexGetRelation(indexoid, true); + if (OidIsValid(heapoid)) +diff -urN postgresql-10.5/src/backend/catalog/index.c postgresql-10.5.new/src/backend/catalog/index.c +--- postgresql-10.5/src/backend/catalog/index.c 2018-08-07 04:05:31.000000000 +0800 ++++ postgresql-10.5.new/src/backend/catalog/index.c 2023-11-06 19:20:25.415733531 +0800 +@@ -2821,7 +2821,17 @@ + + /* Open and lock the parent heap relation */ + heapRelation = heap_open(heapId, ShareUpdateExclusiveLock); +- /* And the target index relation */ ++ ++ /* ++ * Switch to the table owner's userid, so that any index functions are run ++ * as that user. Also lock down security-restricted operations and ++ * arrange to make GUC variable changes local to this command. ++ */ ++ GetUserIdAndSecContext(&save_userid, &save_sec_context); ++ SetUserIdAndSecContext(heapRelation->rd_rel->relowner, ++ save_sec_context | SECURITY_RESTRICTED_OPERATION); ++ save_nestlevel = NewGUCNestLevel(); ++ + indexRelation = index_open(indexId, RowExclusiveLock); + + /* +@@ -2835,16 +2845,6 @@ + indexInfo->ii_Concurrent = true; + + /* +- * Switch to the table owner's userid, so that any index functions are run +- * as that user. Also lock down security-restricted operations and +- * arrange to make GUC variable changes local to this command. +- */ +- GetUserIdAndSecContext(&save_userid, &save_sec_context); +- SetUserIdAndSecContext(heapRelation->rd_rel->relowner, +- save_sec_context | SECURITY_RESTRICTED_OPERATION); +- save_nestlevel = NewGUCNestLevel(); +- +- /* + * Scan the index and gather up all the TIDs into a tuplesort object. + */ + ivinfo.index = indexRelation; +@@ -3317,6 +3317,9 @@ + Relation iRel, + heapRelation; + Oid heapId; ++ Oid save_userid; ++ int save_sec_context; ++ int save_nestlevel; + IndexInfo *indexInfo; + volatile bool skipped_constraint = false; + PGRUsage ru0; +@@ -3331,6 +3334,16 @@ + heapRelation = heap_open(heapId, ShareLock); + + /* ++ * Switch to the table owner's userid, so that any index functions are run ++ * as that user. Also lock down security-restricted operations and ++ * arrange to make GUC variable changes local to this command. ++ */ ++ GetUserIdAndSecContext(&save_userid, &save_sec_context); ++ SetUserIdAndSecContext(heapRelation->rd_rel->relowner, ++ save_sec_context | SECURITY_RESTRICTED_OPERATION); ++ save_nestlevel = NewGUCNestLevel(); ++ ++ /* + * Open the target index relation and get an exclusive lock on it, to + * ensure that no one else is touching this particular index. + */ +@@ -3479,6 +3492,12 @@ + errdetail_internal("%s", + pg_rusage_show(&ru0)))); + ++ /* Roll back any GUC changes executed by index functions */ ++ AtEOXact_GUC(false, save_nestlevel); ++ ++ /* Restore userid and security context */ ++ SetUserIdAndSecContext(save_userid, save_sec_context); ++ + /* Close rels, but keep locks */ + index_close(iRel, NoLock); + heap_close(heapRelation, NoLock); +diff -urN postgresql-10.5/src/backend/commands/cluster.c postgresql-10.5.new/src/backend/commands/cluster.c +--- postgresql-10.5/src/backend/commands/cluster.c 2018-08-07 04:05:31.000000000 +0800 ++++ postgresql-10.5.new/src/backend/commands/cluster.c 2023-11-06 19:21:59.817177607 +0800 +@@ -260,6 +260,9 @@ + cluster_rel(Oid tableOid, Oid indexOid, bool recheck, bool verbose) + { + Relation OldHeap; ++ Oid save_userid; ++ int save_sec_context; ++ int save_nestlevel; + + /* Check for user-requested abort. */ + CHECK_FOR_INTERRUPTS(); +@@ -277,6 +280,16 @@ + return; + + /* ++ * Switch to the table owner's userid, so that any index functions are run ++ * as that user. Also lock down security-restricted operations and ++ * arrange to make GUC variable changes local to this command. ++ */ ++ GetUserIdAndSecContext(&save_userid, &save_sec_context); ++ SetUserIdAndSecContext(OldHeap->rd_rel->relowner, ++ save_sec_context | SECURITY_RESTRICTED_OPERATION); ++ save_nestlevel = NewGUCNestLevel(); ++ ++ /* + * Since we may open a new transaction for each relation, we have to check + * that the relation still is what we think it is. + * +@@ -290,10 +303,10 @@ + Form_pg_index indexForm; + + /* Check that the user still owns the relation */ +- if (!pg_class_ownercheck(tableOid, GetUserId())) ++ if (!pg_class_ownercheck(tableOid, save_userid)) + { + relation_close(OldHeap, AccessExclusiveLock); +- return; ++ goto out; + } + + /* +@@ -307,7 +320,7 @@ + if (RELATION_IS_OTHER_TEMP(OldHeap)) + { + relation_close(OldHeap, AccessExclusiveLock); +- return; ++ goto out; + } + + if (OidIsValid(indexOid)) +@@ -318,7 +331,7 @@ + if (!SearchSysCacheExists1(RELOID, ObjectIdGetDatum(indexOid))) + { + relation_close(OldHeap, AccessExclusiveLock); +- return; ++ goto out; + } + + /* +@@ -328,14 +341,14 @@ + if (!HeapTupleIsValid(tuple)) /* probably can't happen */ + { + relation_close(OldHeap, AccessExclusiveLock); +- return; ++ goto out; + } + indexForm = (Form_pg_index) GETSTRUCT(tuple); + if (!indexForm->indisclustered) + { + ReleaseSysCache(tuple); + relation_close(OldHeap, AccessExclusiveLock); +- return; ++ goto out; + } + ReleaseSysCache(tuple); + } +@@ -389,7 +402,7 @@ + !RelationIsPopulated(OldHeap)) + { + relation_close(OldHeap, AccessExclusiveLock); +- return; ++ goto out; + } + + /* +@@ -404,6 +417,13 @@ + rebuild_relation(OldHeap, indexOid, verbose); + + /* NB: rebuild_relation does heap_close() on OldHeap */ ++ ++out: ++ /* Roll back any GUC changes executed by index functions */ ++ AtEOXact_GUC(false, save_nestlevel); ++ ++ /* Restore userid and security context */ ++ SetUserIdAndSecContext(save_userid, save_sec_context); + } + + /* +diff -urN postgresql-10.5/src/backend/commands/indexcmds.c postgresql-10.5.new/src/backend/commands/indexcmds.c +--- postgresql-10.5/src/backend/commands/indexcmds.c 2018-08-07 04:05:31.000000000 +0800 ++++ postgresql-10.5.new/src/backend/commands/indexcmds.c 2023-11-06 19:40:13.556405440 +0800 +@@ -342,8 +342,14 @@ + LOCKTAG heaplocktag; + LOCKMODE lockmode; + Snapshot snapshot; ++ Oid root_save_userid; ++ int root_save_sec_context; ++ int root_save_nestlevel; + int i; + ++ root_save_nestlevel = NewGUCNestLevel(); ++ ++ + /* + * count attributes in index + */ +@@ -372,6 +378,15 @@ + lockmode = stmt->concurrent ? ShareUpdateExclusiveLock : ShareLock; + rel = heap_open(relationId, lockmode); + ++ /* ++ * Switch to the table owner's userid, so that any index functions are run ++ * as that user. Also lock down security-restricted operations. We ++ * already arranged to make GUC variable changes local to this command. ++ */ ++ GetUserIdAndSecContext(&root_save_userid, &root_save_sec_context); ++ SetUserIdAndSecContext(rel->rd_rel->relowner, ++ root_save_sec_context | SECURITY_RESTRICTED_OPERATION); ++ + relationId = RelationGetRelid(rel); + namespaceId = RelationGetNamespace(rel); + +@@ -427,7 +442,7 @@ + { + AclResult aclresult; + +- aclresult = pg_namespace_aclcheck(namespaceId, GetUserId(), ++ aclresult = pg_namespace_aclcheck(namespaceId, root_save_userid, + ACL_CREATE); + if (aclresult != ACLCHECK_OK) + aclcheck_error(aclresult, ACL_KIND_NAMESPACE, +@@ -454,7 +469,7 @@ + { + AclResult aclresult; + +- aclresult = pg_tablespace_aclcheck(tablespaceId, GetUserId(), ++ aclresult = pg_tablespace_aclcheck(tablespaceId, root_save_userid, + ACL_CREATE); + if (aclresult != ACLCHECK_OK) + aclcheck_error(aclresult, ACL_KIND_TABLESPACE, +@@ -681,15 +696,31 @@ + + if (!OidIsValid(indexRelationId)) + { ++ /* Roll back any GUC changes executed by index functions. */ ++ AtEOXact_GUC(false, root_save_nestlevel); ++ ++ /* Restore userid and security context */ ++ SetUserIdAndSecContext(root_save_userid, root_save_sec_context); ++ + heap_close(rel, NoLock); + return address; + } + ++ /* ++ * Roll back any GUC changes executed by index functions, and keep ++ * subsequent changes local to this command. This is essential if some ++ * index function changed a behavior-affecting GUC, e.g. search_path. ++ */ ++ AtEOXact_GUC(false, root_save_nestlevel); ++ root_save_nestlevel = NewGUCNestLevel(); ++ + /* Add any requested comment */ + if (stmt->idxcomment != NULL) + CreateComments(indexRelationId, RelationRelationId, 0, + stmt->idxcomment); + ++ AtEOXact_GUC(false, root_save_nestlevel); ++ SetUserIdAndSecContext(root_save_userid, root_save_sec_context); + if (!stmt->concurrent) + { + /* Close the heap and we're done, in the non-concurrent case */ +@@ -768,6 +799,16 @@ + /* Open and lock the parent heap relation */ + rel = heap_openrv(stmt->relation, ShareUpdateExclusiveLock); + ++ /* ++ * Switch to the table owner's userid, so that any index functions are run ++ * as that user. Also lock down security-restricted operations and ++ * arrange to make GUC variable changes local to this command. ++ */ ++ GetUserIdAndSecContext(&root_save_userid, &root_save_sec_context); ++ SetUserIdAndSecContext(rel->rd_rel->relowner, ++ root_save_sec_context | SECURITY_RESTRICTED_OPERATION); ++ root_save_nestlevel = NewGUCNestLevel(); ++ + /* And the target index relation */ + indexRelation = index_open(indexRelationId, RowExclusiveLock); + +@@ -783,6 +824,12 @@ + /* Now build the index */ + index_build(rel, indexRelation, indexInfo, stmt->primary, false); + ++ /* Roll back any GUC changes executed by index functions */ ++ AtEOXact_GUC(false, root_save_nestlevel); ++ ++ /* Restore userid and security context */ ++ SetUserIdAndSecContext(root_save_userid, root_save_sec_context); ++ + /* Close both the relations, but keep the locks */ + heap_close(rel, NoLock); + index_close(indexRelation, NoLock); +diff -urN postgresql-10.5/src/backend/utils/init/miscinit.c postgresql-10.5.new/src/backend/utils/init/miscinit.c +--- postgresql-10.5/src/backend/utils/init/miscinit.c 2018-08-07 04:05:31.000000000 +0800 ++++ postgresql-10.5.new/src/backend/utils/init/miscinit.c 2023-11-06 19:47:03.468076209 +0800 +@@ -359,15 +359,21 @@ + * with guc.c's internal state, so SET ROLE has to be disallowed. + * + * SECURITY_RESTRICTED_OPERATION indicates that we are inside an operation +- * that does not wish to trust called user-defined functions at all. This +- * bit prevents not only SET ROLE, but various other changes of session state +- * that normally is unprotected but might possibly be used to subvert the +- * calling session later. An example is replacing an existing prepared +- * statement with new code, which will then be executed with the outer +- * session's permissions when the prepared statement is next used. Since +- * these restrictions are fairly draconian, we apply them only in contexts +- * where the called functions are really supposed to be side-effect-free +- * anyway, such as VACUUM/ANALYZE/REINDEX. ++ * that does not wish to trust called user-defined functions at all. The ++ * policy is to use this before operations, e.g. autovacuum and REINDEX, that ++ * enumerate relations of a database or schema and run functions associated ++ * with each found relation. The relation owner is the new user ID. Set this ++ * as soon as possible after locking the relation. Restore the old user ID as ++ * late as possible before closing the relation; restoring it shortly after ++ * close is also tolerable. If a command has both relation-enumerating and ++ * non-enumerating modes, e.g. ANALYZE, both modes set this bit. This bit ++ * prevents not only SET ROLE, but various other changes of session state that ++ * normally is unprotected but might possibly be used to subvert the calling ++ * session later. An example is replacing an existing prepared statement with ++ * new code, which will then be executed with the outer session's permissions ++ * when the prepared statement is next used. These restrictions are fairly ++ * draconian, but the functions called in relation-enumerating operations are ++ * really supposed to be side-effect-free anyway. + * + * SECURITY_NOFORCE_RLS indicates that we are inside an operation which should + * ignore the FORCE ROW LEVEL SECURITY per-table indication. This is used to +diff -urN postgresql-10.5/src/test/regress/expected/privileges.out postgresql-10.5.new/src/test/regress/expected/privileges.out +--- postgresql-10.5/src/test/regress/expected/privileges.out 2023-11-06 17:45:31.353238604 +0800 ++++ postgresql-10.5.new/src/test/regress/expected/privileges.out 2023-11-06 19:49:33.432379562 +0800 +@@ -1141,6 +1141,69 @@ + -- security-restricted operations + \c - + CREATE ROLE regress_sro_user; ++-- Check that index expressions and predicates are run as the table's owner ++-- A dummy index function checking current_user ++CREATE FUNCTION sro_ifun(int) RETURNS int AS $$ ++BEGIN ++ -- Below we set the table's owner to regress_sro_user ++ ASSERT current_user = 'regress_sro_user', ++ format('sro_ifun(%s) called by %s', $1, current_user); ++ RETURN $1; ++END; ++$$ LANGUAGE plpgsql IMMUTABLE; ++-- Create a table owned by regress_sro_user ++CREATE TABLE sro_tab (a int); ++ALTER TABLE sro_tab OWNER TO regress_sro_user; ++INSERT INTO sro_tab VALUES (1), (2), (3); ++-- Create an expression index with a predicate ++CREATE INDEX sro_idx ON sro_tab ((sro_ifun(a) + sro_ifun(0))) ++ WHERE sro_ifun(a + 10) > sro_ifun(10); ++DROP INDEX sro_idx; ++-- Do the same concurrently ++CREATE INDEX CONCURRENTLY sro_idx ON sro_tab ((sro_ifun(a) + sro_ifun(0))) ++ WHERE sro_ifun(a + 10) > sro_ifun(10); ++-- REINDEX ++REINDEX TABLE sro_tab; ++REINDEX INDEX sro_idx; ++REINDEX TABLE CONCURRENTLY sro_tab; -- v12+ feature ++ERROR: syntax error at or near "CONCURRENTLY" ++LINE 1: REINDEX TABLE CONCURRENTLY sro_tab; ++ ^ ++DROP INDEX sro_idx; ++-- CLUSTER ++CREATE INDEX sro_cluster_idx ON sro_tab ((sro_ifun(a) + sro_ifun(0))); ++CLUSTER sro_tab USING sro_cluster_idx; ++DROP INDEX sro_cluster_idx; ++-- BRIN index ++CREATE INDEX sro_brin ON sro_tab USING brin ((sro_ifun(a) + sro_ifun(0))); ++SELECT brin_desummarize_range('sro_brin', 0); ++ brin_desummarize_range ++------------------------ ++ ++(1 row) ++ ++SELECT brin_summarize_range('sro_brin', 0); ++ brin_summarize_range ++---------------------- ++ 1 ++(1 row) ++ ++DROP TABLE sro_tab; ++-- Check with a partitioned table ++CREATE TABLE sro_ptab (a int) PARTITION BY RANGE (a); ++ALTER TABLE sro_ptab OWNER TO regress_sro_user; ++CREATE TABLE sro_part PARTITION OF sro_ptab FOR VALUES FROM (1) TO (10); ++ALTER TABLE sro_part OWNER TO regress_sro_user; ++INSERT INTO sro_ptab VALUES (1), (2), (3); ++CREATE INDEX sro_pidx ON sro_ptab ((sro_ifun(a) + sro_ifun(0))) ++ WHERE sro_ifun(a + 10) > sro_ifun(10); ++ERROR: cannot create index on partitioned table "sro_ptab" ++REINDEX TABLE sro_ptab; ++NOTICE: table "sro_ptab" has no indexes ++REINDEX INDEX CONCURRENTLY sro_pidx; -- v12+ feature ++ERROR: syntax error at or near "CONCURRENTLY" ++LINE 1: REINDEX INDEX CONCURRENTLY sro_pidx; ++ ^ + SET SESSION AUTHORIZATION regress_sro_user; + CREATE FUNCTION unwanted_grant() RETURNS void LANGUAGE sql AS + 'GRANT regress_group2 TO regress_sro_user'; +diff -urN postgresql-10.5/src/test/regress/sql/privileges.sql postgresql-10.5.new/src/test/regress/sql/privileges.sql +--- postgresql-10.5/src/test/regress/sql/privileges.sql 2023-11-06 17:45:31.353238604 +0800 ++++ postgresql-10.5.new/src/test/regress/sql/privileges.sql 2023-11-06 19:51:19.200617640 +0800 +@@ -730,6 +730,52 @@ + \c - + CREATE ROLE regress_sro_user; + ++-- Check that index expressions and predicates are run as the table's owner ++ ++-- A dummy index function checking current_user ++CREATE FUNCTION sro_ifun(int) RETURNS int AS $$ ++BEGIN ++ -- Below we set the table's owner to regress_sro_user ++ ASSERT current_user = 'regress_sro_user', ++ format('sro_ifun(%s) called by %s', $1, current_user); ++ RETURN $1; ++END; ++$$ LANGUAGE plpgsql IMMUTABLE; ++-- Create a table owned by regress_sro_user ++CREATE TABLE sro_tab (a int); ++ALTER TABLE sro_tab OWNER TO regress_sro_user; ++INSERT INTO sro_tab VALUES (1), (2), (3); ++-- Create an expression index with a predicate ++CREATE INDEX sro_idx ON sro_tab ((sro_ifun(a) + sro_ifun(0))) ++ WHERE sro_ifun(a + 10) > sro_ifun(10); ++DROP INDEX sro_idx; ++-- Do the same concurrently ++CREATE INDEX CONCURRENTLY sro_idx ON sro_tab ((sro_ifun(a) + sro_ifun(0))) ++ WHERE sro_ifun(a + 10) > sro_ifun(10); ++-- REINDEX ++REINDEX TABLE sro_tab; ++REINDEX INDEX sro_idx; ++REINDEX TABLE CONCURRENTLY sro_tab; -- v12+ feature ++DROP INDEX sro_idx; ++-- CLUSTER ++CREATE INDEX sro_cluster_idx ON sro_tab ((sro_ifun(a) + sro_ifun(0))); ++CLUSTER sro_tab USING sro_cluster_idx; ++DROP INDEX sro_cluster_idx; ++-- BRIN index ++CREATE INDEX sro_brin ON sro_tab USING brin ((sro_ifun(a) + sro_ifun(0))); ++SELECT brin_desummarize_range('sro_brin', 0); ++SELECT brin_summarize_range('sro_brin', 0); ++DROP TABLE sro_tab; ++-- Check with a partitioned table ++CREATE TABLE sro_ptab (a int) PARTITION BY RANGE (a); ++ALTER TABLE sro_ptab OWNER TO regress_sro_user; ++CREATE TABLE sro_part PARTITION OF sro_ptab FOR VALUES FROM (1) TO (10); ++ALTER TABLE sro_part OWNER TO regress_sro_user; ++INSERT INTO sro_ptab VALUES (1), (2), (3); ++CREATE INDEX sro_pidx ON sro_ptab ((sro_ifun(a) + sro_ifun(0))) ++ WHERE sro_ifun(a + 10) > sro_ifun(10); ++REINDEX TABLE sro_ptab; ++ + SET SESSION AUTHORIZATION regress_sro_user; + CREATE FUNCTION unwanted_grant() RETURNS void LANGUAGE sql AS + 'GRANT regress_group2 TO regress_sro_user'; diff --git a/CVE-2022-1552-3.patch b/CVE-2022-1552-3.patch new file mode 100644 index 0000000000000000000000000000000000000000..e5fc1dd9fd844e6cd68f5fe47407b182249beb05 --- /dev/null +++ b/CVE-2022-1552-3.patch @@ -0,0 +1,84 @@ +diff -urN postgresql-10.5/contrib/amcheck/expected/check_btree.out postgresql-10.5.new/contrib/amcheck/expected/check_btree.out +--- postgresql-10.5/contrib/amcheck/expected/check_btree.out 2023-11-07 17:41:58.195114132 +0800 ++++ postgresql-10.5.new/contrib/amcheck/expected/check_btree.out 2023-11-06 20:48:51.398344591 +0800 +@@ -5,9 +5,9 @@ + INSERT INTO bttest_b SELECT * FROM generate_series(100000, 1, -1); + CREATE INDEX bttest_a_idx ON bttest_a USING btree (id); + CREATE INDEX bttest_b_idx ON bttest_b USING btree (id); +-CREATE ROLE bttest_role; ++CREATE ROLE regress_bttest_role; + -- verify permissions are checked (error due to function not callable) +-SET ROLE bttest_role; ++SET ROLE regress_bttest_role; + SELECT bt_index_check('bttest_a_idx'::regclass); + ERROR: permission denied for function bt_index_check + SELECT bt_index_parent_check('bttest_a_idx'::regclass); +@@ -16,9 +16,9 @@ + -- we, intentionally, don't check relation permissions - it's useful + -- to run this cluster-wide with a restricted account, and as tested + -- above explicit permission has to be granted for that. +-GRANT EXECUTE ON FUNCTION bt_index_check(regclass) TO bttest_role; +-GRANT EXECUTE ON FUNCTION bt_index_parent_check(regclass) TO bttest_role; +-SET ROLE bttest_role; ++GRANT EXECUTE ON FUNCTION bt_index_check(regclass) TO regress_bttest_role; ++GRANT EXECUTE ON FUNCTION bt_index_parent_check(regclass) TO regress_bttest_role; ++SET ROLE regress_bttest_role; + SELECT bt_index_check('bttest_a_idx'); + bt_index_check + ---------------- +@@ -111,5 +111,5 @@ + DROP TABLE bttest_a; + DROP TABLE bttest_b; + DROP FUNCTION ifun(int8); +-DROP OWNED BY bttest_role; -- permissions +-DROP ROLE bttest_role; ++DROP OWNED BY regress_bttest_role; -- permissions ++DROP ROLE regress_bttest_role; +diff -urN postgresql-10.5/contrib/amcheck/sql/check_btree.sql postgresql-10.5.new/contrib/amcheck/sql/check_btree.sql +--- postgresql-10.5/contrib/amcheck/sql/check_btree.sql 2023-11-07 17:41:58.195114132 +0800 ++++ postgresql-10.5.new/contrib/amcheck/sql/check_btree.sql 2023-11-07 15:14:59.932838014 +0800 +@@ -8,10 +8,10 @@ + CREATE INDEX bttest_a_idx ON bttest_a USING btree (id); + CREATE INDEX bttest_b_idx ON bttest_b USING btree (id); + +-CREATE ROLE bttest_role; ++CREATE ROLE regress_bttest_role; + + -- verify permissions are checked (error due to function not callable) +-SET ROLE bttest_role; ++SET ROLE regress_bttest_role; + SELECT bt_index_check('bttest_a_idx'::regclass); + SELECT bt_index_parent_check('bttest_a_idx'::regclass); + RESET ROLE; +@@ -19,9 +19,9 @@ + -- we, intentionally, don't check relation permissions - it's useful + -- to run this cluster-wide with a restricted account, and as tested + -- above explicit permission has to be granted for that. +-GRANT EXECUTE ON FUNCTION bt_index_check(regclass) TO bttest_role; +-GRANT EXECUTE ON FUNCTION bt_index_parent_check(regclass) TO bttest_role; +-SET ROLE bttest_role; ++GRANT EXECUTE ON FUNCTION bt_index_check(regclass) TO regress_bttest_role; ++GRANT EXECUTE ON FUNCTION bt_index_parent_check(regclass) TO regress_bttest_role; ++SET ROLE regress_bttest_role; + SELECT bt_index_check('bttest_a_idx'); + SELECT bt_index_parent_check('bttest_a_idx'); + RESET ROLE; +@@ -78,5 +78,5 @@ + DROP TABLE bttest_a; + DROP TABLE bttest_b; + DROP FUNCTION ifun(int8); +-DROP OWNED BY bttest_role; -- permissions +-DROP ROLE bttest_role; ++DROP OWNED BY regress_bttest_role; -- permissions ++DROP ROLE regress_bttest_role; +diff -urN postgresql-10.5/src/test/regress/sql/privileges.sql postgresql-10.5.new/src/test/regress/sql/privileges.sql +--- postgresql-10.5/src/test/regress/sql/privileges.sql 2023-11-07 17:41:58.195114132 +0800 ++++ postgresql-10.5.new/src/test/regress/sql/privileges.sql 2023-11-07 17:12:16.457776767 +0800 +@@ -775,6 +775,7 @@ + CREATE INDEX sro_pidx ON sro_ptab ((sro_ifun(a) + sro_ifun(0))) + WHERE sro_ifun(a + 10) > sro_ifun(10); + REINDEX TABLE sro_ptab; ++REINDEX INDEX CONCURRENTLY sro_pidx; -- v12+ feature + + SET SESSION AUTHORIZATION regress_sro_user; + CREATE FUNCTION unwanted_grant() RETURNS void LANGUAGE sql AS diff --git a/CVE-2022-2625-1.patch b/CVE-2022-2625-1.patch new file mode 100644 index 0000000000000000000000000000000000000000..5f556de9c19052331fc21288de00d75f17b89910 --- /dev/null +++ b/CVE-2022-2625-1.patch @@ -0,0 +1,13 @@ +diff -urN postgresql-10.5/src/test/modules/test_extensions/Makefile postgresql-10.5.new/src/test/modules/test_extensions/Makefile +--- postgresql-10.5/src/test/modules/test_extensions/Makefile 2018-08-07 04:05:31.000000000 +0800 ++++ postgresql-10.5.new/src/test/modules/test_extensions/Makefile 2023-11-06 20:05:02.509706885 +0800 +@@ -12,6 +12,9 @@ + + REGRESS = test_extensions test_extdepend + ++# force C locale for output stability ++NO_LOCALE = 1 ++ + ifdef USE_PGXS + PG_CONFIG = pg_config + PGXS := $(shell $(PG_CONFIG) --pgxs) diff --git a/CVE-2022-2625-2.patch b/CVE-2022-2625-2.patch new file mode 100644 index 0000000000000000000000000000000000000000..60d00f707a3c3ef14424b8a5f394cd2b4fceeb74 --- /dev/null +++ b/CVE-2022-2625-2.patch @@ -0,0 +1,753 @@ +diff -urN postgresql-10.5/src/backend/catalog/pg_collation.c postgresql-10.5.new/src/backend/catalog/pg_collation.c +--- postgresql-10.5/src/backend/catalog/pg_collation.c 2018-08-07 04:05:31.000000000 +0800 ++++ postgresql-10.5.new/src/backend/catalog/pg_collation.c 2023-11-06 20:15:32.834822194 +0800 +@@ -78,15 +78,24 @@ + * friendlier error message. The unique index provides a backstop against + * race conditions. + */ +- if (SearchSysCacheExists3(COLLNAMEENCNSP, +- PointerGetDatum(collname), +- Int32GetDatum(collencoding), +- ObjectIdGetDatum(collnamespace))) ++ oid = GetSysCacheOid3(COLLNAMEENCNSP, ++ 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 +125,17 @@ + * 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, ++ PointerGetDatum(collname), ++ Int32GetDatum(GetDatabaseEncoding()), ++ ObjectIdGetDatum(collnamespace)); ++ else ++ oid = GetSysCacheOid3(COLLNAMEENCNSP, ++ PointerGetDatum(collname), ++ Int32GetDatum(-1), ++ ObjectIdGetDatum(collnamespace)); ++ if (OidIsValid(oid)) + { + if (quiet) + { +@@ -134,6 +144,14 @@ + } + 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 */ + heap_close(rel, NoLock); + ereport(NOTICE, + (errcode(ERRCODE_DUPLICATE_OBJECT), +diff -urN postgresql-10.5/src/backend/catalog/pg_depend.c postgresql-10.5.new/src/backend/catalog/pg_depend.c +--- postgresql-10.5/src/backend/catalog/pg_depend.c 2018-08-07 04:05:31.000000000 +0800 ++++ postgresql-10.5.new/src/backend/catalog/pg_depend.c 2023-11-06 20:17:41.070405939 +0800 +@@ -125,15 +125,23 @@ + + /* + * 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, +@@ -151,6 +159,12 @@ + { + 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)) + { +@@ -164,6 +178,13 @@ + 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 */ +@@ -175,6 +196,49 @@ + } + } + ++/* ++ * 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 -urN postgresql-10.5/src/backend/catalog/pg_operator.c postgresql-10.5.new/src/backend/catalog/pg_operator.c +--- postgresql-10.5/src/backend/catalog/pg_operator.c 2018-08-07 04:05:31.000000000 +0800 ++++ postgresql-10.5.new/src/backend/catalog/pg_operator.c 2023-11-06 20:17:57.538350179 +0800 +@@ -858,7 +858,7 @@ + oper->oprowner); + + /* Dependency on extension */ +- recordDependencyOnCurrentExtension(&myself, true); ++ recordDependencyOnCurrentExtension(&myself, isUpdate); + + return myself; + } +diff -urN postgresql-10.5/src/backend/commands/foreigncmds.c postgresql-10.5.new/src/backend/commands/foreigncmds.c +--- postgresql-10.5/src/backend/commands/foreigncmds.c 2018-08-07 04:05:31.000000000 +0800 ++++ postgresql-10.5.new/src/backend/commands/foreigncmds.c 2023-11-06 20:26:27.133438848 +0800 +@@ -878,13 +878,22 @@ + 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", +@@ -1170,6 +1179,10 @@ + { + 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 -urN postgresql-10.5/src/backend/commands/schemacmds.c postgresql-10.5.new/src/backend/commands/schemacmds.c +--- postgresql-10.5/src/backend/commands/schemacmds.c 2018-08-07 04:05:31.000000000 +0800 ++++ postgresql-10.5.new/src/backend/commands/schemacmds.c 2023-11-06 20:27:23.989404450 +0800 +@@ -113,14 +113,25 @@ + * 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 -urN postgresql-10.5/src/backend/commands/sequence.c postgresql-10.5.new/src/backend/commands/sequence.c +--- postgresql-10.5/src/backend/commands/sequence.c 2018-08-07 04:05:31.000000000 +0800 ++++ postgresql-10.5.new/src/backend/commands/sequence.c 2023-11-06 20:27:46.201393441 +0800 +@@ -147,6 +147,14 @@ + 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 -urN postgresql-10.5/src/backend/commands/statscmds.c postgresql-10.5.new/src/backend/commands/statscmds.c +--- postgresql-10.5/src/backend/commands/statscmds.c 2018-08-07 04:05:31.000000000 +0800 ++++ postgresql-10.5.new/src/backend/commands/statscmds.c 2023-11-06 20:28:06.401384532 +0800 +@@ -156,6 +156,10 @@ + { + 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 -urN postgresql-10.5/src/backend/commands/view.c postgresql-10.5.new/src/backend/commands/view.c +--- postgresql-10.5/src/backend/commands/view.c 2018-08-07 04:05:31.000000000 +0800 ++++ postgresql-10.5.new/src/backend/commands/view.c 2023-11-06 20:28:40.469371780 +0800 +@@ -219,8 +219,22 @@ + + 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 -urN postgresql-10.5/src/backend/parser/parse_utilcmd.c postgresql-10.5.new/src/backend/parser/parse_utilcmd.c +--- postgresql-10.5/src/backend/parser/parse_utilcmd.c 2018-08-07 04:05:31.000000000 +0800 ++++ postgresql-10.5.new/src/backend/parser/parse_utilcmd.c 2023-11-06 20:29:26.609358773 +0800 +@@ -203,6 +203,16 @@ + */ + 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 -urN postgresql-10.5/src/include/catalog/dependency.h postgresql-10.5.new/src/include/catalog/dependency.h +--- postgresql-10.5/src/include/catalog/dependency.h 2018-08-07 04:05:31.000000000 +0800 ++++ postgresql-10.5.new/src/include/catalog/dependency.h 2023-11-06 20:30:54.313346173 +0800 +@@ -226,6 +226,8 @@ + extern void recordDependencyOnCurrentExtension(const ObjectAddress *object, + bool isReplace); + ++extern void checkMembershipInCurrentExtension(const ObjectAddress *object); ++ + extern long deleteDependencyRecordsFor(Oid classId, Oid objectId, + bool skipExtensionDeps); + +diff -urN postgresql-10.5/src/test/modules/test_extensions/expected/test_extensions.out postgresql-10.5.new/src/test/modules/test_extensions/expected/test_extensions.out +--- postgresql-10.5/src/test/modules/test_extensions/expected/test_extensions.out 2018-08-07 04:05:31.000000000 +0800 ++++ postgresql-10.5.new/src/test/modules/test_extensions/expected/test_extensions.out 2023-11-06 20:33:05.313352359 +0800 +@@ -121,3 +121,156 @@ + + -- dropping it should still work + drop extension test_ext8; ++-- 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 -urN postgresql-10.5/src/test/modules/test_extensions/Makefile postgresql-10.5.new/src/test/modules/test_extensions/Makefile +--- postgresql-10.5/src/test/modules/test_extensions/Makefile 2023-11-06 20:06:15.565766099 +0800 ++++ postgresql-10.5.new/src/test/modules/test_extensions/Makefile 2023-11-06 20:31:51.637345532 +0800 +@@ -4,10 +4,13 @@ + 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 -urN postgresql-10.5/src/test/modules/test_extensions/sql/test_extensions.sql postgresql-10.5.new/src/test/modules/test_extensions/sql/test_extensions.sql +--- postgresql-10.5/src/test/modules/test_extensions/sql/test_extensions.sql 2018-08-07 04:05:31.000000000 +0800 ++++ postgresql-10.5.new/src/test/modules/test_extensions/sql/test_extensions.sql 2023-11-06 20:34:03.857363188 +0800 +@@ -64,3 +64,112 @@ + + -- dropping it should still work + drop extension test_ext8; ++-- 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 -urN postgresql-10.5/src/test/modules/test_extensions/test_ext_cine--1.0--1.1.sql postgresql-10.5.new/src/test/modules/test_extensions/test_ext_cine--1.0--1.1.sql +--- postgresql-10.5/src/test/modules/test_extensions/test_ext_cine--1.0--1.1.sql 1970-01-01 08:00:00.000000000 +0800 ++++ postgresql-10.5.new/src/test/modules/test_extensions/test_ext_cine--1.0--1.1.sql 2022-11-08 05:51:09.000000000 +0800 +@@ -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 -urN postgresql-10.5/src/test/modules/test_extensions/test_ext_cine--1.0.sql postgresql-10.5.new/src/test/modules/test_extensions/test_ext_cine--1.0.sql +--- postgresql-10.5/src/test/modules/test_extensions/test_ext_cine--1.0.sql 1970-01-01 08:00:00.000000000 +0800 ++++ postgresql-10.5.new/src/test/modules/test_extensions/test_ext_cine--1.0.sql 2022-11-08 05:51:09.000000000 +0800 +@@ -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 -urN postgresql-10.5/src/test/modules/test_extensions/test_ext_cine.control postgresql-10.5.new/src/test/modules/test_extensions/test_ext_cine.control +--- postgresql-10.5/src/test/modules/test_extensions/test_ext_cine.control 1970-01-01 08:00:00.000000000 +0800 ++++ postgresql-10.5.new/src/test/modules/test_extensions/test_ext_cine.control 2022-11-08 05:51:09.000000000 +0800 +@@ -0,0 +1,3 @@ ++comment = 'Test extension using CREATE IF NOT EXISTS' ++default_version = '1.0' ++relocatable = true +diff -urN postgresql-10.5/src/test/modules/test_extensions/test_ext_cor--1.0.sql postgresql-10.5.new/src/test/modules/test_extensions/test_ext_cor--1.0.sql +--- postgresql-10.5/src/test/modules/test_extensions/test_ext_cor--1.0.sql 1970-01-01 08:00:00.000000000 +0800 ++++ postgresql-10.5.new/src/test/modules/test_extensions/test_ext_cor--1.0.sql 2022-11-08 05:51:09.000000000 +0800 +@@ -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 -urN postgresql-10.5/src/test/modules/test_extensions/test_ext_cor.control postgresql-10.5.new/src/test/modules/test_extensions/test_ext_cor.control +--- postgresql-10.5/src/test/modules/test_extensions/test_ext_cor.control 1970-01-01 08:00:00.000000000 +0800 ++++ postgresql-10.5.new/src/test/modules/test_extensions/test_ext_cor.control 2022-11-08 05:51:09.000000000 +0800 +@@ -0,0 +1,3 @@ ++comment = 'Test extension using CREATE OR REPLACE' ++default_version = '1.0' ++relocatable = true diff --git a/postgresql.spec b/postgresql.spec index 16ab6e1715cb71128b36b39156770e2f2f720415..f506d5a79bd257d3f425f6c524d4e2735b82cad8 100644 --- a/postgresql.spec +++ b/postgresql.spec @@ -48,6 +48,11 @@ Patch6014: CVE-2021-20229.patch Patch6018: CVE-2021-32028.patch Patch6019: CVE-2021-23214.patch Patch6020: CVE-2021-23222.patch +Patch6021: CVE-2022-1552-1.patch +Patch6022: CVE-2022-1552-2.patch +Patch6023: CVE-2022-1552-3.patch +Patch6024: CVE-2022-2625-1.patch +Patch6025: CVE-2022-2625-2.patch BuildRequires: gcc perl(ExtUtils::MakeMaker) glibc-devel bison flex gawk perl(ExtUtils::Embed) BuildRequires: perl-devel perl-generators readline-devel zlib-devel systemd systemd-devel @@ -438,6 +443,9 @@ find_lang_bins pltcl.lst pltcl %attr(-,postgres,postgres) %{_libdir}/pgsql/test %changelog +* Tue Nov 11 2023 zhangzeyang - 10.5-24 +- Fix CVE-2022-1552 CVE-2022-2625 + * Fri Mar 11 2022 wangkai - 10.5-23 - Fix CVE-2021-23214 CVE-2021-23222