diff options
Diffstat (limited to 'src/backend/commands')
-rw-r--r-- | src/backend/commands/cluster.c | 37 | ||||
-rw-r--r-- | src/backend/commands/indexcmds.c | 98 |
2 files changed, 111 insertions, 24 deletions
diff --git a/src/backend/commands/cluster.c b/src/backend/commands/cluster.c index 7cc08f18cf3..33718aad436 100644 --- a/src/backend/commands/cluster.c +++ b/src/backend/commands/cluster.c @@ -277,6 +277,9 @@ void cluster_rel(Oid tableOid, Oid indexOid, ClusterParams *params) { Relation OldHeap; + Oid save_userid; + int save_sec_context; + int save_nestlevel; bool verbose = ((params->options & CLUOPT_VERBOSE) != 0); bool recheck = ((params->options & CLUOPT_RECHECK) != 0); @@ -307,6 +310,16 @@ cluster_rel(Oid tableOid, Oid indexOid, ClusterParams *params) } /* + * 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. * @@ -317,11 +330,10 @@ cluster_rel(Oid tableOid, Oid indexOid, ClusterParams *params) if (recheck) { /* 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; } /* @@ -335,8 +347,7 @@ cluster_rel(Oid tableOid, Oid indexOid, ClusterParams *params) if (RELATION_IS_OTHER_TEMP(OldHeap)) { relation_close(OldHeap, AccessExclusiveLock); - pgstat_progress_end_command(); - return; + goto out; } if (OidIsValid(indexOid)) @@ -347,8 +358,7 @@ cluster_rel(Oid tableOid, Oid indexOid, ClusterParams *params) if (!SearchSysCacheExists1(RELOID, ObjectIdGetDatum(indexOid))) { relation_close(OldHeap, AccessExclusiveLock); - pgstat_progress_end_command(); - return; + goto out; } /* @@ -357,8 +367,7 @@ cluster_rel(Oid tableOid, Oid indexOid, ClusterParams *params) if (!get_index_isclustered(indexOid)) { relation_close(OldHeap, AccessExclusiveLock); - pgstat_progress_end_command(); - return; + goto out; } } } @@ -411,8 +420,7 @@ cluster_rel(Oid tableOid, Oid indexOid, ClusterParams *params) !RelationIsPopulated(OldHeap)) { relation_close(OldHeap, AccessExclusiveLock); - pgstat_progress_end_command(); - return; + goto out; } /* @@ -428,6 +436,13 @@ cluster_rel(Oid tableOid, Oid indexOid, ClusterParams *params) /* 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 76774dce064..ca150452c1c 100644 --- a/src/backend/commands/indexcmds.c +++ b/src/backend/commands/indexcmds.c @@ -547,21 +547,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 @@ -640,6 +641,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 */ @@ -725,7 +735,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, @@ -757,7 +767,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, @@ -1147,15 +1157,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 */ @@ -1165,6 +1177,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, @@ -1211,6 +1234,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; AttrMap *attmap; @@ -1218,6 +1244,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 @@ -1233,6 +1265,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; } @@ -1304,6 +1339,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); /* @@ -1360,12 +1398,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, @@ -1402,12 +1449,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 */ @@ -3536,6 +3588,9 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params) Oid newIndexId; Relation indexRel; Relation heapRel; + Oid save_userid; + int save_sec_context; + int save_nestlevel; Relation newIndexRel; LockRelId *lockrelid; Oid tablespaceid; @@ -3544,6 +3599,16 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params) 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(); + /* determine safety of this index for set_indexsafe_procflags */ idx->safe = (indexRel->rd_indexprs == NIL && indexRel->rd_indpred == NIL); @@ -3619,6 +3684,13 @@ ReindexRelationConcurrently(Oid relationOid, ReindexParams *params) 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); } |