diff options
Diffstat (limited to 'src/backend')
-rw-r--r-- | src/backend/optimizer/path/allpaths.c | 6 | ||||
-rw-r--r-- | src/backend/optimizer/util/clauses.c | 96 |
2 files changed, 75 insertions, 27 deletions
diff --git a/src/backend/optimizer/path/allpaths.c b/src/backend/optimizer/path/allpaths.c index c4b0c79fb17..9caca94f64b 100644 --- a/src/backend/optimizer/path/allpaths.c +++ b/src/backend/optimizer/path/allpaths.c @@ -1982,7 +1982,9 @@ targetIsInAllPartitionLists(TargetEntry *tle, Query *query) * 2. If unsafeVolatile is set, the qual must not contain any volatile * functions. * - * 3. If unsafeLeaky is set, the qual must not contain any leaky functions. + * 3. If unsafeLeaky is set, the qual must not contain any leaky functions + * that are passed Var nodes, and therefore might reveal values from the + * subquery as side effects. * * 4. The qual must not refer to the whole-row output of the subquery * (since there is no easy way to name that within the subquery itself). @@ -2009,7 +2011,7 @@ qual_is_pushdown_safe(Query *subquery, Index rti, Node *qual, /* Refuse leaky quals if told to (point 3) */ if (safetyInfo->unsafeLeaky && - contain_leaky_functions(qual)) + contain_leaked_vars(qual)) return false; /* diff --git a/src/backend/optimizer/util/clauses.c b/src/backend/optimizer/util/clauses.c index 84d58ae595e..480114d92b6 100644 --- a/src/backend/optimizer/util/clauses.c +++ b/src/backend/optimizer/util/clauses.c @@ -97,7 +97,7 @@ static bool contain_mutable_functions_walker(Node *node, void *context); static bool contain_volatile_functions_walker(Node *node, void *context); static bool contain_volatile_functions_not_nextval_walker(Node *node, void *context); static bool contain_nonstrict_functions_walker(Node *node, void *context); -static bool contain_leaky_functions_walker(Node *node, void *context); +static bool contain_leaked_vars_walker(Node *node, void *context); static Relids find_nonnullable_rels_walker(Node *node, bool top_level); static List *find_nonnullable_vars_walker(Node *node, bool top_level); static bool is_strict_saop(ScalarArrayOpExpr *expr, bool falseOK); @@ -1318,26 +1318,30 @@ contain_nonstrict_functions_walker(Node *node, void *context) } /***************************************************************************** - * Check clauses for non-leakproof functions + * Check clauses for Vars passed to non-leakproof functions *****************************************************************************/ /* - * contain_leaky_functions - * Recursively search for leaky functions within a clause. + * contain_leaked_vars + * Recursively scan a clause to discover whether it contains any Var + * nodes (of the current query level) that are passed as arguments to + * leaky functions. * - * Returns true if any function call with side-effect may be present in the - * clause. Qualifiers from outside the a security_barrier view should not - * be pushed down into the view, lest the contents of tuples intended to be - * filtered out be revealed via side effects. + * Returns true if the clause contains any non-leakproof functions that are + * passed Var nodes of the current query level, and which might therefore leak + * data. Qualifiers from outside a security_barrier view that might leak data + * in this way should not be pushed down into the view in case the contents of + * tuples intended to be filtered out by the view are revealed by the leaky + * functions. */ bool -contain_leaky_functions(Node *clause) +contain_leaked_vars(Node *clause) { - return contain_leaky_functions_walker(clause, NULL); + return contain_leaked_vars_walker(clause, NULL); } static bool -contain_leaky_functions_walker(Node *node, void *context) +contain_leaked_vars_walker(Node *node, void *context) { if (node == NULL) return false; @@ -1369,7 +1373,8 @@ contain_leaky_functions_walker(Node *node, void *context) { FuncExpr *expr = (FuncExpr *) node; - if (!get_func_leakproof(expr->funcid)) + if (!get_func_leakproof(expr->funcid) && + contain_var_clause((Node *) expr->args)) return true; } break; @@ -1381,7 +1386,8 @@ contain_leaky_functions_walker(Node *node, void *context) OpExpr *expr = (OpExpr *) node; set_opfuncid(expr); - if (!get_func_leakproof(expr->opfuncid)) + if (!get_func_leakproof(expr->opfuncid) && + contain_var_clause((Node *) expr->args)) return true; } break; @@ -1391,7 +1397,8 @@ contain_leaky_functions_walker(Node *node, void *context) ScalarArrayOpExpr *expr = (ScalarArrayOpExpr *) node; set_sa_opfuncid(expr); - if (!get_func_leakproof(expr->opfuncid)) + if (!get_func_leakproof(expr->opfuncid) && + contain_var_clause((Node *) expr->args)) return true; } break; @@ -1401,15 +1408,29 @@ contain_leaky_functions_walker(Node *node, void *context) CoerceViaIO *expr = (CoerceViaIO *) node; Oid funcid; Oid ioparam; + bool leakproof; bool varlena; + /* + * Data may be leaked if either the input or the output + * function is leaky. + */ getTypeInputInfo(exprType((Node *) expr->arg), &funcid, &ioparam); - if (!get_func_leakproof(funcid)) - return true; + leakproof = get_func_leakproof(funcid); + + /* + * If the input function is leakproof, then check the output + * function. + */ + if (leakproof) + { + getTypeOutputInfo(expr->resulttype, &funcid, &varlena); + leakproof = get_func_leakproof(funcid); + } - getTypeOutputInfo(expr->resulttype, &funcid, &varlena); - if (!get_func_leakproof(funcid)) + if (!leakproof && + contain_var_clause((Node *) expr->arg)) return true; } break; @@ -1419,14 +1440,29 @@ contain_leaky_functions_walker(Node *node, void *context) ArrayCoerceExpr *expr = (ArrayCoerceExpr *) node; Oid funcid; Oid ioparam; + bool leakproof; bool varlena; + /* + * Data may be leaked if either the input or the output + * function is leaky. + */ getTypeInputInfo(exprType((Node *) expr->arg), &funcid, &ioparam); - if (!get_func_leakproof(funcid)) - return true; - getTypeOutputInfo(expr->resulttype, &funcid, &varlena); - if (!get_func_leakproof(funcid)) + leakproof = get_func_leakproof(funcid); + + /* + * If the input function is leakproof, then check the output + * function. + */ + if (leakproof) + { + getTypeOutputInfo(expr->resulttype, &funcid, &varlena); + leakproof = get_func_leakproof(funcid); + } + + if (!leakproof && + contain_var_clause((Node *) expr->arg)) return true; } break; @@ -1435,12 +1471,22 @@ contain_leaky_functions_walker(Node *node, void *context) { RowCompareExpr *rcexpr = (RowCompareExpr *) node; ListCell *opid; + ListCell *larg; + ListCell *rarg; - foreach(opid, rcexpr->opnos) + /* + * Check the comparison function and arguments passed to it for + * each pair of row elements. + */ + forthree(opid, rcexpr->opnos, + larg, rcexpr->largs, + rarg, rcexpr->rargs) { Oid funcid = get_opcode(lfirst_oid(opid)); - if (!get_func_leakproof(funcid)) + if (!get_func_leakproof(funcid) && + (contain_var_clause((Node *) lfirst(larg)) || + contain_var_clause((Node *) lfirst(rarg)))) return true; } } @@ -1455,7 +1501,7 @@ contain_leaky_functions_walker(Node *node, void *context) */ return true; } - return expression_tree_walker(node, contain_leaky_functions_walker, + return expression_tree_walker(node, contain_leaked_vars_walker, context); } |