]> git.ipfire.org Git - thirdparty/postgresql.git/commitdiff
Cleanup of rewriter and planner handling of Query.hasRowSecurity flag.
authorTom Lane <tgl@sss.pgh.pa.us>
Thu, 10 Nov 2016 21:16:33 +0000 (16:16 -0500)
committerTom Lane <tgl@sss.pgh.pa.us>
Thu, 10 Nov 2016 21:16:33 +0000 (16:16 -0500)
Be sure to pull up the subquery's hasRowSecurity flag when flattening a
subquery in pull_up_simple_subquery().  This isn't a bug today because
we don't look at the hasRowSecurity flag during planning, but it could
easily be a bug tomorrow.

Likewise, make rewriteRuleAction() pull up the hasRowSecurity flag when
absorbing RTEs from a rule action.  This isn't a bug either, for the
opposite reason: the flag should never be set yet.  But again, it seems
like good future proofing.

Add a comment explaining why rewriteTargetView() should *not* set
hasRowSecurity when adding stuff to securityQuals.

Improve some nearby comments about securityQuals processing, and document
that field more completely in parsenodes.h.

Patch by me, analysis by Dean Rasheed.

Discussion: <CAEZATCXZ8tb2DV6f=bkhsMV6u_gRcZ0CZBw2J-qU84RxSukZog@mail.gmail.com>

src/backend/optimizer/prep/prepjointree.c
src/backend/rewrite/rewriteHandler.c
src/include/nodes/parsenodes.h

index 878db9b4ab76cb8ecb3bc587e5731e0583a78aac..b68123034983ca03f26c0dc0489886405768e976 100644 (file)
@@ -1187,6 +1187,9 @@ pull_up_simple_subquery(PlannerInfo *root, Node *jtnode, RangeTblEntry *rte,
         */
        parse->hasSubLinks |= subquery->hasSubLinks;
 
+       /* If subquery had any RLS conditions, now main query does too */
+       parse->hasRowSecurity |= subquery->hasRowSecurity;
+
        /*
         * subquery won't be pulled up if it hasAggs, hasWindowFuncs, or
         * hasTargetSRFs, so no work needed on those flags
index b828e3cb0779f84dd5c9784c8862e52350bb733d..65c3d6e081405c42153b2064fec01b85bfe53bc7 100644 (file)
@@ -446,6 +446,15 @@ rewriteRuleAction(Query *parsetree,
                }
        }
 
+       /*
+        * Also, we might have absorbed some RTEs with RLS conditions into the
+        * sub_action.  If so, mark it as hasRowSecurity, whether or not those
+        * RTEs will be referenced after we finish rewriting.  (Note: currently
+        * this is a no-op because RLS conditions aren't added till later, but it
+        * seems like good future-proofing to do this anyway.)
+        */
+       sub_action->hasRowSecurity |= parsetree->hasRowSecurity;
+
        /*
         * Each rule action's jointree should be the main parsetree's jointree
         * plus that rule's jointree, but usually *without* the original rtindex
@@ -1835,10 +1844,10 @@ fireRIRrules(Query *parsetree, List *activeRIRs, bool forUpdatePushedDown)
                        }
 
                        /*
-                        * Add the new security quals to the start of the RTE's list so
-                        * that they get applied before any existing security quals (which
-                        * might have come from a user-written security barrier view, and
-                        * might contain malicious code).
+                        * Add the new security barrier quals to the start of the RTE's
+                        * list so that they get applied before any existing barrier quals
+                        * (which would have come from a security-barrier view, and should
+                        * get lower priority than RLS conditions on the table itself).
                         */
                        rte->securityQuals = list_concat(securityQuals,
                                                                                         rte->securityQuals);
@@ -2957,9 +2966,9 @@ rewriteTargetView(Query *parsetree, Relation view)
         * only adjust their varnos to reference the new target (just the same as
         * we did with the view targetlist).
         *
-        * Note that there is special-case handling for the quals of a security
-        * barrier view, since they need to be kept separate from any
-        * user-supplied quals, so these quals are kept on the new target RTE.
+        * If it's a security-barrier view, its WHERE quals must be applied before
+        * quals from the outer query, so we attach them to the RTE as security
+        * barrier quals rather than adding them to the main WHERE clause.
         *
         * For INSERT, the view's quals can be ignored in the main query.
         */
@@ -2980,12 +2989,21 @@ rewriteTargetView(Query *parsetree, Relation view)
                if (RelationIsSecurityView(view))
                {
                        /*
+                        * The view's quals go in front of existing barrier quals: those
+                        * would have come from an outer level of security-barrier view,
+                        * and so must get evaluated later.
+                        *
                         * Note: the parsetree has been mutated, so the new_rte pointer is
                         * stale and needs to be re-computed.
                         */
                        new_rte = rt_fetch(new_rt_index, parsetree->rtable);
                        new_rte->securityQuals = lcons(viewqual, new_rte->securityQuals);
 
+                       /*
+                        * Do not set parsetree->hasRowSecurity, because these aren't RLS
+                        * conditions (they aren't affected by enabling/disabling RLS).
+                        */
+
                        /*
                         * Make sure that the query is marked correctly if the added qual
                         * has sublinks.
index 9b600a5f76df6fca566218ad3a76f477187330cc..04b1c2f2d436eddf94c64e2ef52135feb773b81f 100644 (file)
@@ -775,6 +775,13 @@ typedef struct XmlSerialize
  *       FirstLowInvalidHeapAttributeNumber from column numbers before storing
  *       them in these fields.  A whole-row Var reference is represented by
  *       setting the bit for InvalidAttrNumber.
+ *
+ *       securityQuals is a list of security barrier quals (boolean expressions),
+ *       to be tested in the listed order before returning a row from the
+ *       relation.  It is always NIL in parser output.  Entries are added by the
+ *       rewriter to implement security-barrier views and/or row-level security.
+ *       Note that the planner turns each boolean expression into an implicitly
+ *       AND'ed sublist, as is its usual habit with qualification expressions.
  *--------------------
  */
 typedef enum RTEKind
@@ -872,7 +879,7 @@ typedef struct RangeTblEntry
        Bitmapset  *selectedCols;       /* columns needing SELECT permission */
        Bitmapset  *insertedCols;       /* columns needing INSERT permission */
        Bitmapset  *updatedCols;        /* columns needing UPDATE permission */
-       List       *securityQuals;      /* any security barrier quals to apply */
+       List       *securityQuals;      /* security barrier quals to apply, if any */
 } RangeTblEntry;
 
 /*