Skip to content

Commit 46286d6

Browse files
committed
Further fixes to the pg_get_expr() security fix in back branches.
It now emerges that the JDBC driver expects to be able to use pg_get_expr() on an output of a sub-SELECT. So extend the check logic to be able to recurse into a sub-SELECT to see if the argument is ultimately coming from an appropriate column. Per report from Thomas Kellerer.
1 parent 74515dc commit 46286d6

File tree

1 file changed

+56
-24
lines changed

1 file changed

+56
-24
lines changed

src/backend/parser/parse_func.c

Lines changed: 56 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
#include "parser/parse_func.h"
3030
#include "parser/parse_relation.h"
3131
#include "parser/parse_type.h"
32+
#include "parser/parsetree.h"
3233
#include "utils/builtins.h"
3334
#include "utils/fmgroids.h"
3435
#include "utils/lsyscache.h"
@@ -42,6 +43,7 @@ static Oid **argtype_inherit(int nargs, Oid *argtypes);
4243
static int find_inheritors(Oid relid, Oid **supervec);
4344
static Oid **gen_cross_product(InhPaths *arginh, int nargs);
4445
static void unknown_attribute(ParseState *pstate, Node *relref, char *attname);
46+
static bool check_pg_get_expr_arg(ParseState *pstate, Node *arg, int netlevelsup);
4547

4648

4749
/*
@@ -1439,9 +1441,7 @@ LookupFuncNameTypeNames(List *funcname, List *argtypes, bool noError)
14391441
void
14401442
check_pg_get_expr_args(ParseState *pstate, Oid fnoid, List *args)
14411443
{
1442-
bool allowed = false;
14431444
Node *arg;
1444-
int netlevelsup;
14451445

14461446
/* if not being called for pg_get_expr, do nothing */
14471447
if (fnoid != F_PG_GET_EXPR && fnoid != F_PG_GET_EXPR_EXT)
@@ -1453,59 +1453,91 @@ check_pg_get_expr_args(ParseState *pstate, Oid fnoid, List *args)
14531453

14541454
/*
14551455
* The first argument must be a Var referencing one of the allowed
1456-
* system-catalog columns. It could be a join alias Var, though.
1456+
* system-catalog columns. It could be a join alias Var or subquery
1457+
* reference Var, though, so we need a recursive subroutine to chase
1458+
* through those possibilities.
14571459
*/
14581460
Assert(list_length(args) > 1);
14591461
arg = (Node *) linitial(args);
1460-
netlevelsup = 0;
14611462

1462-
restart:
1463-
if (IsA(arg, Var))
1463+
if (!check_pg_get_expr_arg(pstate, arg, 0))
1464+
ereport(ERROR,
1465+
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
1466+
errmsg("argument to pg_get_expr() must come from system catalogs")));
1467+
}
1468+
1469+
static bool
1470+
check_pg_get_expr_arg(ParseState *pstate, Node *arg, int netlevelsup)
1471+
{
1472+
if (arg && IsA(arg, Var))
14641473
{
14651474
Var *var = (Var *) arg;
14661475
RangeTblEntry *rte;
1476+
AttrNumber attnum;
14671477

14681478
netlevelsup += var->varlevelsup;
14691479
rte = GetRTEByRangeTablePosn(pstate, var->varno, netlevelsup);
1480+
attnum = var->varattno;
14701481

14711482
if (rte->rtekind == RTE_JOIN)
14721483
{
1473-
/* Expand join alias reference */
1474-
if (var->varattno > 0 &&
1475-
var->varattno <= list_length(rte->joinaliasvars))
1484+
/* Recursively examine join alias variable */
1485+
if (attnum > 0 &&
1486+
attnum <= list_length(rte->joinaliasvars))
14761487
{
1477-
arg = (Node *) list_nth(rte->joinaliasvars, var->varattno - 1);
1478-
goto restart;
1488+
arg = (Node *) list_nth(rte->joinaliasvars, attnum - 1);
1489+
return check_pg_get_expr_arg(pstate, arg, netlevelsup);
14791490
}
14801491
}
1492+
else if (rte->rtekind == RTE_SUBQUERY)
1493+
{
1494+
/* Subselect-in-FROM: examine sub-select's output expr */
1495+
TargetEntry *ste = get_tle_by_resno(rte->subquery->targetList,
1496+
attnum);
1497+
ParseState mypstate;
1498+
1499+
if (ste == NULL || ste->resdom->resjunk)
1500+
elog(ERROR, "subquery %s does not have attribute %d",
1501+
rte->eref->aliasname, attnum);
1502+
arg = (Node *) ste->expr;
1503+
1504+
/*
1505+
* Recurse into the sub-select to see what its expr refers to.
1506+
* We have to build an additional level of ParseState to keep in
1507+
* step with varlevelsup in the subselect.
1508+
*/
1509+
MemSet(&mypstate, 0, sizeof(mypstate));
1510+
mypstate.parentParseState = pstate;
1511+
mypstate.p_rtable = rte->subquery->rtable;
1512+
/* don't bother filling the rest of the fake pstate */
1513+
1514+
return check_pg_get_expr_arg(&mypstate, arg, 0);
1515+
}
14811516
else if (rte->rtekind == RTE_RELATION)
14821517
{
14831518
if (rte->relid == get_system_catalog_relid(IndexRelationName))
14841519
{
1485-
if (var->varattno == Anum_pg_index_indexprs ||
1486-
var->varattno == Anum_pg_index_indpred)
1487-
allowed = true;
1520+
if (attnum == Anum_pg_index_indexprs ||
1521+
attnum == Anum_pg_index_indpred)
1522+
return true;
14881523
}
14891524
else if (rte->relid == get_system_catalog_relid(AttrDefaultRelationName))
14901525
{
1491-
if (var->varattno == Anum_pg_attrdef_adbin)
1492-
allowed = true;
1526+
if (attnum == Anum_pg_attrdef_adbin)
1527+
return true;
14931528
}
14941529
else if (rte->relid == get_system_catalog_relid(ConstraintRelationName))
14951530
{
1496-
if (var->varattno == Anum_pg_constraint_conbin)
1497-
allowed = true;
1531+
if (attnum == Anum_pg_constraint_conbin)
1532+
return true;
14981533
}
14991534
else if (rte->relid == get_system_catalog_relid(TypeRelationName))
15001535
{
1501-
if (var->varattno == Anum_pg_type_typdefaultbin)
1502-
allowed = true;
1536+
if (attnum == Anum_pg_type_typdefaultbin)
1537+
return true;
15031538
}
15041539
}
15051540
}
15061541

1507-
if (!allowed)
1508-
ereport(ERROR,
1509-
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
1510-
errmsg("argument to pg_get_expr() must come from system catalogs")));
1542+
return false;
15111543
}

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy