aboutsummaryrefslogtreecommitdiffstats
path: root/meta-oe/recipes-dbs/postgresql/files/CVE-2022-1552.patch
diff options
context:
space:
mode:
Diffstat (limited to 'meta-oe/recipes-dbs/postgresql/files/CVE-2022-1552.patch')
-rw-r--r--meta-oe/recipes-dbs/postgresql/files/CVE-2022-1552.patch947
1 files changed, 0 insertions, 947 deletions
diff --git a/meta-oe/recipes-dbs/postgresql/files/CVE-2022-1552.patch b/meta-oe/recipes-dbs/postgresql/files/CVE-2022-1552.patch
deleted file mode 100644
index 6f0d5ac06f..0000000000
--- a/meta-oe/recipes-dbs/postgresql/files/CVE-2022-1552.patch
+++ /dev/null
@@ -1,947 +0,0 @@
-From 31eefa1efc8eecb6ab91c8835d2952d44a3b1ae1 Mon Sep 17 00:00:00 2001
-From: Hitendra Prajapati <hprajapati@mvista.com>
-Date: Thu, 22 Sep 2022 11:20:41 +0530
-Subject: [PATCH] CVE-2022-1552
-
-Upstream-Status: Backport [https://git.postgresql.org/gitweb/?p=postgresql.git;a=commit;h=ab49ce7c3414ac19e4afb386d7843ce2d2fb8bda && https://git.postgresql.org/gitweb/?p=postgresql.git;a=commit;h=677a494789062ca88e0142a17bedd5415f6ab0aa]
-
-CVE: CVE-2022-1552
-Signed-off-by: Hitendra Prajapati <hprajapati@mvista.com>
----
- contrib/amcheck/expected/check_btree.out | 23 ++++++
- contrib/amcheck/sql/check_btree.sql | 21 +++++
- contrib/amcheck/verify_nbtree.c | 27 +++++++
- src/backend/access/brin/brin.c | 29 ++++++-
- src/backend/catalog/index.c | 65 ++++++++++++----
- src/backend/commands/cluster.c | 37 ++++++---
- src/backend/commands/indexcmds.c | 98 ++++++++++++++++++++----
- src/backend/commands/matview.c | 30 +++-----
- src/backend/utils/init/miscinit.c | 24 +++---
- src/test/regress/expected/privileges.out | 71 +++++++++++++++++
- src/test/regress/sql/privileges.sql | 64 ++++++++++++++++
- 11 files changed, 422 insertions(+), 67 deletions(-)
-
-diff --git a/contrib/amcheck/expected/check_btree.out b/contrib/amcheck/expected/check_btree.out
-index 59a805d..0fd6ea0 100644
---- a/contrib/amcheck/expected/check_btree.out
-+++ b/contrib/amcheck/expected/check_btree.out
-@@ -168,11 +168,34 @@ SELECT bt_index_check('toasty', true);
-
- (1 row)
-
-+--
-+-- 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', true);
-+ bt_index_check
-+----------------
-+
-+(1 row)
-+
- -- cleanup
- DROP TABLE bttest_a;
- DROP TABLE bttest_b;
- DROP TABLE bttest_multi;
- DROP TABLE delete_test_table;
- DROP TABLE toast_bug;
-+DROP FUNCTION ifun(int8);
- DROP OWNED BY regress_bttest_role; -- permissions
- DROP ROLE regress_bttest_role;
-diff --git a/contrib/amcheck/sql/check_btree.sql b/contrib/amcheck/sql/check_btree.sql
-index 99acbc8..3248187 100644
---- a/contrib/amcheck/sql/check_btree.sql
-+++ b/contrib/amcheck/sql/check_btree.sql
-@@ -110,11 +110,32 @@ INSERT INTO toast_bug SELECT repeat('a', 2200);
- -- Should not get false positive report of corruption:
- SELECT bt_index_check('toasty', true);
-
-+--
-+-- 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', true);
-+
- -- cleanup
- DROP TABLE bttest_a;
- DROP TABLE bttest_b;
- DROP TABLE bttest_multi;
- DROP TABLE delete_test_table;
- DROP TABLE toast_bug;
-+DROP FUNCTION ifun(int8);
- DROP OWNED BY regress_bttest_role; -- permissions
- DROP ROLE regress_bttest_role;
-diff --git a/contrib/amcheck/verify_nbtree.c b/contrib/amcheck/verify_nbtree.c
-index 700a02f..cb6475d 100644
---- a/contrib/amcheck/verify_nbtree.c
-+++ b/contrib/amcheck/verify_nbtree.c
-@@ -228,6 +228,9 @@ bt_index_check_internal(Oid indrelid, bool parentcheck, bool heapallindexed,
- Relation indrel;
- Relation heaprel;
- LOCKMODE lockmode;
-+ Oid save_userid;
-+ int save_sec_context;
-+ int save_nestlevel;
-
- if (parentcheck)
- lockmode = ShareLock;
-@@ -244,9 +247,27 @@ bt_index_check_internal(Oid indrelid, bool parentcheck, bool heapallindexed,
- */
- heapid = IndexGetRelation(indrelid, true);
- if (OidIsValid(heapid))
-+ {
- heaprel = table_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;
-+ /* for "gcc -Og" https://gcc.gnu.org/bugzilla/show_bug.cgi?id=78394 */
-+ save_userid = InvalidOid;
-+ save_sec_context = -1;
-+ save_nestlevel = -1;
-+ }
-
- /*
- * Open the target index relations separately (like relation_openrv(), but
-@@ -293,6 +314,12 @@ bt_index_check_internal(Oid indrelid, bool parentcheck, bool heapallindexed,
- heapallindexed, rootdescend);
- }
-
-+ /* 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
- * routines will trigger shared cache invalidations to be sent, so we can
-diff --git a/src/backend/access/brin/brin.c b/src/backend/access/brin/brin.c
-index c7b403b..781cac2 100644
---- a/src/backend/access/brin/brin.c
-+++ b/src/backend/access/brin/brin.c
-@@ -873,6 +873,9 @@ brin_summarize_range(PG_FUNCTION_ARGS)
- Oid heapoid;
- Relation indexRel;
- Relation heapRel;
-+ Oid save_userid;
-+ int save_sec_context;
-+ int save_nestlevel;
- double numSummarized = 0;
-
- if (RecoveryInProgress())
-@@ -899,7 +902,22 @@ brin_summarize_range(PG_FUNCTION_ARGS)
- */
- heapoid = IndexGetRelation(indexoid, true);
- if (OidIsValid(heapoid))
-+ {
- heapRel = table_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;
-
-@@ -914,7 +932,7 @@ brin_summarize_range(PG_FUNCTION_ARGS)
- 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, OBJECT_INDEX,
- RelationGetRelationName(indexRel));
-
-@@ -932,6 +950,12 @@ brin_summarize_range(PG_FUNCTION_ARGS)
- /* 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);
-
-@@ -973,6 +997,9 @@ brin_desummarize_range(PG_FUNCTION_ARGS)
- * 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 --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
-index 3ece136..0333bfd 100644
---- a/src/backend/catalog/index.c
-+++ b/src/backend/catalog/index.c
-@@ -1400,6 +1400,9 @@ index_concurrently_build(Oid heapRelationId,
- Oid indexRelationId)
- {
- Relation heapRel;
-+ Oid save_userid;
-+ int save_sec_context;
-+ int save_nestlevel;
- Relation indexRelation;
- IndexInfo *indexInfo;
-
-@@ -1409,7 +1412,16 @@ index_concurrently_build(Oid heapRelationId,
- /* Open and lock the parent heap relation */
- heapRel = table_open(heapRelationId, 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(heapRel->rd_rel->relowner,
-+ save_sec_context | SECURITY_RESTRICTED_OPERATION);
-+ save_nestlevel = NewGUCNestLevel();
-+
- indexRelation = index_open(indexRelationId, RowExclusiveLock);
-
- /*
-@@ -1425,6 +1437,12 @@ index_concurrently_build(Oid heapRelationId,
- /* Now build the index */
- index_build(heapRel, indexRelation, indexInfo, false, true);
-
-+ /* 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 both the relations, but keep the locks */
- table_close(heapRel, NoLock);
- index_close(indexRelation, NoLock);
-@@ -3271,7 +3289,17 @@ validate_index(Oid heapId, Oid indexId, Snapshot snapshot)
-
- /* Open and lock the parent heap relation */
- heapRelation = table_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);
-
- /*
-@@ -3284,16 +3312,6 @@ validate_index(Oid heapId, Oid indexId, Snapshot snapshot)
- /* mark build is concurrent just for consistency */
- 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.
- */
-@@ -3497,6 +3515,9 @@ reindex_index(Oid indexId, bool skip_constraint_checks, char persistence,
- Relation iRel,
- heapRelation;
- Oid heapId;
-+ Oid save_userid;
-+ int save_sec_context;
-+ int save_nestlevel;
- IndexInfo *indexInfo;
- volatile bool skipped_constraint = false;
- PGRUsage ru0;
-@@ -3527,6 +3548,16 @@ reindex_index(Oid indexId, bool skip_constraint_checks, char persistence,
- */
- iRel = index_open(indexId, AccessExclusiveLock);
-
-+ /*
-+ * 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();
-+
- if (progress)
- pgstat_progress_update_param(PROGRESS_CREATEIDX_ACCESS_METHOD_OID,
- iRel->rd_rel->relam);
-@@ -3684,12 +3715,18 @@ reindex_index(Oid indexId, bool skip_constraint_checks, char persistence,
- errdetail_internal("%s",
- pg_rusage_show(&ru0))));
-
-- if (progress)
-- pgstat_progress_end_command();
-+ /* 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);
- table_close(heapRelation, NoLock);
-+
-+ if (progress)
-+ pgstat_progress_end_command();
- }
-
- /*
-diff --git a/src/backend/commands/cluster.c b/src/backend/commands/cluster.c
-index bd6f408..74db03e 100644
---- a/src/backend/commands/cluster.c
-+++ b/src/backend/commands/cluster.c
-@@ -266,6 +266,9 @@ void
- cluster_rel(Oid tableOid, Oid indexOid, int options)
- {
- Relation OldHeap;
-+ Oid save_userid;
-+ int save_sec_context;
-+ int save_nestlevel;
- bool verbose = ((options & CLUOPT_VERBOSE) != 0);
- bool recheck = ((options & CLUOPT_RECHECK) != 0);
-
-@@ -295,6 +298,16 @@ cluster_rel(Oid tableOid, Oid indexOid, int options)
- 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.
-@@ -309,11 +322,10 @@ cluster_rel(Oid tableOid, Oid indexOid, int options)
- 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);
-- pgstat_progress_end_command();
-- return;
-+ goto out;
- }
-
- /*
-@@ -327,8 +339,7 @@ cluster_rel(Oid tableOid, Oid indexOid, int options)
- if (RELATION_IS_OTHER_TEMP(OldHeap))
- {
- relation_close(OldHeap, AccessExclusiveLock);
-- pgstat_progress_end_command();
-- return;
-+ goto out;
- }
-
- if (OidIsValid(indexOid))
-@@ -339,8 +350,7 @@ cluster_rel(Oid tableOid, Oid indexOid, int options)
- if (!SearchSysCacheExists1(RELOID, ObjectIdGetDatum(indexOid)))
- {
- relation_close(OldHeap, AccessExclusiveLock);
-- pgstat_progress_end_command();
-- return;
-+ goto out;
- }
-
- /*
-@@ -350,8 +360,7 @@ cluster_rel(Oid tableOid, Oid indexOid, int options)
- if (!HeapTupleIsValid(tuple)) /* probably can't happen */
- {
- relation_close(OldHeap, AccessExclusiveLock);
-- pgstat_progress_end_command();
-- return;
-+ goto out;
- }
- indexForm = (Form_pg_index) GETSTRUCT(tuple);
- if (!indexForm->indisclustered)
-@@ -413,8 +422,7 @@ cluster_rel(Oid tableOid, Oid indexOid, int options)
- !RelationIsPopulated(OldHeap))
- {
- relation_close(OldHeap, AccessExclusiveLock);
-- pgstat_progress_end_command();
-- return;
-+ goto out;
- }
-
- /*
-@@ -430,6 +438,13 @@ cluster_rel(Oid tableOid, Oid indexOid, int options)
-
- /* NB: rebuild_relation does table_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);
-+
- pgstat_progress_end_command();
- }
-
-diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c
-index be1cf8c..167b377 100644
---- a/src/backend/commands/indexcmds.c
-+++ b/src/backend/commands/indexcmds.c
-@@ -470,21 +470,22 @@ DefineIndex(Oid relationId,
- LOCKTAG heaplocktag;
- LOCKMODE lockmode;
- Snapshot snapshot;
-- int save_nestlevel = -1;
-+ Oid root_save_userid;
-+ int root_save_sec_context;
-+ int root_save_nestlevel;
- int i;
-
-+ root_save_nestlevel = NewGUCNestLevel();
-+
- /*
- * Some callers need us to run with an empty default_tablespace; this is a
- * necessary hack to be able to reproduce catalog state accurately when
- * recreating indexes after table-rewriting ALTER TABLE.
- */
- if (stmt->reset_default_tblspc)
-- {
-- save_nestlevel = NewGUCNestLevel();
- (void) set_config_option("default_tablespace", "",
- PGC_USERSET, PGC_S_SESSION,
- GUC_ACTION_SAVE, true, 0, false);
-- }
-
- /*
- * Force non-concurrent build on temporary relations, even if CONCURRENTLY
-@@ -563,6 +564,15 @@ DefineIndex(Oid relationId,
- lockmode = concurrent ? ShareUpdateExclusiveLock : ShareLock;
- rel = table_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);
-+
- namespaceId = RelationGetNamespace(rel);
-
- /* Ensure that it makes sense to index this kind of relation */
-@@ -648,7 +658,7 @@ DefineIndex(Oid relationId,
- {
- 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, OBJECT_SCHEMA,
-@@ -680,7 +690,7 @@ DefineIndex(Oid relationId,
- {
- 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, OBJECT_TABLESPACE,
-@@ -1066,15 +1076,17 @@ DefineIndex(Oid relationId,
-
- ObjectAddressSet(address, RelationRelationId, indexRelationId);
-
-- /*
-- * Revert to original default_tablespace. Must do this before any return
-- * from this function, but after index_create, so this is a good time.
-- */
-- if (save_nestlevel >= 0)
-- AtEOXact_GUC(true, save_nestlevel);
--
- if (!OidIsValid(indexRelationId))
- {
-+ /*
-+ * Roll back any GUC changes executed by index functions. Also revert
-+ * to original default_tablespace if we changed it above.
-+ */
-+ AtEOXact_GUC(false, root_save_nestlevel);
-+
-+ /* Restore userid and security context */
-+ SetUserIdAndSecContext(root_save_userid, root_save_sec_context);
-+
- table_close(rel, NoLock);
-
- /* If this is the top-level index, we're done */
-@@ -1084,6 +1096,17 @@ DefineIndex(Oid relationId,
- return address;
- }
-
-+ /*
-+ * Roll back any GUC changes executed by index functions, and keep
-+ * subsequent changes local to this command. It's barely possible that
-+ * some index function changed a behavior-affecting GUC, e.g. xmloption,
-+ * that affects subsequent steps. This improves bug-compatibility with
-+ * older PostgreSQL versions. They did the AtEOXact_GUC() here for the
-+ * purpose of clearing the above default_tablespace change.
-+ */
-+ AtEOXact_GUC(false, root_save_nestlevel);
-+ root_save_nestlevel = NewGUCNestLevel();
-+
- /* Add any requested comment */
- if (stmt->idxcomment != NULL)
- CreateComments(indexRelationId, RelationRelationId, 0,
-@@ -1130,6 +1153,9 @@ DefineIndex(Oid relationId,
- {
- Oid childRelid = part_oids[i];
- Relation childrel;
-+ Oid child_save_userid;
-+ int child_save_sec_context;
-+ int child_save_nestlevel;
- List *childidxs;
- ListCell *cell;
- AttrNumber *attmap;
-@@ -1138,6 +1164,12 @@ DefineIndex(Oid relationId,
-
- childrel = table_open(childRelid, lockmode);
-
-+ GetUserIdAndSecContext(&child_save_userid,
-+ &child_save_sec_context);
-+ SetUserIdAndSecContext(childrel->rd_rel->relowner,
-+ child_save_sec_context | SECURITY_RESTRICTED_OPERATION);
-+ child_save_nestlevel = NewGUCNestLevel();
-+
- /*
- * Don't try to create indexes on foreign tables, though. Skip
- * those if a regular index, or fail if trying to create a
-@@ -1153,6 +1185,9 @@ DefineIndex(Oid relationId,
- errdetail("Table \"%s\" contains partitions that are foreign tables.",
- RelationGetRelationName(rel))));
-
-+ AtEOXact_GUC(false, child_save_nestlevel);
-+ SetUserIdAndSecContext(child_save_userid,
-+ child_save_sec_context);
- table_close(childrel, lockmode);
- continue;
- }
-@@ -1226,6 +1261,9 @@ DefineIndex(Oid relationId,
- }
-
- list_free(childidxs);
-+ AtEOXact_GUC(false, child_save_nestlevel);
-+ SetUserIdAndSecContext(child_save_userid,
-+ child_save_sec_context);
- table_close(childrel, NoLock);
-
- /*
-@@ -1280,12 +1318,21 @@ DefineIndex(Oid relationId,
- if (found_whole_row)
- elog(ERROR, "cannot convert whole-row table reference");
-
-+ /*
-+ * Recurse as the starting user ID. Callee will use that
-+ * for permission checks, then switch again.
-+ */
-+ Assert(GetUserId() == child_save_userid);
-+ SetUserIdAndSecContext(root_save_userid,
-+ root_save_sec_context);
- DefineIndex(childRelid, childStmt,
- InvalidOid, /* no predefined OID */
- indexRelationId, /* this is our child */
- createdConstraintId,
- is_alter_table, check_rights, check_not_in_use,
- skip_build, quiet);
-+ SetUserIdAndSecContext(child_save_userid,
-+ child_save_sec_context);
- }
-
- pgstat_progress_update_param(PROGRESS_CREATEIDX_PARTITIONS_DONE,
-@@ -1322,12 +1369,17 @@ DefineIndex(Oid relationId,
- * Indexes on partitioned tables are not themselves built, so we're
- * done here.
- */
-+ AtEOXact_GUC(false, root_save_nestlevel);
-+ SetUserIdAndSecContext(root_save_userid, root_save_sec_context);
- table_close(rel, NoLock);
- if (!OidIsValid(parentIndexId))
- pgstat_progress_end_command();
- return address;
- }
-
-+ AtEOXact_GUC(false, root_save_nestlevel);
-+ SetUserIdAndSecContext(root_save_userid, root_save_sec_context);
-+
- if (!concurrent)
- {
- /* Close the heap and we're done, in the non-concurrent case */
-@@ -3040,6 +3092,9 @@ ReindexRelationConcurrently(Oid relationOid, int options)
- Oid newIndexId;
- Relation indexRel;
- Relation heapRel;
-+ Oid save_userid;
-+ int save_sec_context;
-+ int save_nestlevel;
- Relation newIndexRel;
- LockRelId *lockrelid;
-
-@@ -3047,6 +3102,16 @@ ReindexRelationConcurrently(Oid relationOid, int options)
- heapRel = table_open(indexRel->rd_index->indrelid,
- 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(&save_userid, &save_sec_context);
-+ SetUserIdAndSecContext(heapRel->rd_rel->relowner,
-+ save_sec_context | SECURITY_RESTRICTED_OPERATION);
-+ save_nestlevel = NewGUCNestLevel();
-+
- /* This function shouldn't be called for temporary relations. */
- if (indexRel->rd_rel->relpersistence == RELPERSISTENCE_TEMP)
- elog(ERROR, "cannot reindex a temporary table concurrently");
-@@ -3101,6 +3166,13 @@ ReindexRelationConcurrently(Oid relationOid, int options)
-
- index_close(indexRel, NoLock);
- index_close(newIndexRel, NoLock);
-+
-+ /* 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);
-+
- table_close(heapRel, NoLock);
- }
-
-diff --git a/src/backend/commands/matview.c b/src/backend/commands/matview.c
-index 80e9ec0..e485661 100644
---- a/src/backend/commands/matview.c
-+++ b/src/backend/commands/matview.c
-@@ -167,6 +167,17 @@ ExecRefreshMatView(RefreshMatViewStmt *stmt, const char *queryString,
- lockmode, 0,
- RangeVarCallbackOwnsTable, NULL);
- matviewRel = table_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 @@ ExecRefreshMatView(RefreshMatViewStmt *stmt, const char *queryString,
- */
- 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 @@ ExecRefreshMatView(RefreshMatViewStmt *stmt, const char *queryString,
- 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 --git a/src/backend/utils/init/miscinit.c b/src/backend/utils/init/miscinit.c
-index de554e2..c9f858e 100644
---- a/src/backend/utils/init/miscinit.c
-+++ b/src/backend/utils/init/miscinit.c
-@@ -455,15 +455,21 @@ GetAuthenticatedUserId(void)
- * 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 --git a/src/test/regress/expected/privileges.out b/src/test/regress/expected/privileges.out
-index 186d2fb..0f0c1b3 100644
---- a/src/test/regress/expected/privileges.out
-+++ b/src/test/regress/expected/privileges.out
-@@ -1336,6 +1336,61 @@ SELECT has_table_privilege('regress_priv_user1', 'atest4', 'SELECT WITH GRANT OP
- -- 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;
-+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);
-+REINDEX TABLE sro_ptab;
-+REINDEX INDEX CONCURRENTLY sro_pidx;
- SET SESSION AUTHORIZATION regress_sro_user;
- CREATE FUNCTION unwanted_grant() RETURNS void LANGUAGE sql AS
- 'GRANT regress_priv_group2 TO regress_sro_user';
-@@ -1373,6 +1428,22 @@ CONTEXT: SQL function "unwanted_grant" statement 1
- 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 --git a/src/test/regress/sql/privileges.sql b/src/test/regress/sql/privileges.sql
-index 34fbf0e..c0b88a6 100644
---- a/src/test/regress/sql/privileges.sql
-+++ b/src/test/regress/sql/privileges.sql
-@@ -826,6 +826,53 @@ SELECT has_table_privilege('regress_priv_user1', 'atest4', 'SELECT WITH GRANT OP
- \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;
-+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;
-+REINDEX INDEX CONCURRENTLY sro_pidx;
-+
- SET SESSION AUTHORIZATION regress_sro_user;
- CREATE FUNCTION unwanted_grant() RETURNS void LANGUAGE sql AS
- 'GRANT regress_priv_group2 TO regress_sro_user';
-@@ -852,6 +899,23 @@ REFRESH MATERIALIZED VIEW sro_mv;
- 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;
-
---
-2.25.1
-