diff --git a/src/backend/parser/parse_expr.c b/src/backend/parser/parse_expr.c index e5ba730874..36d7bddc43 100644 --- a/src/backend/parser/parse_expr.c +++ b/src/backend/parser/parse_expr.c @@ -8,13 +8,15 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/parser/parse_expr.c,v 1.198.2.2 2008/10/26 02:46:36 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/parser/parse_expr.c,v 1.198.2.3 2010/06/30 18:11:04 heikki Exp $ * *------------------------------------------------------------------------- */ #include "postgres.h" +#include "catalog/pg_attrdef.h" +#include "catalog/pg_constraint.h" #include "catalog/pg_type.h" #include "commands/dbcommands.h" #include "mb/pg_wchar.h" @@ -33,6 +35,7 @@ #include "parser/parse_target.h" #include "parser/parse_type.h" #include "utils/builtins.h" +#include "utils/fmgroids.h" #include "utils/lsyscache.h" @@ -956,6 +959,7 @@ transformFuncCall(ParseState *pstate, FuncCall *fn) { List *targs; ListCell *args; + Node *result; /* * Transform the list of arguments. We use a shallow list copy and then @@ -971,13 +975,88 @@ transformFuncCall(ParseState *pstate, FuncCall *fn) (Node *) lfirst(args)); } - return ParseFuncOrColumn(pstate, + result = ParseFuncOrColumn(pstate, fn->funcname, targs, fn->agg_star, fn->agg_distinct, false, fn->location); + + /* + * pg_get_expr() is a system function that exposes the expression + * deparsing functionality in ruleutils.c to users. Very handy, but + * it was later realized that the functions in ruleutils.c don't check + * the input rigorously, assuming it to come from system catalogs and + * to therefore be valid. That makes it easy for a user to crash the + * backend by passing a maliciously crafted string representation of + * an expression to pg_get_expr(). + * + * There's a lot of code in ruleutils.c, so it's not feasible to add + * water-proof input checking after the fact. Even if we did it once, + * it would need to be taken into account in any future patches too. + * + * Instead, we restrict pg_rule_expr() to only allow input from system + * catalogs instead. This is a hack, but it's the most robust and easiest + * to backpatch way of plugging the vulnerability. + * + * This is transparent to the typical usage pattern of + * "pg_get_expr(systemcolumn, ...)", but will break + * "pg_get_expr('foo', ...)", even if 'foo' is a valid expression fetched + * earlier from a system catalog. Hopefully there's isn't many clients + * doing that out there. + */ + if (result && IsA(result, FuncExpr) && !superuser()) + { + FuncExpr *fe = (FuncExpr *) result; + if (fe->funcid == F_PG_GET_EXPR || fe->funcid == F_PG_GET_EXPR_EXT) + { + Expr *arg = linitial(fe->args); + bool allowed = false; + + /* + * Check that the argument came directly from one of the + * allowed system catalog columns + */ + if (IsA(arg, Var)) + { + Var *var = (Var *) arg; + RangeTblEntry *rte; + + rte = GetRTEByRangeTablePosn(pstate, + var->varno, var->varlevelsup); + + switch(rte->relid) + { + case IndexRelationId: + if (var->varattno == Anum_pg_index_indexprs || + var->varattno == Anum_pg_index_indpred) + allowed = true; + break; + + case AttrDefaultRelationId: + if (var->varattno == Anum_pg_attrdef_adbin) + allowed = true; + break; + + case ConstraintRelationId: + if (var->varattno == Anum_pg_constraint_conbin) + allowed = true; + break; + + case TypeRelationId: + if (var->varattno == Anum_pg_type_typdefaultbin) + allowed = true; + break; + } + } + if (!allowed) + ereport(ERROR, + (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), + errmsg("argument to pg_get_expr() must come from system catalogs"))); + } + } + return result; } static Node * diff --git a/src/backend/tcop/fastpath.c b/src/backend/tcop/fastpath.c index 7bd91eee07..1cc43a7bdb 100644 --- a/src/backend/tcop/fastpath.c +++ b/src/backend/tcop/fastpath.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/tcop/fastpath.c,v 1.94 2006/10/19 22:44:11 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/tcop/fastpath.c,v 1.94.2.1 2010/06/30 18:11:04 heikki Exp $ * * NOTES * This cruft is the server side of PQfn. @@ -29,6 +29,7 @@ #include "tcop/fastpath.h" #include "tcop/tcopprot.h" #include "utils/acl.h" +#include "utils/fmgroids.h" #include "utils/lsyscache.h" #include "utils/syscache.h" @@ -348,6 +349,16 @@ HandleFunctionRequest(StringInfo msgBuf) aclcheck_error(aclresult, ACL_KIND_PROC, get_func_name(fid)); + /* + * Restrict access to pg_get_expr(). This reflects the hack in + * transformFuncCall() in parse_expr.c, see comments there for an + * explanation. + */ + if ((fid == F_PG_GET_EXPR || fid == F_PG_GET_EXPR_EXT) && !superuser()) + ereport(ERROR, + (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), + errmsg("argument to pg_get_expr() must come from system catalogs"))); + /* * Prepare function call info block and insert arguments. */