1
0
mirror of https://github.com/postgres/postgres.git synced 2025-11-22 12:22:45 +03:00

Make relation-enumerating operations be security-restricted operations.

When a feature enumerates relations and runs functions associated with
all found relations, the feature's user shall not need to trust every
user having permission to create objects.  BRIN-specific functionality
in autovacuum neglected to account for this, as did pg_amcheck and
CLUSTER.  An attacker having permission to create non-temp objects in at
least one schema could execute arbitrary SQL functions under the
identity of the bootstrap superuser.  CREATE INDEX (not a
relation-enumerating operation) and REINDEX protected themselves too
late.  This change extends to the non-enumerating amcheck interface.
Back-patch to v10 (all supported versions).

Sergey Shinderuk, reviewed (in earlier versions) by Alexander Lakhin.
Reported by Alexander Lakhin.

Security: CVE-2022-1552
This commit is contained in:
Noah Misch
2022-05-09 08:35:08 -07:00
parent f45f8b7ff3
commit a117cebd63
10 changed files with 378 additions and 48 deletions

View File

@@ -1445,6 +1445,9 @@ index_concurrently_build(Oid heapRelationId,
Oid indexRelationId)
{
Relation heapRel;
Oid save_userid;
int save_sec_context;
int save_nestlevel;
Relation indexRelation;
IndexInfo *indexInfo;
@@ -1454,7 +1457,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);
/*
@@ -1470,6 +1482,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);
@@ -3299,7 +3317,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);
/*
@@ -3312,16 +3340,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.
*/
@@ -3530,6 +3548,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;
@@ -3557,6 +3578,16 @@ reindex_index(Oid indexId, bool skip_constraint_checks, char persistence,
if (!heapRelation)
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(heapRelation->rd_rel->relowner,
save_sec_context | SECURITY_RESTRICTED_OPERATION);
save_nestlevel = NewGUCNestLevel();
if (progress)
{
const int progress_cols[] = {
@@ -3775,12 +3806,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();
}
/*