From 8f36605efc5fdf3cfcfe69f33b6fce524fd84a53 Mon Sep 17 00:00:00 2001 From: Heikki Linnakangas Date: Wed, 30 Jun 2010 18:11:32 +0000 Subject: stringToNode() and deparse_expression_pretty() crash on invalid input, but we have nevertheless exposed them to users via pg_get_expr(). It would be too much maintenance effort to rigorously check the input, so put a hack in place instead to restrict pg_get_expr() so that the argument must come from one of the system catalog columns known to contain valid expressions. Per report from Rushabh Lathia. Backpatch to 7.4 which is the oldest supported version at the moment. --- src/backend/parser/parse_expr.c | 82 ++++++++++++++++++++++++++++++++++++++++- 1 file changed, 81 insertions(+), 1 deletion(-) (limited to 'src/backend/parser/parse_expr.c') diff --git a/src/backend/parser/parse_expr.c b/src/backend/parser/parse_expr.c index f95e58593a4..ff4d43caf0d 100644 --- a/src/backend/parser/parse_expr.c +++ b/src/backend/parser/parse_expr.c @@ -8,13 +8,16 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/parser/parse_expr.c,v 1.179.4.3 2005/11/18 23:08:28 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/parser/parse_expr.c,v 1.179.4.4 2010/06/30 18:11:31 heikki Exp $ * *------------------------------------------------------------------------- */ #include "postgres.h" +#include "catalog/catname.h" +#include "catalog/pg_attrdef.h" +#include "catalog/pg_constraint.h" #include "catalog/pg_operator.h" #include "catalog/pg_proc.h" #include "commands/dbcommands.h" @@ -32,6 +35,7 @@ #include "parser/parse_relation.h" #include "parser/parse_type.h" #include "utils/builtins.h" +#include "utils/fmgroids.h" #include "utils/lsyscache.h" #include "utils/syscache.h" @@ -435,6 +439,82 @@ transformExpr(ParseState *pstate, Node *expr) fn->agg_star, fn->agg_distinct, false); + + /* + * 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); + + if (rte->relid == get_system_catalog_relid(IndexRelationName)) + { + if (var->varattno == Anum_pg_index_indexprs || + var->varattno == Anum_pg_index_indpred) + allowed = true; + } + else if (rte->relid == get_system_catalog_relid(AttrDefaultRelationName)) + { + if (var->varattno == Anum_pg_attrdef_adbin) + allowed = true; + } + else if (rte->relid == get_system_catalog_relid(ConstraintRelationName)) + { + if (var->varattno == Anum_pg_constraint_conbin) + allowed = true; + } + else if (rte->relid == get_system_catalog_relid(TypeRelationName)) + { + if (var->varattno == Anum_pg_type_typdefaultbin) + allowed = true; + } + } + if (!allowed) + ereport(ERROR, + (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), + errmsg("argument to pg_get_expr() must come from system catalogs"))); + } + } break; } case T_SubLink: -- cgit v1.2.3