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),