On Tue, Jul 14, 2015 at 4:01 AM, Stephen Frost <sfr...@snowman.net> wrote:
> Michael,
> * Michael Paquier (michael.paqu...@gmail.com) wrote:
>> On Sun, Jul 12, 2015 at 5:59 PM, Yaroslav wrote:
>> > I can still see all statistics for 'test' in pg_stats under unprivileged
>> > user.
>> Indeed, this looks like an oversight of RLS. Even if a policy is
>> defined to prevent a user from seeing the rows of other users, it is
>> still possible to get some information though this view.
>> I am adding an open item regarding that for 9.5.
> We need to be careful to avoid the slippery slope of trying to prevent
> all covert channels, which has been extensively discussed previously.  I
> tend to agree with this specific case of, if you have RLS configured on
> the table then we probably shouldn't allow normal users to see the stats
> on the table, but I don't have a problem with the usage of those stats
> for generating plans, which users could see the results of via EXPLAIN.

You mean for example the case where EXPLAIN adds in its output the
number of rows filtered out for all users? This gives an hint about
the number of rows of a relation even if a user that a limited access
to its rows with a policy.

>> > I'd prefer statistics on RLS-enabled tables to be simply hidden completely
>> > for unprivileged users.
>> This looks like something simple enough to do.
>> @Stephen: perhaps you have some thoughts on the matter? Currently
>> pg_stats breaks its promise to only show information about the rows
>> current user can read.
> I agree that it should be reasonably simple to do and, provided that's
> the case, I'm fine with doing it once I get back (currently out until
> the 27th).

Looking at that I am not seeing any straight-forward way to resolve
this issue except by hardening pg_stats by having an additional filter
of this type so as a non-owner of a relation cannot see the stats of
this table directly when RLS is enabled:
c.relrowsecurity = false OR c.relowner = current_user::regrole::oid
Attached is a patch doing that (/me now hides, expecting to receive
laser shots because of the use of current_user on a system view).
diff --git a/src/backend/catalog/system_views.sql b/src/backend/catalog/system_views.sql
index e82a53a..3ecf948 100644
--- a/src/backend/catalog/system_views.sql
+++ b/src/backend/catalog/system_views.sql
@@ -211,7 +211,10 @@ CREATE VIEW pg_stats AS
     FROM pg_statistic s JOIN pg_class c ON (c.oid = s.starelid)
          JOIN pg_attribute a ON (c.oid = attrelid AND attnum = s.staattnum)
          LEFT JOIN pg_namespace n ON (n.oid = c.relnamespace)
-    WHERE NOT attisdropped AND has_column_privilege(c.oid, a.attnum, 'select');
+    WHERE NOT attisdropped AND
+          has_column_privilege(c.oid, a.attnum, 'select') AND
+          (c.relrowsecurity = false OR
+           c.relowner = current_user::regrole::oid);
 REVOKE ALL on pg_statistic FROM public;
diff --git a/src/test/regress/expected/rules.out b/src/test/regress/expected/rules.out
index cd53375..67aa14a 100644
--- a/src/test/regress/expected/rules.out
+++ b/src/test/regress/expected/rules.out
@@ -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 (c.relowner = (("current_user"())::regrole)::oid)));
 pg_tables| SELECT n.nspname AS schemaname,
     c.relname AS tablename,
     pg_get_userbyid(c.relowner) AS tableowner,
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:

Reply via email to