Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit 5413eef

Browse files
committed
Repair failure to check that a table is still compatible with a previously
made query plan. Use of ALTER COLUMN TYPE creates a hazard for cached query plans: they could contain Vars that claim a column has a different type than it now has. Fix this by checking during plan startup that Vars at relation scan level match the current relation tuple descriptor. Since at that point we already have at least AccessShareLock, we can be sure the column type will not change underneath us later in the query. However, since a backend's locks do not conflict against itself, there is still a hole for an attacker to exploit: he could try to execute ALTER COLUMN TYPE while a query is in progress in the current backend. Seal that hole by rejecting ALTER TABLE whenever the target relation is already open in the current backend. This is a significant security hole: not only can one trivially crash the backend, but with appropriate misuse of pass-by-reference datatypes it is possible to read out arbitrary locations in the server process's memory, which could allow retrieving database content the user should not be able to see. Our thanks to Jeff Trout for the initial report. Security: CVE-2007-0556
1 parent f8eb75b commit 5413eef

File tree

13 files changed

+311
-90
lines changed

13 files changed

+311
-90
lines changed

src/backend/commands/tablecmds.c

Lines changed: 50 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
*
99
*
1010
* IDENTIFICATION
11-
* $PostgreSQL: pgsql/src/backend/commands/tablecmds.c,v 1.212 2007/01/25 04:35:10 momjian Exp $
11+
* $PostgreSQL: pgsql/src/backend/commands/tablecmds.c,v 1.213 2007/02/02 00:07:02 tgl Exp $
1212
*
1313
*-------------------------------------------------------------------------
1414
*/
@@ -1964,22 +1964,47 @@ update_ri_trigger_args(Oid relid,
19641964
void
19651965
AlterTable(AlterTableStmt *stmt)
19661966
{
1967-
ATController(relation_openrv(stmt->relation, AccessExclusiveLock),
1968-
stmt->cmds,
1969-
interpretInhOption(stmt->relation->inhOpt));
1967+
Relation rel = relation_openrv(stmt->relation, AccessExclusiveLock);
1968+
int expected_refcnt;
1969+
1970+
/*
1971+
* Disallow ALTER TABLE when the current backend has any open reference
1972+
* to it besides the one we just got (such as an open cursor or active
1973+
* plan); our AccessExclusiveLock doesn't protect us against stomping on
1974+
* our own foot, only other people's feet!
1975+
*
1976+
* Note: the only case known to cause serious trouble is ALTER COLUMN TYPE,
1977+
* and some changes are obviously pretty benign, so this could possibly
1978+
* be relaxed to only error out for certain types of alterations. But
1979+
* the use-case for allowing any of these things is not obvious, so we
1980+
* won't work hard at it for now.
1981+
*/
1982+
expected_refcnt = rel->rd_isnailed ? 2 : 1;
1983+
if (rel->rd_refcnt != expected_refcnt)
1984+
ereport(ERROR,
1985+
(errcode(ERRCODE_OBJECT_IN_USE),
1986+
errmsg("relation \"%s\" is being used by active queries in this session",
1987+
RelationGetRelationName(rel))));
1988+
1989+
ATController(rel, stmt->cmds, interpretInhOption(stmt->relation->inhOpt));
19701990
}
19711991

19721992
/*
19731993
* AlterTableInternal
19741994
*
19751995
* ALTER TABLE with target specified by OID
1996+
*
1997+
* We do not reject if the relation is already open, because it's quite
1998+
* likely that one or more layers of caller have it open. That means it
1999+
* is unsafe to use this entry point for alterations that could break
2000+
* existing query plans.
19762001
*/
19772002
void
19782003
AlterTableInternal(Oid relid, List *cmds, bool recurse)
19792004
{
1980-
ATController(relation_open(relid, AccessExclusiveLock),
1981-
cmds,
1982-
recurse);
2005+
Relation rel = relation_open(relid, AccessExclusiveLock);
2006+
2007+
ATController(rel, cmds, recurse);
19832008
}
19842009

19852010
static void
@@ -2929,6 +2954,12 @@ ATSimpleRecursion(List **wqueue, Relation rel,
29292954
if (childrelid == relid)
29302955
continue;
29312956
childrel = relation_open(childrelid, AccessExclusiveLock);
2957+
/* check for child relation in use in this session */
2958+
if (childrel->rd_refcnt != 1)
2959+
ereport(ERROR,
2960+
(errcode(ERRCODE_OBJECT_IN_USE),
2961+
errmsg("relation \"%s\" is being used by active queries in this session",
2962+
RelationGetRelationName(childrel))));
29322963
ATPrepCmd(wqueue, childrel, cmd, false, true);
29332964
relation_close(childrel, NoLock);
29342965
}
@@ -2960,6 +2991,12 @@ ATOneLevelRecursion(List **wqueue, Relation rel,
29602991
Relation childrel;
29612992

29622993
childrel = relation_open(childrelid, AccessExclusiveLock);
2994+
/* check for child relation in use in this session */
2995+
if (childrel->rd_refcnt != 1)
2996+
ereport(ERROR,
2997+
(errcode(ERRCODE_OBJECT_IN_USE),
2998+
errmsg("relation \"%s\" is being used by active queries in this session",
2999+
RelationGetRelationName(childrel))));
29633000
ATPrepCmd(wqueue, childrel, cmd, true, true);
29643001
relation_close(childrel, NoLock);
29653002
}
@@ -3765,6 +3802,12 @@ ATExecDropColumn(Relation rel, const char *colName,
37653802
Form_pg_attribute childatt;
37663803

37673804
childrel = heap_open(childrelid, AccessExclusiveLock);
3805+
/* check for child relation in use in this session */
3806+
if (childrel->rd_refcnt != 1)
3807+
ereport(ERROR,
3808+
(errcode(ERRCODE_OBJECT_IN_USE),
3809+
errmsg("relation \"%s\" is being used by active queries in this session",
3810+
RelationGetRelationName(childrel))));
37683811

37693812
tuple = SearchSysCacheCopyAttName(childrelid, colName);
37703813
if (!HeapTupleIsValid(tuple)) /* shouldn't happen */

src/backend/executor/execMain.c

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@
2626
*
2727
*
2828
* IDENTIFICATION
29-
* $PostgreSQL: pgsql/src/backend/executor/execMain.c,v 1.285 2007/01/25 04:35:10 momjian Exp $
29+
* $PostgreSQL: pgsql/src/backend/executor/execMain.c,v 1.286 2007/02/02 00:07:02 tgl Exp $
3030
*
3131
*-------------------------------------------------------------------------
3232
*/
@@ -804,7 +804,8 @@ InitPlan(QueryDesc *queryDesc, int eflags)
804804

805805
rliststate = (List *) ExecInitExpr((Expr *) rlist, planstate);
806806
resultRelInfo->ri_projectReturning =
807-
ExecBuildProjectionInfo(rliststate, econtext, slot);
807+
ExecBuildProjectionInfo(rliststate, econtext, slot,
808+
resultRelInfo->ri_RelationDesc->rd_att);
808809
resultRelInfo++;
809810
}
810811

0 commit comments

Comments
 (0)