1
0
mirror of https://github.com/postgres/postgres.git synced 2025-07-28 23:42:10 +03:00

Reset plan->row_security_env and planUserId

In the plancache, we check if the environment we planned the query under
has changed in a way which requires us to re-plan, such as when the user
for whom the plan was prepared changes and RLS is being used (and,
therefore, there may be different policies to apply).

Unfortunately, while those values were set and checked, they were not
being reset when the query was re-planned and therefore, in cases where
we change role, re-plan, and then change role again, we weren't
re-planning again.  This leads to potentially incorrect policies being
applied in cases where role-specific policies are used and a given query
is planned under one role and then executed under other roles, which
could happen under security definer functions or when a common user and
query is planned initially and then re-used across multiple SET ROLEs.

Further, extensions which made use of CopyCachedPlan() may suffer from
similar issues as the RLS-related fields were not properly copied as
part of the plan and therefore RevalidateCachedQuery() would copy in the
current settings without invalidating the query.

Fix by using the same approach used for 'search_path', where we set the
correct values in CompleteCachedPlan(), check them early on in
RevalidateCachedQuery() and then properly reset them if re-planning.
Also, copy through the values during CopyCachedPlan().

Pointed out by Ashutosh Bapat.  Reviewed by Michael Paquier.

Back-patch to 9.5 where RLS was introduced.

Security: CVE-2016-2193
This commit is contained in:
Stephen Frost
2016-03-28 09:03:20 -04:00
parent d12e5bb79b
commit 86ebf30fd6
3 changed files with 49 additions and 15 deletions

View File

@ -2334,8 +2334,10 @@ GRANT SELECT ON t1 TO rls_regress_user1, rls_regress_user2;
CREATE POLICY p1 ON t1 TO rls_regress_user1 USING ((a % 2) = 0);
CREATE POLICY p2 ON t1 TO rls_regress_user2 USING ((a % 4) = 0);
ALTER TABLE t1 ENABLE ROW LEVEL SECURITY;
-- Prepare as rls_regress_user1
SET ROLE rls_regress_user1;
PREPARE role_inval AS SELECT * FROM t1;
-- Check plan
EXPLAIN (COSTS OFF) EXECUTE role_inval;
QUERY PLAN
-------------------------
@ -2343,7 +2345,9 @@ EXPLAIN (COSTS OFF) EXECUTE role_inval;
Filter: ((a % 2) = 0)
(2 rows)
-- Change to rls_regress_user2
SET ROLE rls_regress_user2;
-- Check plan- should be different
EXPLAIN (COSTS OFF) EXECUTE role_inval;
QUERY PLAN
-------------------------
@ -2351,6 +2355,16 @@ EXPLAIN (COSTS OFF) EXECUTE role_inval;
Filter: ((a % 4) = 0)
(2 rows)
-- Change back to rls_regress_user1
SET ROLE rls_regress_user1;
-- Check plan- should be back to original
EXPLAIN (COSTS OFF) EXECUTE role_inval;
QUERY PLAN
-------------------------
Seq Scan on t1
Filter: ((a % 2) = 0)
(2 rows)
--
-- CTE and RLS
--

View File

@ -852,11 +852,20 @@ CREATE POLICY p2 ON t1 TO rls_regress_user2 USING ((a % 4) = 0);
ALTER TABLE t1 ENABLE ROW LEVEL SECURITY;
-- Prepare as rls_regress_user1
SET ROLE rls_regress_user1;
PREPARE role_inval AS SELECT * FROM t1;
-- Check plan
EXPLAIN (COSTS OFF) EXECUTE role_inval;
-- Change to rls_regress_user2
SET ROLE rls_regress_user2;
-- Check plan- should be different
EXPLAIN (COSTS OFF) EXECUTE role_inval;
-- Change back to rls_regress_user1
SET ROLE rls_regress_user1;
-- Check plan- should be back to original
EXPLAIN (COSTS OFF) EXECUTE role_inval;
--