88 *
99 *
1010 * IDENTIFICATION
11- * $PostgreSQL: pgsql/src/backend/parser/parse_expr.c,v 1.254 2010/02/26 02:00:52 momjian Exp $
11+ * $PostgreSQL: pgsql/src/backend/parser/parse_expr.c,v 1.255 2010/06/30 18:10:23 heikki Exp $
1212 *
1313 *-------------------------------------------------------------------------
1414 */
1515
1616#include "postgres.h"
1717
18+ #include "catalog/pg_attrdef.h"
19+ #include "catalog/pg_constraint.h"
20+ #include "catalog/pg_proc.h"
1821#include "catalog/pg_type.h"
1922#include "commands/dbcommands.h"
2023#include "miscadmin.h"
3033#include "parser/parse_target.h"
3134#include "parser/parse_type.h"
3235#include "utils/builtins.h"
36+ #include "utils/fmgroids.h"
3337#include "utils/lsyscache.h"
3438#include "utils/xml.h"
3539
@@ -1210,6 +1214,7 @@ transformFuncCall(ParseState *pstate, FuncCall *fn)
12101214{
12111215 List * targs ;
12121216 ListCell * args ;
1217+ Node * result ;
12131218
12141219 /* Transform the list of arguments ... */
12151220 targs = NIL ;
@@ -1220,7 +1225,7 @@ transformFuncCall(ParseState *pstate, FuncCall *fn)
12201225 }
12211226
12221227 /* ... and hand off to ParseFuncOrColumn */
1223- return ParseFuncOrColumn (pstate ,
1228+ result = ParseFuncOrColumn (pstate ,
12241229 fn -> funcname ,
12251230 targs ,
12261231 fn -> agg_order ,
@@ -1230,6 +1235,86 @@ transformFuncCall(ParseState *pstate, FuncCall *fn)
12301235 fn -> over ,
12311236 false,
12321237 fn -> location );
1238+
1239+ /*
1240+ * pg_get_expr() is a system function that exposes the expression
1241+ * deparsing functionality in ruleutils.c to users. Very handy, but
1242+ * it was later realized that the functions in ruleutils.c don't check
1243+ * the input rigorously, assuming it to come from system catalogs and
1244+ * to therefore be valid. That makes it easy for a user to crash the
1245+ * backend by passing a maliciously crafted string representation of
1246+ * an expression to pg_get_expr().
1247+ *
1248+ * There's a lot of code in ruleutils.c, so it's not feasible to add
1249+ * water-proof input checking after the fact. Even if we did it once,
1250+ * it would need to be taken into account in any future patches too.
1251+ *
1252+ * Instead, we restrict pg_rule_expr() to only allow input from system
1253+ * catalogs instead. This is a hack, but it's the most robust and easiest
1254+ * to backpatch way of plugging the vulnerability.
1255+ *
1256+ * This is transparent to the typical usage pattern of
1257+ * "pg_get_expr(systemcolumn, ...)", but will break
1258+ * "pg_get_expr('foo', ...)", even if 'foo' is a valid expression fetched
1259+ * earlier from a system catalog. Hopefully there's isn't many clients
1260+ * doing that out there.
1261+ */
1262+ if (result && IsA (result , FuncExpr ) && !superuser ())
1263+ {
1264+ FuncExpr * fe = (FuncExpr * ) result ;
1265+ if (fe -> funcid == F_PG_GET_EXPR || fe -> funcid == F_PG_GET_EXPR_EXT )
1266+ {
1267+ Expr * arg = linitial (fe -> args );
1268+ bool allowed = false;
1269+
1270+ /*
1271+ * Check that the argument came directly from one of the
1272+ * allowed system catalog columns
1273+ */
1274+ if (IsA (arg , Var ))
1275+ {
1276+ Var * var = (Var * ) arg ;
1277+ RangeTblEntry * rte ;
1278+
1279+ rte = GetRTEByRangeTablePosn (pstate ,
1280+ var -> varno , var -> varlevelsup );
1281+
1282+ switch (rte -> relid )
1283+ {
1284+ case IndexRelationId :
1285+ if (var -> varattno == Anum_pg_index_indexprs ||
1286+ var -> varattno == Anum_pg_index_indpred )
1287+ allowed = true;
1288+ break ;
1289+
1290+ case AttrDefaultRelationId :
1291+ if (var -> varattno == Anum_pg_attrdef_adbin )
1292+ allowed = true;
1293+ break ;
1294+
1295+ case ProcedureRelationId :
1296+ if (var -> varattno == Anum_pg_proc_proargdefaults )
1297+ allowed = true;
1298+ break ;
1299+
1300+ case ConstraintRelationId :
1301+ if (var -> varattno == Anum_pg_constraint_conbin )
1302+ allowed = true;
1303+ break ;
1304+
1305+ case TypeRelationId :
1306+ if (var -> varattno == Anum_pg_type_typdefaultbin )
1307+ allowed = true;
1308+ break ;
1309+ }
1310+ }
1311+ if (!allowed )
1312+ ereport (ERROR ,
1313+ (errcode (ERRCODE_INSUFFICIENT_PRIVILEGE ),
1314+ errmsg ("argument to pg_get_expr() must come from system catalogs" )));
1315+ }
1316+ }
1317+ return result ;
12331318}
12341319
12351320static Node *
0 commit comments