Skip to content

Commit 43d4e96

Browse files
committed
Avoid repeated name lookups during table and index DDL.
If the name lookups come to different conclusions due to concurrent activity, we might perform some parts of the DDL on a different table than other parts. At least in the case of CREATE INDEX, this can be used to cause the permissions checks to be performed against a different table than the index creation, allowing for a privilege escalation attack. This changes the calling convention for DefineIndex, CreateTrigger, transformIndexStmt, transformAlterTableStmt, CheckIndexCompatible (in 9.2 and newer), and AlterTable (in 9.1 and older). In addition, CheckRelationOwnership is removed in 9.2 and newer and the calling convention is changed in older branches. A field has also been added to the Constraint node (FkConstraint in 8.4). Third-party code calling these functions or using the Constraint node will require updating. Report by Andres Freund. Patch by Robert Haas and Andres Freund, reviewed by Tom Lane. Security: CVE-2014-0062
1 parent 0551483 commit 43d4e96

File tree

20 files changed

+230
-118
lines changed

20 files changed

+230
-118
lines changed

src/backend/bootstrap/bootparse.y

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
#include "bootstrap/bootstrap.h"
2828
#include "catalog/catalog.h"
2929
#include "catalog/heap.h"
30+
#include "catalog/namespace.h"
3031
#include "catalog/pg_am.h"
3132
#include "catalog/pg_attribute.h"
3233
#include "catalog/pg_authid.h"
@@ -277,9 +278,14 @@ Boot_InsertStmt:
277278
Boot_DeclareIndexStmt:
278279
XDECLARE INDEX boot_ident oidspec ON boot_ident USING boot_ident LPAREN boot_index_params RPAREN
279280
{
281+
Oid relationId;
282+
280283
do_start();
281284

282-
DefineIndex(makeRangeVar(NULL, $6, -1),
285+
relationId = RangeVarGetRelid(makeRangeVar(NULL, $6, -1),
286+
false);
287+
288+
DefineIndex(relationId,
283289
$3,
284290
$4,
285291
$8,
@@ -295,9 +301,14 @@ Boot_DeclareIndexStmt:
295301
Boot_DeclareUniqueIndexStmt:
296302
XDECLARE UNIQUE INDEX boot_ident oidspec ON boot_ident USING boot_ident LPAREN boot_index_params RPAREN
297303
{
304+
Oid relationId;
305+
298306
do_start();
299307

300-
DefineIndex(makeRangeVar(NULL, $7, -1),
308+
relationId = RangeVarGetRelid(makeRangeVar(NULL, $7, -1),
309+
false);
310+
311+
DefineIndex(relationId,
301312
$4,
302313
$5,
303314
$9,

src/backend/catalog/index.c

Lines changed: 4 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,6 @@ static void validate_index_heapscan(Relation heapRelation,
109109
IndexInfo *indexInfo,
110110
Snapshot snapshot,
111111
v_i_state *state);
112-
static Oid IndexGetRelation(Oid indexId);
113112
static void SetReindexProcessing(Oid heapOid, Oid indexOid);
114113
static void ResetReindexProcessing(void);
115114
static void SetReindexPending(List *indexes);
@@ -806,17 +805,12 @@ index_create(Oid heapRelationId,
806805
*/
807806
if (deferrable)
808807
{
809-
RangeVar *heapRel;
810808
CreateTrigStmt *trigger;
811809

812-
heapRel = makeRangeVar(get_namespace_name(namespaceId),
813-
pstrdup(RelationGetRelationName(heapRelation)),
814-
-1);
815-
816810
trigger = makeNode(CreateTrigStmt);
817811
trigger->trigname = (isprimary ? "PK_ConstraintTrigger" :
818812
"Unique_ConstraintTrigger");
819-
trigger->relation = heapRel;
813+
trigger->relation = NULL;
820814
trigger->funcname = SystemFuncName("unique_key_recheck");
821815
trigger->args = NIL;
822816
trigger->before = false;
@@ -829,8 +823,8 @@ index_create(Oid heapRelationId,
829823
trigger->initdeferred = initdeferred;
830824
trigger->constrrel = NULL;
831825

832-
(void) CreateTrigger(trigger, NULL, conOid, indexRelationId,
833-
true);
826+
(void) CreateTrigger(trigger, NULL, heapRelationId, InvalidOid,
827+
conOid, indexRelationId, true);
834828
}
835829
}
836830
else
@@ -2483,7 +2477,7 @@ index_set_state_flags(Oid indexId, IndexStateFlagsAction action)
24832477
* IndexGetRelation: given an index's relation OID, get the OID of the
24842478
* relation it is an index on. Uses the system cache.
24852479
*/
2486-
static Oid
2480+
Oid
24872481
IndexGetRelation(Oid indexId)
24882482
{
24892483
HeapTuple tuple;

src/backend/catalog/pg_constraint.c

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -726,6 +726,25 @@ AlterConstraintNamespaces(Oid ownerId, Oid oldNspId,
726726
heap_close(conRel, RowExclusiveLock);
727727
}
728728

729+
/*
730+
* get_constraint_relation_oids
731+
* Find the IDs of the relations to which a constraint refers.
732+
*/
733+
void
734+
get_constraint_relation_oids(Oid constraint_oid, Oid *conrelid, Oid *confrelid)
735+
{
736+
HeapTuple tup;
737+
Form_pg_constraint con;
738+
739+
tup = SearchSysCache1(CONSTROID, ObjectIdGetDatum(constraint_oid));
740+
if (!HeapTupleIsValid(tup)) /* should not happen */
741+
elog(ERROR, "cache lookup failed for constraint %u", constraint_oid);
742+
con = (Form_pg_constraint) GETSTRUCT(tup);
743+
*conrelid = con->conrelid;
744+
*confrelid = con->confrelid;
745+
ReleaseSysCache(tup);
746+
}
747+
729748
/*
730749
* GetConstraintByName
731750
* Find a constraint on the specified relation with the specified name.

src/backend/commands/alter.c

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -93,9 +93,8 @@ ExecRenameStmt(RenameStmt *stmt)
9393
{
9494
Oid relid;
9595

96-
CheckRelationOwnership(stmt->relation, true);
97-
9896
relid = RangeVarGetRelid(stmt->relation, false);
97+
CheckRelationOwnership(relid, true);
9998

10099
switch (stmt->renameType)
101100
{
@@ -188,7 +187,6 @@ ExecAlterObjectSchemaStmt(AlterObjectSchemaStmt *stmt)
188187
case OBJECT_SEQUENCE:
189188
case OBJECT_TABLE:
190189
case OBJECT_VIEW:
191-
CheckRelationOwnership(stmt->relation, true);
192190
AlterTableNamespace(stmt->relation, stmt->newschema,
193191
stmt->objectType);
194192
break;

src/backend/commands/indexcmds.c

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,8 @@ static bool relationHasPrimaryKey(Relation rel);
7676
* DefineIndex
7777
* Creates a new index.
7878
*
79-
* 'heapRelation': the relation the index will apply to.
79+
* 'relationId': the OID of the heap relation on which the index is to be
80+
* created
8081
* 'indexRelationName': the name for the new index, or NULL to indicate
8182
* that a nonconflicting default name should be picked.
8283
* 'indexRelationId': normally InvalidOid, but during bootstrap can be
@@ -105,7 +106,7 @@ static bool relationHasPrimaryKey(Relation rel);
105106
* 'concurrent': avoid blocking writers to the table while building.
106107
*/
107108
void
108-
DefineIndex(RangeVar *heapRelation,
109+
DefineIndex(Oid relationId,
109110
char *indexRelationName,
110111
Oid indexRelationId,
111112
char *accessMethodName,
@@ -127,7 +128,6 @@ DefineIndex(RangeVar *heapRelation,
127128
{
128129
Oid *classObjectId;
129130
Oid accessMethodId;
130-
Oid relationId;
131131
Oid namespaceId;
132132
Oid tablespaceId;
133133
List *indexColNames;
@@ -147,6 +147,7 @@ DefineIndex(RangeVar *heapRelation,
147147
int n_old_snapshots;
148148
LockRelId heaprelid;
149149
LOCKTAG heaplocktag;
150+
LOCKMODE lockmode;
150151
Snapshot snapshot;
151152
int i;
152153

@@ -165,14 +166,18 @@ DefineIndex(RangeVar *heapRelation,
165166
INDEX_MAX_KEYS)));
166167

167168
/*
168-
* Open heap relation, acquire a suitable lock on it, remember its OID
169-
*
170169
* Only SELECT ... FOR UPDATE/SHARE are allowed while doing a standard
171170
* index build; but for concurrent builds we allow INSERT/UPDATE/DELETE
172171
* (but not VACUUM).
172+
*
173+
* NB: Caller is responsible for making sure that relationId refers
174+
* to the relation on which the index should be built; except in bootstrap
175+
* mode, this will typically require the caller to have already locked
176+
* the relation. To avoid lock upgrade hazards, that lock should be at
177+
* least as strong as the one we take here.
173178
*/
174-
rel = heap_openrv(heapRelation,
175-
(concurrent ? ShareUpdateExclusiveLock : ShareLock));
179+
lockmode = concurrent ? ShareUpdateExclusiveLock : ShareLock;
180+
rel = heap_open(relationId, lockmode);
176181

177182
relationId = RelationGetRelid(rel);
178183
namespaceId = RelationGetNamespace(rel);
@@ -183,7 +188,7 @@ DefineIndex(RangeVar *heapRelation,
183188
ereport(ERROR,
184189
(errcode(ERRCODE_WRONG_OBJECT_TYPE),
185190
errmsg("\"%s\" is not a table",
186-
heapRelation->relname)));
191+
RelationGetRelationName(rel))));
187192

188193
/*
189194
* Don't try to CREATE INDEX on temp tables of other backends.
@@ -567,7 +572,7 @@ DefineIndex(RangeVar *heapRelation,
567572
*/
568573

569574
/* Open and lock the parent heap relation */
570-
rel = heap_openrv(heapRelation, ShareUpdateExclusiveLock);
575+
rel = heap_open(relationId, ShareUpdateExclusiveLock);
571576

572577
/* And the target index relation */
573578
indexRelation = index_open(indexRelationId, RowExclusiveLock);

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy