mirror of
https://github.com/postgres/postgres.git
synced 2025-11-10 17:42:29 +03:00
Make standard maintenance operations (including VACUUM, ANALYZE, REINDEX,
and CLUSTER) execute as the table owner rather than the calling user, using the same privilege-switching mechanism already used for SECURITY DEFINER functions. The purpose of this change is to ensure that user-defined functions used in index definitions cannot acquire the privileges of a superuser account that is performing routine maintenance. While a function used in an index is supposed to be IMMUTABLE and thus not able to do anything very interesting, there are several easy ways around that restriction; and even if we could plug them all, there would remain a risk of reading sensitive information and broadcasting it through a covert channel such as CPU usage. To prevent bypassing this security measure, execution of SET SESSION AUTHORIZATION and SET ROLE is now forbidden within a SECURITY DEFINER context. Thanks to Itagaki Takahiro for reporting this vulnerability. Security: CVE-2007-6600
This commit is contained in:
@@ -10,7 +10,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/access/transam/xact.c,v 1.255 2008/01/01 19:45:48 momjian Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/access/transam/xact.c,v 1.256 2008/01/03 21:23:15 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -123,7 +123,8 @@ typedef struct TransactionStateData
|
||||
MemoryContext curTransactionContext; /* my xact-lifetime context */
|
||||
ResourceOwner curTransactionOwner; /* my query resources */
|
||||
List *childXids; /* subcommitted child XIDs */
|
||||
Oid currentUser; /* subxact start current_user */
|
||||
Oid prevUser; /* previous CurrentUserId setting */
|
||||
bool prevSecDefCxt; /* previous SecurityDefinerContext setting */
|
||||
bool prevXactReadOnly; /* entry-time xact r/o state */
|
||||
struct TransactionStateData *parent; /* back link to parent */
|
||||
} TransactionStateData;
|
||||
@@ -148,7 +149,8 @@ static TransactionStateData TopTransactionStateData = {
|
||||
NULL, /* cur transaction context */
|
||||
NULL, /* cur transaction resource owner */
|
||||
NIL, /* subcommitted child Xids */
|
||||
0, /* entry-time current userid */
|
||||
InvalidOid, /* previous CurrentUserId setting */
|
||||
false, /* previous SecurityDefinerContext setting */
|
||||
false, /* entry-time xact r/o state */
|
||||
NULL /* link to parent state block */
|
||||
};
|
||||
@@ -1490,19 +1492,15 @@ StartTransaction(void)
|
||||
|
||||
/*
|
||||
* initialize current transaction state fields
|
||||
*
|
||||
* note: prevXactReadOnly is not used at the outermost level
|
||||
*/
|
||||
s->nestingLevel = 1;
|
||||
s->gucNestLevel = 1;
|
||||
s->childXids = NIL;
|
||||
|
||||
/*
|
||||
* You might expect to see "s->currentUser = GetUserId();" here, but you
|
||||
* won't because it doesn't work during startup; the userid isn't set yet
|
||||
* during a backend's first transaction start. We only use the
|
||||
* currentUser field in sub-transaction state structs.
|
||||
*
|
||||
* prevXactReadOnly is also valid only in sub-transactions.
|
||||
*/
|
||||
GetUserIdAndContext(&s->prevUser, &s->prevSecDefCxt);
|
||||
/* SecurityDefinerContext should never be set outside a transaction */
|
||||
Assert(!s->prevSecDefCxt);
|
||||
|
||||
/*
|
||||
* initialize other subsystems for new transaction
|
||||
@@ -1963,17 +1961,16 @@ AbortTransaction(void)
|
||||
s->state = TRANS_ABORT;
|
||||
|
||||
/*
|
||||
* Reset user id which might have been changed transiently. We cannot use
|
||||
* s->currentUser, since it may not be set yet; instead rely on internal
|
||||
* state of miscinit.c.
|
||||
* Reset user ID which might have been changed transiently. We need this
|
||||
* to clean up in case control escaped out of a SECURITY DEFINER function
|
||||
* or other local change of CurrentUserId; therefore, the prior value
|
||||
* of SecurityDefinerContext also needs to be restored.
|
||||
*
|
||||
* (Note: it is not necessary to restore session authorization here
|
||||
* because that can only be changed via GUC, and GUC will take care of
|
||||
* rolling it back if need be. However, an error within a SECURITY
|
||||
* DEFINER function could send control here with the wrong current
|
||||
* userid.)
|
||||
* (Note: it is not necessary to restore session authorization or role
|
||||
* settings here because those can only be changed via GUC, and GUC will
|
||||
* take care of rolling them back if need be.)
|
||||
*/
|
||||
AtAbort_UserId();
|
||||
SetUserIdAndContext(s->prevUser, s->prevSecDefCxt);
|
||||
|
||||
/*
|
||||
* do abort processing
|
||||
@@ -3806,6 +3803,12 @@ AbortSubTransaction(void)
|
||||
|
||||
s->state = TRANS_ABORT;
|
||||
|
||||
/*
|
||||
* Reset user ID which might have been changed transiently. (See notes
|
||||
* in AbortTransaction.)
|
||||
*/
|
||||
SetUserIdAndContext(s->prevUser, s->prevSecDefCxt);
|
||||
|
||||
/*
|
||||
* We can skip all this stuff if the subxact failed before creating a
|
||||
* ResourceOwner...
|
||||
@@ -3858,20 +3861,6 @@ AbortSubTransaction(void)
|
||||
AtEOSubXact_PgStat(false, s->nestingLevel);
|
||||
}
|
||||
|
||||
/*
|
||||
* Reset user id which might have been changed transiently. Here we want
|
||||
* to restore to the userid that was current at subxact entry. (As in
|
||||
* AbortTransaction, we need not worry about the session userid.)
|
||||
*
|
||||
* Must do this after AtEOXact_GUC to handle the case where we entered the
|
||||
* subxact inside a SECURITY DEFINER function (hence current and session
|
||||
* userids were different) and then session auth was changed inside the
|
||||
* subxact. GUC will reset both current and session userids to the
|
||||
* entry-time session userid. This is right in every other scenario so it
|
||||
* seems simplest to let GUC do that and fix it here.
|
||||
*/
|
||||
SetUserId(s->currentUser);
|
||||
|
||||
/*
|
||||
* Restore the upper transaction's read-only state, too. This should be
|
||||
* redundant with GUC's cleanup but we may as well do it for consistency
|
||||
@@ -3926,13 +3915,6 @@ PushTransaction(void)
|
||||
{
|
||||
TransactionState p = CurrentTransactionState;
|
||||
TransactionState s;
|
||||
Oid currentUser;
|
||||
|
||||
/*
|
||||
* At present, GetUserId cannot fail, but let's not assume that. Get the
|
||||
* ID before entering the critical code sequence.
|
||||
*/
|
||||
currentUser = GetUserId();
|
||||
|
||||
/*
|
||||
* We keep subtransaction state nodes in TopTransactionContext.
|
||||
@@ -3966,7 +3948,7 @@ PushTransaction(void)
|
||||
s->savepointLevel = p->savepointLevel;
|
||||
s->state = TRANS_DEFAULT;
|
||||
s->blockState = TBLOCK_SUBBEGIN;
|
||||
s->currentUser = currentUser;
|
||||
GetUserIdAndContext(&s->prevUser, &s->prevSecDefCxt);
|
||||
s->prevXactReadOnly = XactReadOnly;
|
||||
|
||||
CurrentTransactionState = s;
|
||||
|
||||
Reference in New Issue
Block a user