|
8 | 8 | *
|
9 | 9 | *
|
10 | 10 | * IDENTIFICATION
|
11 |
| - * $PostgreSQL: pgsql/src/backend/parser/parse_expr.c,v 1.179.4.3 2005/11/18 23:08:28 tgl Exp $ |
| 11 | + * $PostgreSQL: pgsql/src/backend/parser/parse_expr.c,v 1.179.4.4 2010/06/30 18:11:31 heikki Exp $ |
12 | 12 | *
|
13 | 13 | *-------------------------------------------------------------------------
|
14 | 14 | */
|
15 | 15 |
|
16 | 16 | #include "postgres.h"
|
17 | 17 |
|
| 18 | +#include "catalog/catname.h" |
| 19 | +#include "catalog/pg_attrdef.h" |
| 20 | +#include "catalog/pg_constraint.h" |
18 | 21 | #include "catalog/pg_operator.h"
|
19 | 22 | #include "catalog/pg_proc.h"
|
20 | 23 | #include "commands/dbcommands.h"
|
|
32 | 35 | #include "parser/parse_relation.h"
|
33 | 36 | #include "parser/parse_type.h"
|
34 | 37 | #include "utils/builtins.h"
|
| 38 | +#include "utils/fmgroids.h" |
35 | 39 | #include "utils/lsyscache.h"
|
36 | 40 | #include "utils/syscache.h"
|
37 | 41 |
|
@@ -435,6 +439,82 @@ transformExpr(ParseState *pstate, Node *expr)
|
435 | 439 | fn->agg_star,
|
436 | 440 | fn->agg_distinct,
|
437 | 441 | false);
|
| 442 | + |
| 443 | + /* |
| 444 | + * pg_get_expr() is a system function that exposes the |
| 445 | + * expression deparsing functionality in ruleutils.c to users. |
| 446 | + * Very handy, but it was later realized that the functions in |
| 447 | + * ruleutils.c don't check the input rigorously, assuming it to |
| 448 | + * come from system catalogs and to therefore be valid. That |
| 449 | + * makes it easy for a user to crash the backend by passing a |
| 450 | + * maliciously crafted string representation of an expression |
| 451 | + * to pg_get_expr(). |
| 452 | + * |
| 453 | + * There's a lot of code in ruleutils.c, so it's not feasible |
| 454 | + * to add water-proof input checking after the fact. Even if |
| 455 | + * we did it once, it would need to be taken into account in |
| 456 | + * any future patches too. |
| 457 | + * |
| 458 | + * Instead, we restrict pg_rule_expr() to only allow input from |
| 459 | + * system catalogs instead. This is a hack, but it's the most |
| 460 | + * robust and easiest to backpatch way of plugging the |
| 461 | + * vulnerability. |
| 462 | + * |
| 463 | + * This is transparent to the typical usage pattern of |
| 464 | + * "pg_get_expr(systemcolumn, ...)", but will break |
| 465 | + * "pg_get_expr('foo', ...)", even if 'foo' is a valid |
| 466 | + * expression fetched earlier from a system catalog. Hopefully |
| 467 | + * there's isn't many clients doing that out there. |
| 468 | + */ |
| 469 | + if (result && IsA(result, FuncExpr) && !superuser()) |
| 470 | + { |
| 471 | + FuncExpr *fe = (FuncExpr *) result; |
| 472 | + if (fe->funcid == F_PG_GET_EXPR || |
| 473 | + fe->funcid == F_PG_GET_EXPR_EXT) |
| 474 | + { |
| 475 | + Expr *arg = linitial(fe->args); |
| 476 | + bool allowed = false; |
| 477 | + |
| 478 | + /* |
| 479 | + * Check that the argument came directly from one of the |
| 480 | + * allowed system catalog columns |
| 481 | + */ |
| 482 | + if (IsA(arg, Var)) |
| 483 | + { |
| 484 | + Var *var = (Var *) arg; |
| 485 | + RangeTblEntry *rte; |
| 486 | + |
| 487 | + rte = GetRTEByRangeTablePosn(pstate, |
| 488 | + var->varno, var->varlevelsup); |
| 489 | + |
| 490 | + if (rte->relid == get_system_catalog_relid(IndexRelationName)) |
| 491 | + { |
| 492 | + if (var->varattno == Anum_pg_index_indexprs || |
| 493 | + var->varattno == Anum_pg_index_indpred) |
| 494 | + allowed = true; |
| 495 | + } |
| 496 | + else if (rte->relid == get_system_catalog_relid(AttrDefaultRelationName)) |
| 497 | + { |
| 498 | + if (var->varattno == Anum_pg_attrdef_adbin) |
| 499 | + allowed = true; |
| 500 | + } |
| 501 | + else if (rte->relid == get_system_catalog_relid(ConstraintRelationName)) |
| 502 | + { |
| 503 | + if (var->varattno == Anum_pg_constraint_conbin) |
| 504 | + allowed = true; |
| 505 | + } |
| 506 | + else if (rte->relid == get_system_catalog_relid(TypeRelationName)) |
| 507 | + { |
| 508 | + if (var->varattno == Anum_pg_type_typdefaultbin) |
| 509 | + allowed = true; |
| 510 | + } |
| 511 | + } |
| 512 | + if (!allowed) |
F438
tr>
| 513 | + ereport(ERROR, |
| 514 | + (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), |
| 515 | + errmsg("argument to pg_get_expr() must come from system catalogs"))); |
| 516 | + } |
| 517 | + } |
438 | 518 | break;
|
439 | 519 | }
|
440 | 520 | case T_SubLink:
|
|
0 commit comments