mirror of
https://github.com/postgres/postgres.git
synced 2025-07-30 11:03:19 +03:00
Plug RLS related information leak in pg_stats view.
The pg_stats view is supposed to be restricted to only show rows about tables the user can read. However, it sometimes can leak information which could not otherwise be seen when row level security is enabled. Fix that by not showing pg_stats rows to users that would be subject to RLS on the table the row is related to. This is done by creating/using the newly introduced SQL visible function, row_security_active(). Along the way, clean up three call sites of check_enable_rls(). The second argument of that function should only be specified as other than InvalidOid when we are checking as a different user than the current one, as in when querying through a view. These sites were passing GetUserId() instead of InvalidOid, which can cause the function to return incorrect results if the current user has the BYPASSRLS privilege and row_security has been set to OFF. Additionally fix a bug causing RI Trigger error messages to unintentionally leak information when RLS is enabled, and other minor cleanup and improvements. Also add WITH (security_barrier) to the definition of pg_stats. Bumped CATVERSION due to new SQL functions and pg_stats view definition. Back-patch to 9.5 where RLS was introduced. Reported by Yaroslav. Patch by Joe Conway and Dean Rasheed with review and input by Michael Paquier and Stephen Frost.
This commit is contained in:
@ -307,7 +307,7 @@ SELECT * FROM document d FULL OUTER JOIN category c on d.cid = c.cid;
|
||||
|
||||
DELETE FROM category WHERE cid = 33; -- fails with FK violation
|
||||
ERROR: update or delete on table "category" violates foreign key constraint "document_cid_fkey" on table "document"
|
||||
DETAIL: Key (cid)=(33) is still referenced from table "document".
|
||||
DETAIL: Key is still referenced from table "document".
|
||||
-- can insert FK referencing invisible PK
|
||||
SET SESSION AUTHORIZATION rls_regress_user2;
|
||||
SELECT * FROM document d FULL OUTER JOIN category c on d.cid = c.cid;
|
||||
@ -2886,11 +2886,45 @@ SELECT * FROM current_check;
|
||||
(1 row)
|
||||
|
||||
COMMIT;
|
||||
--
|
||||
-- check pg_stats view filtering
|
||||
--
|
||||
SET row_security TO ON;
|
||||
SET SESSION AUTHORIZATION rls_regress_user0;
|
||||
ANALYZE current_check;
|
||||
-- Stats visible
|
||||
SELECT row_security_active('current_check');
|
||||
row_security_active
|
||||
---------------------
|
||||
f
|
||||
(1 row)
|
||||
|
||||
SELECT most_common_vals FROM pg_stats where tablename = 'current_check';
|
||||
most_common_vals
|
||||
---------------------
|
||||
|
||||
|
||||
{rls_regress_user1}
|
||||
(3 rows)
|
||||
|
||||
SET SESSION AUTHORIZATION rls_regress_user1;
|
||||
-- Stats not visible
|
||||
SELECT row_security_active('current_check');
|
||||
row_security_active
|
||||
---------------------
|
||||
t
|
||||
(1 row)
|
||||
|
||||
SELECT most_common_vals FROM pg_stats where tablename = 'current_check';
|
||||
most_common_vals
|
||||
------------------
|
||||
(0 rows)
|
||||
|
||||
--
|
||||
-- Collation support
|
||||
--
|
||||
BEGIN;
|
||||
SET row_security = force;
|
||||
SET row_security TO FORCE;
|
||||
CREATE TABLE coll_t (c) AS VALUES ('bar'::text);
|
||||
CREATE POLICY coll_p ON coll_t USING (c < ('foo'::text COLLATE "C"));
|
||||
ALTER TABLE coll_t ENABLE ROW LEVEL SECURITY;
|
||||
|
@ -2061,7 +2061,7 @@ pg_stats| SELECT n.nspname AS schemaname,
|
||||
JOIN pg_class c ON ((c.oid = s.starelid)))
|
||||
JOIN pg_attribute a ON (((c.oid = a.attrelid) AND (a.attnum = s.staattnum))))
|
||||
LEFT JOIN pg_namespace n ON ((n.oid = c.relnamespace)))
|
||||
WHERE ((NOT a.attisdropped) AND has_column_privilege(c.oid, a.attnum, 'select'::text));
|
||||
WHERE ((NOT a.attisdropped) AND has_column_privilege(c.oid, a.attnum, 'select'::text) AND ((c.relrowsecurity = false) OR (NOT row_security_active(c.oid))));
|
||||
pg_tables| SELECT n.nspname AS schemaname,
|
||||
c.relname AS tablename,
|
||||
pg_get_userbyid(c.relowner) AS tableowner,
|
||||
|
@ -1189,11 +1189,26 @@ SELECT * FROM current_check;
|
||||
|
||||
COMMIT;
|
||||
|
||||
--
|
||||
-- check pg_stats view filtering
|
||||
--
|
||||
SET row_security TO ON;
|
||||
SET SESSION AUTHORIZATION rls_regress_user0;
|
||||
ANALYZE current_check;
|
||||
-- Stats visible
|
||||
SELECT row_security_active('current_check');
|
||||
SELECT most_common_vals FROM pg_stats where tablename = 'current_check';
|
||||
|
||||
SET SESSION AUTHORIZATION rls_regress_user1;
|
||||
-- Stats not visible
|
||||
SELECT row_security_active('current_check');
|
||||
SELECT most_common_vals FROM pg_stats where tablename = 'current_check';
|
||||
|
||||
--
|
||||
-- Collation support
|
||||
--
|
||||
BEGIN;
|
||||
SET row_security = force;
|
||||
SET row_security TO FORCE;
|
||||
CREATE TABLE coll_t (c) AS VALUES ('bar'::text);
|
||||
CREATE POLICY coll_p ON coll_t USING (c < ('foo'::text COLLATE "C"));
|
||||
ALTER TABLE coll_t ENABLE ROW LEVEL SECURITY;
|
||||
|
Reference in New Issue
Block a user