aboutsummaryrefslogtreecommitdiff
path: root/src/backend/executor/execUtils.c
diff options
context:
space:
mode:
authorTom Lane <tgl@sss.pgh.pa.us>2007-02-02 00:07:03 +0000
committerTom Lane <tgl@sss.pgh.pa.us>2007-02-02 00:07:03 +0000
commit5413eef8dcd2dbf2cc46eed4f9fe4024987b8a38 (patch)
treeb374d44369cf79d99c8f7d087f8b0b293567c31c /src/backend/executor/execUtils.c
parentf8eb75b6737f00dc1d9b6ca9c50b0cacc576b998 (diff)
downloadpostgresql-5413eef8dcd2dbf2cc46eed4f9fe4024987b8a38.tar.gz
postgresql-5413eef8dcd2dbf2cc46eed4f9fe4024987b8a38.zip
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
Diffstat (limited to 'src/backend/executor/execUtils.c')
-rw-r--r--src/backend/executor/execUtils.c43
1 files changed, 37 insertions, 6 deletions
diff --git a/src/backend/executor/execUtils.c b/src/backend/executor/execUtils.c
index 7b15e153d22..8285b306276 100644
--- a/src/backend/executor/execUtils.c
+++ b/src/backend/executor/execUtils.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/executor/execUtils.c,v 1.142 2007/01/05 22:19:27 momjian Exp $
+ * $PostgreSQL: pgsql/src/backend/executor/execUtils.c,v 1.143 2007/02/02 00:07:03 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -578,12 +578,19 @@ ExecGetResultType(PlanState *planstate)
* econtext, and storing the result into the tuple slot. (Caller must have
* ensured that tuple slot has a descriptor matching the tlist!) Note that
* the given tlist should be a list of ExprState nodes, not Expr nodes.
+ *
+ * inputDesc can be NULL, but if it is not, we check to see whether simple
+ * Vars in the tlist match the descriptor. It is important to provide
+ * inputDesc for relation-scan plan nodes, as a cross check that the relation
+ * hasn't been changed since the plan was made. At higher levels of a plan,
+ * there is no need to recheck.
* ----------------
*/
ProjectionInfo *
ExecBuildProjectionInfo(List *targetList,
ExprContext *econtext,
- TupleTableSlot *slot)
+ TupleTableSlot *slot,
+ TupleDesc inputDesc)
{
ProjectionInfo *projInfo = makeNode(ProjectionInfo);
int len;
@@ -598,14 +605,17 @@ ExecBuildProjectionInfo(List *targetList,
/*
* Determine whether the target list consists entirely of simple Var
- * references (ie, references to non-system attributes). If so, we can
- * use the simpler ExecVariableList instead of ExecTargetList.
+ * references (ie, references to non-system attributes) that match the
+ * input. If so, we can use the simpler ExecVariableList instead of
+ * ExecTargetList. (Note: if there is a type mismatch then ExecEvalVar
+ * will probably throw an error at runtime, but we leave that to it.)
*/
isVarList = true;
foreach(tl, targetList)
{
GenericExprState *gstate = (GenericExprState *) lfirst(tl);
Var *variable = (Var *) gstate->arg->expr;
+ Form_pg_attribute attr;
if (variable == NULL ||
!IsA(variable, Var) ||
@@ -614,6 +624,22 @@ ExecBuildProjectionInfo(List *targetList,
isVarList = false;
break;
}
+ if (!inputDesc)
+ continue; /* can't check type, assume OK */
+ if (variable->varattno > inputDesc->natts)
+ {
+ isVarList = false;
+ break;
+ }
+ attr = inputDesc->attrs[variable->varattno - 1];
+ if (attr->attisdropped ||
+ variable->vartype != attr->atttypid ||
+ (variable->vartypmod != attr->atttypmod &&
+ variable->vartypmod != -1))
+ {
+ isVarList = false;
+ break;
+ }
}
projInfo->pi_isVarList = isVarList;
@@ -689,15 +715,20 @@ ExecBuildProjectionInfo(List *targetList,
* ExecAssignProjectionInfo
*
* forms the projection information from the node's targetlist
+ *
+ * Notes for inputDesc are same as for ExecBuildProjectionInfo: supply it
+ * for a relation-scan node, can pass NULL for upper-level nodes
* ----------------
*/
void
-ExecAssignProjectionInfo(PlanState *planstate)
+ExecAssignProjectionInfo(PlanState *planstate,
+ TupleDesc inputDesc)
{
planstate->ps_ProjInfo =
ExecBuildProjectionInfo(planstate->targetlist,
planstate->ps_ExprContext,
- planstate->ps_ResultTupleSlot);
+ planstate->ps_ResultTupleSlot,
+ inputDesc);
}