Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit 1e15b21

Browse files
committed
Use appropriate command type when retrieving relation's policies.
When retrieving policies, if not working on the root target relation, we actually want the relation's SELECT policies, regardless of the top level query command type. For example in UPDATE t1...FROM t2 we need to apply t1's UPDATE policies and t2's SELECT policies. Previously top level query command type was applied to all relations, which was wrong. Add some regression coverage to ensure we don't violate this principle in the future. Report and patch by Dean Rasheed. Cherry picked from larger refactoring patch and tweaked by me. Back-patched to 9.5 where RLS was introduced.
1 parent 8693ebe commit 1e15b21

File tree

3 files changed

+134
-1
lines changed

3 files changed

+134
-1
lines changed

src/backend/rewrite/rowsecurity.c

+11-1
Original file line numberDiff line numberDiff line change
@@ -147,8 +147,18 @@ get_row_security_policies(Query *root, CmdType commandType, RangeTblEntry *rte,
147147
return;
148148
}
149149

150-
/* Grab the built-in policies which should be applied to this relation. */
150+
/*
151+
* RLS is enabled for this relation.
152+
*
153+
* Get the security policies that should be applied, based on the command
154+
* type. Note that if this isn't the target relation, we actually want
155+
* the relation's SELECT policies, regardless of the query command type,
156+
* for example in UPDATE t1 ... FROM t2 we need to apply t1's UPDATE
157+
* policies and t2's SELECT policies.
158+
*/
151159
rel = heap_open(rte->relid, NoLock);
160+
if (rt_index != root->resultRelation)
161+
commandType = CMD_SELECT;
152162

153163
rowsec_policies = pull_row_security_policies(commandType, rel,
154164
user_id);

src/test/regress/expected/rowsecurity.out

+83
Original file line numberDiff line numberDiff line change
@@ -3033,6 +3033,89 @@ CREATE POLICY p ON t USING (max(c)); -- fails: aggregate functions are not allow
30333033
ERROR: aggregate functions are not allowed in policy expressions
30343034
ROLLBACK;
30353035
--
3036+
-- Non-target relations are only subject to SELECT policies
3037+
--
3038+
SET SESSION AUTHORIZATION rls_regress_user0;
3039+
CREATE TABLE r1 (a int);
3040+
CREATE TABLE r2 (a int);
3041+
INSERT INTO r1 VALUES (10), (20);
3042+
INSERT INTO r2 VALUES (10), (20);
3043+
GRANT ALL ON r1, r2 TO rls_regress_user1;
3044+
CREATE POLICY p1 ON r1 USING (true);
3045+
ALTER TABLE r1 ENABLE ROW LEVEL SECURITY;
3046+
CREATE POLICY p1 ON r2 FOR SELECT USING (true);
3047+
CREATE POLICY p2 ON r2 FOR INSERT WITH CHECK (false);
3048+
CREATE POLICY p3 ON r2 FOR UPDATE USING (false);
3049+
CREATE POLICY p4 ON r2 FOR DELETE USING (false);
3050+
ALTER TABLE r2 ENABLE ROW LEVEL SECURITY;
3051+
SET SESSION AUTHORIZATION rls_regress_user1;
3052+
SELECT * FROM r1;
3053+
a
3054+
----
3055+
10
3056+
20
3057+
(2 rows)
3058+
3059+
SELECT * FROM r2;
3060+
a
3061+
----
3062+
10
3063+
20
3064+
(2 rows)
3065+
3066+
-- r2 is read-only
3067+
INSERT INTO r2 VALUES (2); -- Not allowed
3068+
ERROR: new row violates row level security policy for "r2"
3069+
UPDATE r2 SET a = 2 RETURNING *; -- Updates nothing
3070+
a
3071+
---
3072+
(0 rows)
3073+
3074+
DELETE FROM r2 RETURNING *; -- Deletes nothing
3075+
a
3076+
---
3077+
(0 rows)
3078+
3079+
-- r2 can be used as a non-target relation in DML
3080+
INSERT INTO r1 SELECT a + 1 FROM r2 RETURNING *; -- OK
3081+
a
3082+
----
3083+
11
3084+
21
3085+
(2 rows)
3086+
3087+
UPDATE r1 SET a = r2.a + 2 FROM r2 WHERE r1.a = r2.a RETURNING *; -- OK
3088+
a | a
3089+
----+----
3090+
12 | 10
3091+
22 | 20
3092+
(2 rows)
3093+
3094+
DELETE FROM r1 USING r2 WHERE r1.a = r2.a + 2 RETURNING *; -- OK
3095+
a | a
3096+
----+----
3097+
12 | 10
3098+
22 | 20
3099+
(2 rows)
3100+
3101+
SELECT * FROM r1;
3102+
a
3103+
----
3104+
11
3105+
21
3106+
(2 rows)
3107+
3108+
SELECT * FROM r2;
3109+
a
3110+
----
3111+
10
3112+
20
3113+
(2 rows)
3114+
3115+
SET SESSION AUTHORIZATION rls_regress_user0;
3116+
DROP TABLE r1;
3117+
DROP TABLE r2;
3118+
--
30363119
-- Clean up objects
30373120
--
30383121
RESET SESSION AUTHORIZATION;

src/test/regress/sql/rowsecurity.sql

+40
Original file line numberDiff line numberDiff line change
@@ -1298,6 +1298,46 @@ CREATE TABLE t (c) AS VALUES ('bar'::text);
12981298
CREATE POLICY p ON t USING (max(c)); -- fails: aggregate functions are not allowed in policy expressions
12991299
ROLLBACK;
13001300

1301+
--
1302+
-- Non-target relations are only subject to SELECT policies
1303+
--
1304+
SET SESSION AUTHORIZATION rls_regress_user0;
1305+
CREATE TABLE r1 (a int);
1306+
CREATE TABLE r2 (a int);
1307+
INSERT INTO r1 VALUES (10), (20);
1308+
INSERT INTO r2 VALUES (10), (20);
1309+
1310+
GRANT ALL ON r1, r2 TO rls_regress_user1;
1311+
1312+
CREATE POLICY p1 ON r1 USING (true);
1313+
ALTER TABLE r1 ENABLE ROW LEVEL SECURITY;
1314+
1315+
CREATE POLICY p1 ON r2 FOR SELECT USING (true);
1316+
CREATE POLICY p2 ON r2 FOR INSERT WITH CHECK (false);
1317+
CREATE POLICY p3 ON r2 FOR UPDATE USING (false);
1318+
CREATE POLICY p4 ON r2 FOR DELETE USING (false);
1319+
ALTER TABLE r2 ENABLE ROW LEVEL SECURITY;
1320+
1321+
SET SESSION AUTHORIZATION rls_regress_user1;
1322+
SELECT * FROM r1;
1323+
SELECT * FROM r2;
1324+
1325+
-- r2 is read-only
1326+
INSERT INTO r2 VALUES (2); -- Not allowed
1327+
UPDATE r2 SET a = 2 RETURNING *; -- Updates nothing
1328+
DELETE FROM r2 RETURNING *; -- Deletes nothing
1329+
1330+
-- r2 can be used as a non-target relation in DML
1331+
INSERT INTO r1 SELECT a + 1 FROM r2 RETURNING *; -- OK
1332+
UPDATE r1 SET a = r2.a + 2 FROM r2 WHERE r1.a = r2.a RETURNING *; -- OK
1333+
DELETE FROM r1 USING r2 WHERE r1.a = r2.a + 2 RETURNING *; -- OK
1334+
SELECT * FROM r1;
1335+
SELECT * FROM r2;
1336+
1337+
SET SESSION AUTHORIZATION rls_regress_user0;
1338+
DROP TABLE r1;
1339+
DROP TABLE r2;
1340+
13011341
--
13021342
-- Clean up objects
13031343
--

0 commit comments

Comments
 (0)