Skip to content

Commit 0027ee3

Browse files
committed
Fix security checks for selectivity estimation functions with RLS.
In commit e2d4ef8, 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
1 parent 60c2951 commit 0027ee3

File tree

3 files changed

+56
-6
lines changed

3 files changed

+56
-6
lines changed

src/backend/utils/adt/selfuncs.c

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4955,9 +4955,13 @@ examine_variable(PlannerInfo *root, Node *node, int varRelid,
49554955
* For simplicity, we insist on the whole
49564956
* table being selectable, rather than trying
49574957
* to identify which column(s) the index
4958-
* depends on.
4958+
* depends on. Also require all rows to be
4959+
* selectable --- there must be no
4960+
* securityQuals from security barrier views
4961+
* or RLS policies.
49594962
*/
49604963
vardata->acl_ok =
4964+
rte->securityQuals == NIL &&
49614965
(pg_class_aclcheck(rte->relid, GetUserId(),
49624966
ACL_SELECT) == ACLCHECK_OK);
49634967
}
@@ -5021,12 +5025,17 @@ examine_simple_variable(PlannerInfo *root, Var *var,
50215025

50225026
if (HeapTupleIsValid(vardata->statsTuple))
50235027
{
5024-
/* check if user has permission to read this column */
5028+
/*
5029+
* Check if user has permission to read this column. We require
5030+
* all rows to be accessible, so there must be no securityQuals
5031+
* from security barrier views or RLS policies.
5032+
*/
50255033
vardata->acl_ok =
5026-
(pg_class_aclcheck(rte->relid, GetUserId(),
5027-
ACL_SELECT) == ACLCHECK_OK) ||
5028-
(pg_attribute_aclcheck(rte->relid, var->varattno, GetUserId(),
5029-
ACL_SELECT) == ACLCHECK_OK);
5034+
rte->securityQuals == NIL &&
5035+
((pg_class_aclcheck(rte->relid, GetUserId(),
5036+
ACL_SELECT) == ACLCHECK_OK) ||
5037+
(pg_attribute_aclcheck(rte->relid, var->varattno, GetUserId(),
5038+
ACL_SELECT) == ACLCHECK_OK));
50305039
}
50315040
else
50325041
{

src/test/regress/expected/rowsecurity.out

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3938,6 +3938,27 @@ RESET SESSION AUTHORIZATION;
39383938
DROP VIEW rls_view;
39393939
DROP TABLE rls_tbl;
39403940
DROP TABLE ref_tbl;
3941+
-- Leaky operator test
3942+
CREATE TABLE rls_tbl (a int);
3943+
INSERT INTO rls_tbl SELECT x/10 FROM generate_series(1, 100) x;
3944+
ANALYZE rls_tbl;
3945+
ALTER TABLE rls_tbl ENABLE ROW LEVEL SECURITY;
3946+
GRANT SELECT ON rls_tbl TO regress_rls_alice;
3947+
SET SESSION AUTHORIZATION regress_rls_alice;
3948+
CREATE FUNCTION op_leak(int, int) RETURNS bool
3949+
AS 'BEGIN RAISE NOTICE ''op_leak => %, %'', $1, $2; RETURN $1 < $2; END'
3950+
LANGUAGE plpgsql;
3951+
CREATE OPERATOR <<< (procedure = op_leak, leftarg = int, rightarg = int,
3952+
restrict = scalarltsel);
3953+
SELECT * FROM rls_tbl WHERE a <<< 1000;
3954+
a
3955+
---
3956+
(0 rows)
3957+
3958+
DROP OPERATOR <<< (int, int);
3959+
DROP FUNCTION op_leak(int, int);
3960+
RESET SESSION AUTHORIZATION;
3961+
DROP TABLE rls_tbl;
39413962
--
39423963
-- Clean up objects
39433964
--

src/test/regress/sql/rowsecurity.sql

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1793,6 +1793,26 @@ DROP VIEW rls_view;
17931793
DROP TABLE rls_tbl;
17941794
DROP TABLE ref_tbl;
17951795

1796+
-- Leaky operator test
1797+
CREATE TABLE rls_tbl (a int);
1798+
INSERT INTO rls_tbl SELECT x/10 FROM generate_series(1, 100) x;
1799+
ANALYZE rls_tbl;
1800+
1801+
ALTER TABLE rls_tbl ENABLE ROW LEVEL SECURITY;
1802+
GRANT SELECT ON rls_tbl TO regress_rls_alice;
1803+
1804+
SET SESSION AUTHORIZATION regress_rls_alice;
1805+
CREATE FUNCTION op_leak(int, int) RETURNS bool
1806+
AS 'BEGIN RAISE NOTICE ''op_leak => %, %'', $1, $2; RETURN $1 < $2; END'
1807+
LANGUAGE plpgsql;
1808+
CREATE OPERATOR <<< (procedure = op_leak, leftarg = int, rightarg = int,
1809+
restrict = scalarltsel);
1810+
SELECT * FROM rls_tbl WHERE a <<< 1000;
1811+
DROP OPERATOR <<< (int, int);
1812+
DROP FUNCTION op_leak(int, int);
1813+
RESET SESSION AUTHORIZATION;
1814+
DROP TABLE rls_tbl;
1815+
17961816
--
17971817
-- Clean up objects
17981818
--

0 commit comments

Comments
 (0)