pgsql-v9.2-fix-leaky-view-part-1.v8.option-1.patch
application/octet-stream
Filename: pgsql-v9.2-fix-leaky-view-part-1.v8.option-1.patch
Type: application/octet-stream
Part: 2
Message:
Re: [v9.2] Fix Leaky View Problem
Patch
Same data as JSON:
GET /api/v1/attachments/:id/patch
the parsed metadata as JSON — format, series position, per-file stats; never the diff bytes.
API reference →
Format: unified
Series: patch v9
| File | + | − |
|---|---|---|
| src/backend/optimizer/util/plancat.c | 88 | 0 |
src/backend/optimizer/util/plancat.c | 88 ++++++++++++++++++++++++++++++++++
1 files changed, 88 insertions(+), 0 deletions(-)
diff --git a/src/backend/optimizer/util/plancat.c b/src/backend/optimizer/util/plancat.c
index de629e9..1d87394 100644
--- a/src/backend/optimizer/util/plancat.c
+++ b/src/backend/optimizer/util/plancat.c
@@ -25,8 +25,10 @@
#include "catalog/heap.h"
#include "miscadmin.h"
#include "nodes/makefuncs.h"
+#include "nodes/nodeFuncs.h"
#include "optimizer/clauses.h"
#include "optimizer/cost.h"
+#include "optimizer/pathnode.h"
#include "optimizer/plancat.h"
#include "optimizer/predtest.h"
#include "optimizer/prep.h"
@@ -998,6 +1000,76 @@ build_index_tlist(PlannerInfo *root, IndexOptInfo *index,
}
/*
+ * clause_touch_security_barrier
+ *
+ * It returns true, if the supplied clause touches attribute of relation
+ * with 'security_barrier' being set on its RangeTblEntry.
+ * The purpose of this check is to make sure row-level security performs
+ * correctly, even if user defined its own operator with function that
+ * have a side-effect to leak its arguments.
+ */
+static bool
+clause_touch_security_barrier(Node *clause, PlannerInfo *root)
+{
+ if (!clause)
+ return false;
+
+ if (IsA(clause, Var))
+ {
+ Var *var = (Var *) clause;
+ RangeTblEntry *rte = root->simple_rte_array[var->varno];
+
+ if (rte->rtekind == RTE_RELATION)
+ {
+ /*
+ * XXX - Extension modules may append qualifiers on WHERE clause
+ * implicitly for row-level security, and set security_barrier of
+ * RangeTblEnty. In this case, we should not allow operator
+ * functions to reference statistics data that may originated from
+ * the tuples to be invisible.
+ */
+ return rte->security_barrier;
+ }
+ else if (rte->rtekind == RTE_SUBQUERY)
+ {
+ Query *subqry = rte->subquery;
+ RelOptInfo *rel;
+ TargetEntry *ste;
+
+ /*
+ * This clause touches an attribute of sub-query originated from
+ * a view with security_barrier option; that means view is defined
+ * to row-level security. Thus, user given operator functions
+ * should not reference statistics data that may originated from
+ * the tuples to be invisible.
+ */
+ if (rte->security_barrier)
+ return true;
+
+ if (subqry->setOperations ||
+ subqry->groupClause ||
+ subqry->distinctClause)
+ return false;
+
+ rel = find_base_rel(root, var->varno);
+ Assert(rel->subroot && IsA(rel->subroot, PlannerInfo));
+
+ ste = get_tle_by_resno(subqry->targetList, var->varattno);
+ if (ste == NULL || ste->resjunk)
+ elog(ERROR, "subquery %s does not have attribute %d",
+ rte->eref->aliasname, var->varattno);
+
+ return clause_touch_security_barrier((Node *)ste->expr,
+ rel->subroot);
+ }
+ return false;
+ }
+ return expression_tree_walker(clause,
+ clause_touch_security_barrier,
+ (void *) root);
+}
+
+/*
* restriction_selectivity
*
* Returns the selectivity of a specified restriction operator clause.
@@ -1022,6 +1094,14 @@ restriction_selectivity(PlannerInfo *root,
if (!oprrest)
return (Selectivity) 0.5;
+ /*
+ * if the operator depends on values originated from security-barrier
+ * relation, we skip to call estimator function; to ensure row-level
+ * security.
+ */
+ if (clause_touch_security_barrier((Node *) args, root))
+ return (Selectivity) 0.5;
+
result = DatumGetFloat8(OidFunctionCall4(oprrest,
PointerGetDatum(root),
ObjectIdGetDatum(operatorid),
@@ -1058,6 +1138,14 @@ join_selectivity(PlannerInfo *root,
if (!oprjoin)
return (Selectivity) 0.5;
+ /*
+ * if the operator depends on values originated from security-barrier
+ * relation, we skip to call estimator function; to ensure row-level
+ * security.
+ */
+ if (clause_touch_security_barrier((Node *) args, root))
+ return (Selectivity) 0.5;
+
result = DatumGetFloat8(OidFunctionCall5(oprjoin,
PointerGetDatum(root),
ObjectIdGetDatum(operatorid),