|
|
|
@ -8,18 +8,15 @@ |
|
|
|
|
* |
|
|
|
|
* |
|
|
|
|
* IDENTIFICATION |
|
|
|
|
* $PostgreSQL: pgsql/src/backend/parser/parse_func.c,v 1.226 2010/08/05 21:45:35 tgl Exp $ |
|
|
|
|
* $PostgreSQL: pgsql/src/backend/parser/parse_func.c,v 1.227 2010/09/03 01:26:52 tgl Exp $ |
|
|
|
|
* |
|
|
|
|
*------------------------------------------------------------------------- |
|
|
|
|
*/ |
|
|
|
|
#include "postgres.h" |
|
|
|
|
|
|
|
|
|
#include "catalog/pg_attrdef.h" |
|
|
|
|
#include "catalog/pg_constraint.h" |
|
|
|
|
#include "catalog/pg_proc.h" |
|
|
|
|
#include "catalog/pg_type.h" |
|
|
|
|
#include "funcapi.h" |
|
|
|
|
#include "miscadmin.h" |
|
|
|
|
#include "nodes/makefuncs.h" |
|
|
|
|
#include "nodes/nodeFuncs.h" |
|
|
|
|
#include "parser/parse_agg.h" |
|
|
|
@ -29,7 +26,6 @@ |
|
|
|
|
#include "parser/parse_target.h" |
|
|
|
|
#include "parser/parse_type.h" |
|
|
|
|
#include "utils/builtins.h" |
|
|
|
|
#include "utils/fmgroids.h" |
|
|
|
|
#include "utils/lsyscache.h" |
|
|
|
|
#include "utils/syscache.h" |
|
|
|
|
|
|
|
|
@ -511,9 +507,6 @@ ParseFuncOrColumn(ParseState *pstate, List *funcname, List *fargs, |
|
|
|
|
retval = (Node *) wfunc; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/* Hack to protect pg_get_expr() against misuse */ |
|
|
|
|
check_pg_get_expr_args(pstate, funcid, fargs); |
|
|
|
|
|
|
|
|
|
return retval; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
@ -1600,107 +1593,3 @@ LookupAggNameTypeNames(List *aggname, List *argtypes, bool noError) |
|
|
|
|
|
|
|
|
|
return oid; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* 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. 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 aren't many clients doing that out there. |
|
|
|
|
*/ |
|
|
|
|
void |
|
|
|
|
check_pg_get_expr_args(ParseState *pstate, Oid fnoid, List *args) |
|
|
|
|
{ |
|
|
|
|
bool allowed = false; |
|
|
|
|
Node *arg; |
|
|
|
|
int netlevelsup; |
|
|
|
|
|
|
|
|
|
/* if not being called for pg_get_expr, do nothing */ |
|
|
|
|
if (fnoid != F_PG_GET_EXPR && fnoid != F_PG_GET_EXPR_EXT) |
|
|
|
|
return; |
|
|
|
|
|
|
|
|
|
/* superusers are allowed to call it anyway (dubious) */ |
|
|
|
|
if (superuser()) |
|
|
|
|
return; |
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* The first argument must be a Var referencing one of the allowed |
|
|
|
|
* system-catalog columns. It could be a join alias Var, though. |
|
|
|
|
*/ |
|
|
|
|
Assert(list_length(args) > 1); |
|
|
|
|
arg = (Node *) linitial(args); |
|
|
|
|
netlevelsup = 0; |
|
|
|
|
|
|
|
|
|
restart: |
|
|
|
|
if (IsA(arg, Var)) |
|
|
|
|
{ |
|
|
|
|
Var *var = (Var *) arg; |
|
|
|
|
RangeTblEntry *rte; |
|
|
|
|
|
|
|
|
|
netlevelsup += var->varlevelsup; |
|
|
|
|
rte = GetRTEByRangeTablePosn(pstate, var->varno, netlevelsup); |
|
|
|
|
|
|
|
|
|
if (rte->rtekind == RTE_JOIN) |
|
|
|
|
{ |
|
|
|
|
/* Expand join alias reference */ |
|
|
|
|
if (var->varattno > 0 && |
|
|
|
|
var->varattno <= list_length(rte->joinaliasvars)) |
|
|
|
|
{ |
|
|
|
|
arg = (Node *) list_nth(rte->joinaliasvars, var->varattno - 1); |
|
|
|
|
goto restart; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
else if (rte->rtekind == RTE_RELATION) |
|
|
|
|
{ |
|
|
|
|
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 ProcedureRelationId: |
|
|
|
|
if (var->varattno == Anum_pg_proc_proargdefaults) |
|
|
|
|
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"))); |
|
|
|
|
} |
|
|
|
|