]> git.ipfire.org Git - thirdparty/postgresql.git/commitdiff
Fix security checks for selectivity estimation functions with RLS.
authorDean Rasheed <dean.a.rasheed@gmail.com>
Mon, 6 May 2019 10:41:22 +0000 (11:41 +0100)
committerDean Rasheed <dean.a.rasheed@gmail.com>
Mon, 6 May 2019 10:41:22 +0000 (11:41 +0100)
In commit e2d4ef8de8, security checks were added to prevent
user-supplied operators from running over data from pg_statistic
unless the user has table or column privileges on the table, or the
operator is leakproof. For a table with RLS, however, checking for
table or column privileges is insufficient, since that does not
guarantee that the user has permission to view all of the column's
data.

Fix this by also checking for securityQuals on the RTE, and insisting
that the operator be leakproof if there are any. Thus the
leakproofness check will only be skipped if there are no securityQuals
and the user has table or column privileges on the table -- i.e., only
if we know that the user has access to all the data in the column.

Back-patch to 9.5 where RLS was added.

Dean Rasheed, reviewed by Jonathan Katz and Stephen Frost.

Security: CVE-2019-10130

src/backend/utils/adt/selfuncs.c
src/test/regress/expected/rowsecurity.out
src/test/regress/sql/rowsecurity.sql

index fc4c70c0d07e2496b6d98ab37534afdacabe2dc4..5b72a2de81f3df8b37a5e35bbb9e68ad5d45b0d8 100644 (file)
@@ -4955,9 +4955,13 @@ examine_variable(PlannerInfo *root, Node *node, int varRelid,
                                                                 * For simplicity, we insist on the whole
                                                                 * table being selectable, rather than trying
                                                                 * to identify which column(s) the index
-                                                                * depends on.
+                                                                * depends on.  Also require all rows to be
+                                                                * selectable --- there must be no
+                                                                * securityQuals from security barrier views
+                                                                * or RLS policies.
                                                                 */
                                                                vardata->acl_ok =
+                                                                       rte->securityQuals == NIL &&
                                                                        (pg_class_aclcheck(rte->relid, GetUserId(),
                                                                                                           ACL_SELECT) == ACLCHECK_OK);
                                                        }
@@ -5021,12 +5025,17 @@ examine_simple_variable(PlannerInfo *root, Var *var,
 
                if (HeapTupleIsValid(vardata->statsTuple))
                {
-                       /* check if user has permission to read this column */
+                       /*
+                        * Check if user has permission to read this column.  We require
+                        * all rows to be accessible, so there must be no securityQuals
+                        * from security barrier views or RLS policies.
+                        */
                        vardata->acl_ok =
-                               (pg_class_aclcheck(rte->relid, GetUserId(),
-                                                                  ACL_SELECT) == ACLCHECK_OK) ||
-                               (pg_attribute_aclcheck(rte->relid, var->varattno, GetUserId(),
-                                                                          ACL_SELECT) == ACLCHECK_OK);
+                               rte->securityQuals == NIL &&
+                               ((pg_class_aclcheck(rte->relid, GetUserId(),
+                                                                       ACL_SELECT) == ACLCHECK_OK) ||
+                                (pg_attribute_aclcheck(rte->relid, var->varattno, GetUserId(),
+                                                                               ACL_SELECT) == ACLCHECK_OK));
                }
                else
                {
index d8bd739bd65dffba595d5747604412ee2415a780..4e43ad85c116057fcfc0dd85bef1c3a4a8e6463e 100644 (file)
@@ -3938,6 +3938,27 @@ RESET SESSION AUTHORIZATION;
 DROP VIEW rls_view;
 DROP TABLE rls_tbl;
 DROP TABLE ref_tbl;
+-- Leaky operator test
+CREATE TABLE rls_tbl (a int);
+INSERT INTO rls_tbl SELECT x/10 FROM generate_series(1, 100) x;
+ANALYZE rls_tbl;
+ALTER TABLE rls_tbl ENABLE ROW LEVEL SECURITY;
+GRANT SELECT ON rls_tbl TO regress_rls_alice;
+SET SESSION AUTHORIZATION regress_rls_alice;
+CREATE FUNCTION op_leak(int, int) RETURNS bool
+    AS 'BEGIN RAISE NOTICE ''op_leak => %, %'', $1, $2; RETURN $1 < $2; END'
+    LANGUAGE plpgsql;
+CREATE OPERATOR <<< (procedure = op_leak, leftarg = int, rightarg = int,
+                     restrict = scalarltsel);
+SELECT * FROM rls_tbl WHERE a <<< 1000;
+ a 
+---
+(0 rows)
+
+DROP OPERATOR <<< (int, int);
+DROP FUNCTION op_leak(int, int);
+RESET SESSION AUTHORIZATION;
+DROP TABLE rls_tbl;
 --
 -- Clean up objects
 --
index 21d6222d507074d2bf433849a8b2ca5bf8b6894b..7325630398e728867fa31c6ecc1b633ec0faba43 100644 (file)
@@ -1793,6 +1793,26 @@ DROP VIEW rls_view;
 DROP TABLE rls_tbl;
 DROP TABLE ref_tbl;
 
+-- Leaky operator test
+CREATE TABLE rls_tbl (a int);
+INSERT INTO rls_tbl SELECT x/10 FROM generate_series(1, 100) x;
+ANALYZE rls_tbl;
+
+ALTER TABLE rls_tbl ENABLE ROW LEVEL SECURITY;
+GRANT SELECT ON rls_tbl TO regress_rls_alice;
+
+SET SESSION AUTHORIZATION regress_rls_alice;
+CREATE FUNCTION op_leak(int, int) RETURNS bool
+    AS 'BEGIN RAISE NOTICE ''op_leak => %, %'', $1, $2; RETURN $1 < $2; END'
+    LANGUAGE plpgsql;
+CREATE OPERATOR <<< (procedure = op_leak, leftarg = int, rightarg = int,
+                     restrict = scalarltsel);
+SELECT * FROM rls_tbl WHERE a <<< 1000;
+DROP OPERATOR <<< (int, int);
+DROP FUNCTION op_leak(int, int);
+RESET SESSION AUTHORIZATION;
+DROP TABLE rls_tbl;
+
 --
 -- Clean up objects
 --