Skip to content

Commit e464761

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 09e2d4c commit e464761

File tree

20 files changed

+232
-114
lines changed

20 files changed

+232
-114
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"
@@ -257,9 +258,14 @@ Boot_InsertStmt:
257258
Boot_DeclareIndexStmt:
258259
XDECLARE INDEX boot_ident oidspec ON boot_ident USING boot_ident LPAREN boot_index_params RPAREN
259260
{
261+
Oid relationId;
262+
260263
do_start();
261264

262-
DefineIndex(makeRangeVar(NULL, LexIDStr($6), -1),
265+
relationId = RangeVarGetRelid(makeRangeVar(NULL, LexIDStr($6), -1),
266+
false);
267+
268+
DefineIndex(relationId,
263269
LexIDStr($3),
264270
$4,
265271
LexIDStr($8),
@@ -275,9 +281,14 @@ Boot_DeclareIndexStmt:
275281
Boot_DeclareUniqueIndexStmt:
276282
XDECLARE UNIQUE INDEX boot_ident oidspec ON boot_ident USING boot_ident LPAREN boot_index_params RPAREN
277283
{
284+
Oid relationId;
285+
278286
do_start();
279287

280-
DefineIndex(makeRangeVar(NULL, LexIDStr($7), -1),
288+
relationId = RangeVarGetRelid(makeRangeVar(NULL, LexIDStr($7), -1),
289+
false);
290+
291+
DefineIndex(relationId,
281292
LexIDStr($4),
282293
$5,
283294
LexIDStr($9),

src/backend/catalog/index.c

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,6 @@ static void validate_index_heapscan(Relation heapRelation,
9696
IndexInfo *indexInfo,
9797
Snapshot snapshot,
9898
v_i_state *state);
99-
static Oid IndexGetRelation(Oid indexId);
10099

101100

102101
/*
@@ -2319,7 +2318,7 @@ index_set_state_flags(Oid indexId, IndexStateFlagsAction action)
23192318
* IndexGetRelation: given an index's relation OID, get the OID of the
23202319
* relation it is an index on. Uses the system cache.
23212320
*/
2322-
static Oid
2321+
Oid
23232322
IndexGetRelation(Oid indexId)
23242323
{
23252324
HeapTuple tuple;

src/backend/catalog/pg_constraint.c

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -699,3 +699,22 @@ AlterConstraintNamespaces(Oid ownerId, Oid oldNspId,
699699

700700
heap_close(conRel, RowExclusiveLock);
701701
}
702+
703+
/*
704+
* get_constraint_relation_oids
705+
* Find the IDs of the relations to which a constraint refers.
706+
*/
707+
void
708+
get_constraint_relation_oids(Oid constraint_oid, Oid *conrelid, Oid *confrelid)
709+
{
710+
HeapTuple tup;
711+
Form_pg_constraint con;
712+
713+
tup = SearchSysCache(CONSTROID, ObjectIdGetDatum(constraint_oid), 0, 0, 0);
714+
if (!HeapTupleIsValid(tup)) /* should not happen */
715+
elog(ERROR, "cache lookup failed for constraint %u", constraint_oid);
716+
con = (Form_pg_constraint) GETSTRUCT(tup);
717+
*conrelid = con->conrelid;
718+
*confrelid = con->confrelid;
719+
ReleaseSysCache(tup);
720+
}

src/backend/commands/alter.c

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

94-
CheckRelationOwnership(stmt->relation, true);
95-
9694
relid = RangeVarGetRelid(stmt->relation, false);
95+
CheckRelationOwnership(relid, true);
9796

9897
switch (stmt->renameType)
9998
{
@@ -186,7 +185,6 @@ ExecAlterObjectSchemaStmt(AlterObjectSchemaStmt *stmt)
186185
case OBJECT_SEQUENCE:
187186
case OBJECT_TABLE:
188187
case OBJECT_VIEW:
189-
CheckRelationOwnership(stmt->relation, true);
190188
AlterTableNamespace(stmt->relation, stmt->newschema,
191189
stmt->objectType);
192190
break;

src/backend/commands/indexcmds.c

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,8 @@ static bool relationHasPrimaryKey(Relation rel);
7272
* DefineIndex
7373
* Creates a new index.
7474
*
75-
* 'heapRelation': the relation the index will apply to.
75+
* 'relationId': the OID of the heap relation on which the index is to be
76+
* created
7677
* 'indexRelationName': the name for the new index, or NULL to indicate
7778
* that a nonconflicting default name should be picked.
7879
* 'indexRelationId': normally InvalidOid, but during bootstrap can be
@@ -97,7 +98,7 @@ static bool relationHasPrimaryKey(Relation rel);
9798
* 'concurrent': avoid blocking writers to the table while building.
9899
*/
99100
void
100-
DefineIndex(RangeVar *heapRelation,
101+
DefineIndex(Oid relationId,
101102
char *indexRelationName,
102103
Oid indexRelationId,
103104
char *accessMethodName,
@@ -116,7 +117,6 @@ DefineIndex(RangeVar *heapRelation,
116117
{
117118
Oid *classObjectId;
118119
Oid accessMethodId;
119-
Oid relationId;
120120
Oid namespaceId;
121121
Oid tablespaceId;
122122
Relation rel;
@@ -135,6 +135,7 @@ DefineIndex(RangeVar *heapRelation,
135135
int n_old_snapshots;
136136
LockRelId heaprelid;
137137
LOCKTAG heaplocktag;
138+
LOCKMODE lockmode;
138139
Snapshot snapshot;
139140
int i;
140141

@@ -153,14 +154,18 @@ DefineIndex(RangeVar *heapRelation,
153154
INDEX_MAX_KEYS)));
154155

155156
/*
156-
* Open heap relation, acquire a suitable lock on it, remember its OID
157-
*
158157
* Only SELECT ... FOR UPDATE/SHARE are allowed while doing a standard
159158
* index build; but for concurrent builds we allow INSERT/UPDATE/DELETE
160159
* (but not VACUUM).
160+
*
161+
* NB: Caller is responsible for making sure that relationId refers
162+
* to the relation on which the index should be built; except in bootstrap
163+
* mode, this will typically require the caller to have already locked
164+
* the relation. To avoid lock upgrade hazards, that lock should be at
165+
* least as strong as the one we take here.
161166
*/
162-
rel = heap_openrv(heapRelation,
163-
(concurrent ? ShareUpdateExclusiveLock : ShareLock));
167+
lockmode = concurrent ? ShareUpdateExclusiveLock : ShareLock;
168+
rel = heap_open(relationId, lockmode);
164169

165170
relationId = RelationGetRelid(rel);
166171
namespaceId = RelationGetNamespace(rel);
@@ -171,7 +176,7 @@ DefineIndex(RangeVar *heapRelation,
171176
ereport(ERROR,
172177
(errcode(ERRCODE_WRONG_OBJECT_TYPE),
173178
errmsg("\"%s\" is not a table",
174-
heapRelation->relname)));
179+
RelationGetRelationName(rel))));
175180

176181
/*
177182
* Don't try to CREATE INDEX on temp tables of other backends.
@@ -537,7 +542,7 @@ DefineIndex(RangeVar *heapRelation,
537542
*/
538543

539544
/* Open and lock the parent heap relation */
540-
rel = heap_openrv(heapRelation, ShareUpdateExclusiveLock);
545+
rel = heap_open(relationId, ShareUpdateExclusiveLock);
541546

542547
/* And the target index relation */
543548
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