Author: Filip Januš Backport from release: 10.21/12.11/13.7 Upstream commit: https://git.postgresql.org/gitweb/?p=postgresql.git;a=commitdiff;h=a117cebd638dd02e5c2e791c25e43745f233111b postgresql-9.2 doesn't support amcheck and brin BZ: https://bugzilla.redhat.com/show_bug.cgi?id=2081126 diff -ur -x '*.so' -x '*.o' -x 'cscope.*' -x '*.out' -x '*.sql' postgresql-9.2.24/src/backend/catalog/index.c postgresql-9.2.24_patched/src/backend/catalog/index.c --- postgresql-9.2.24/src/backend/catalog/index.c 2017-11-06 23:17:39.000000000 +0100 +++ postgresql-9.2.24_patched/src/backend/catalog/index.c 2022-06-09 15:40:32.000000000 +0200 @@ -2684,7 +2684,16 @@ /* 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); /* @@ -2698,16 +2707,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; @@ -3112,6 +3111,9 @@ Oid heapId; IndexInfo *indexInfo; volatile bool skipped_constraint = false; + Oid save_userid; + int save_sec_context; + int save_nestlevel; /* * Open and lock the parent heap relation. ShareLock is sufficient since @@ -3121,6 +3123,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. */ @@ -3260,6 +3272,12 @@ heap_close(pg_index, RowExclusiveLock); } + /* 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 -ur -x '*.so' -x '*.o' -x 'cscope.*' -x '*.out' -x '*.sql' postgresql-9.2.24/src/backend/commands/cluster.c postgresql-9.2.24_patched/src/backend/commands/cluster.c --- postgresql-9.2.24/src/backend/commands/cluster.c 2017-11-06 23:17:39.000000000 +0100 +++ postgresql-9.2.24_patched/src/backend/commands/cluster.c 2022-06-09 15:41:12.000000000 +0200 @@ -258,7 +258,9 @@ int freeze_min_age, int freeze_table_age) { Relation OldHeap; - + Oid save_userid; + int save_sec_context; + int save_nestlevel; /* Check for user-requested abort. */ CHECK_FOR_INTERRUPTS(); @@ -275,6 +277,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. * @@ -288,10 +300,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; } /* @@ -305,7 +317,7 @@ if (RELATION_IS_OTHER_TEMP(OldHeap)) { relation_close(OldHeap, AccessExclusiveLock); - return; + goto out; } if (OidIsValid(indexOid)) @@ -316,7 +328,7 @@ if (!SearchSysCacheExists1(RELOID, ObjectIdGetDatum(indexOid))) { relation_close(OldHeap, AccessExclusiveLock); - return; + goto out; } /* @@ -326,14 +338,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,6 +401,13 @@ 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 -ur -x '*.so' -x '*.o' -x 'cscope.*' -x '*.out' -x '*.sql' postgresql-9.2.24/src/backend/commands/indexcmds.c postgresql-9.2.24_patched/src/backend/commands/indexcmds.c --- postgresql-9.2.24/src/backend/commands/indexcmds.c 2017-11-06 23:17:39.000000000 +0100 +++ postgresql-9.2.24_patched/src/backend/commands/indexcmds.c 2022-06-08 12:32:22.000000000 +0200 @@ -329,6 +329,11 @@ LOCKMODE lockmode; Snapshot snapshot; int i; + Oid root_save_userid; + int root_save_sec_context; + int root_save_nestlevel; + + root_save_nestlevel = NewGUCNestLevel(); /* * count attributes in index @@ -358,6 +363,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); @@ -400,7 +414,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, @@ -427,7 +441,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, @@ -610,11 +624,40 @@ skip_build || stmt->concurrent, stmt->concurrent); + 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); + + heap_close(rel, NoLock); + return indexRelationId; + } + + /* + * 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, 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 */ @@ -705,6 +748,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); @@ -720,6 +773,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); --- postgresql-9.2.24/src/test/regress/expected/privileges.out 2017-11-06 23:17:39.000000000 +0100 +++ privileges.out 2022-06-10 10:05:51.000000000 +0200 @@ -1544,9 +1544,27 @@ set session role regressuser1; drop table dep_priv_test; +\c - +CREATE ROLE regress_sro_user; +CREATE FUNCTION sro_ifun(int) RETURNS int AS $$ +BEGIN + RETURN(SELECT current_user); + +END; +$$ LANGUAGE plpgsql IMMUTABLE; +CREATE TABLE sro_tab (a int); +ALTER TABLE sro_tab OWNER TO regress_sro_user; +INSERT INTO sro_tab VALUES (1), (2), (3); +CREATE INDEX sro_idx ON sro_tab ((sro_ifun(a) + sro_ifun(0))) + WHERE sro_ifun(a + 10) > sro_ifun(10); +ERROR: invalid input syntax for integer: "regress_sro_user" +CONTEXT: PL/pgSQL function sro_ifun(integer) while casting return value to function's return type -- clean up \c drop sequence x_seq; +DROP TABLE sro_tab; +DROP ROLE regress_sro_user; +DROP FUNCTION sro_ifun(int); DROP FUNCTION testfunc2(int); DROP FUNCTION testfunc4(boolean); DROP VIEW atestv1; diff -ur postgresql-9.2.24/src/test/regress/sql/privileges.sql postgresql-9.2.24_patch/src/test/regress/sql/privileges.sql --- postgresql-9.2.24/src/test/regress/sql/privileges.sql 2017-11-06 23:17:39.000000000 +0100 +++ postgresql-9.2.24_patch/src/test/regress/sql/privileges.sql 2022-06-08 10:01:35.000000000 +0200 @@ -931,6 +931,19 @@ set session role regressuser1; drop table dep_priv_test; +\c - +CREATE ROLE regress_sro_user; +CREATE FUNCTION sro_ifun(int) RETURNS int AS $$ +BEGIN + RETURN(SELECT current_user); + +END; +$$ LANGUAGE plpgsql IMMUTABLE; +CREATE TABLE sro_tab (a int); +ALTER TABLE sro_tab OWNER TO regress_sro_user; +INSERT INTO sro_tab VALUES (1), (2), (3); +CREATE INDEX sro_idx ON sro_tab ((sro_ifun(a) + sro_ifun(0))) + WHERE sro_ifun(a + 10) > sro_ifun(10); -- clean up @@ -938,6 +951,10 @@ drop sequence x_seq; +DROP TABLE sro_tab; +DROP ROLE regress_sro_user; + +DROP FUNCTION sro_ifun(int); DROP FUNCTION testfunc2(int); DROP FUNCTION testfunc4(boolean);