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

Commit 3cb0a7e

Browse files
committed
Make BYPASSRLS behave like superuser RLS bypass.
Specifically, make its effect independent from the row_security GUC, and make it affect permission checks pertinent to views the BYPASSRLS role owns. The row_security GUC thereby ceases to change successful-query behavior; it can only make a query fail with an error. Back-patch to 9.5, where BYPASSRLS was introduced.
1 parent 23fc0b4 commit 3cb0a7e

File tree

8 files changed

+44
-76
lines changed

8 files changed

+44
-76
lines changed

doc/src/sgml/catalogs.sgml

+3-3
Original file line numberDiff line numberDiff line change
@@ -1454,7 +1454,7 @@
14541454
<entry><structfield>rolbypassrls</structfield></entry>
14551455
<entry><type>bool</type></entry>
14561456
<entry>
1457-
Role can bypass row level security policies, see
1457+
Role bypasses every row level security policy, see
14581458
<xref linkend="ddl-rowsecurity"> for more information.
14591459
</entry>
14601460
</row>
@@ -9413,7 +9413,7 @@ SELECT * FROM pg_locks pl LEFT JOIN pg_prepared_xacts ppx
94139413
<entry><type>bool</type></entry>
94149414
<entry></entry>
94159415
<entry>
9416-
User can bypass row level security policies, see
9416+
User bypasses every row level security policy, see
94179417
<xref linkend="ddl-rowsecurity"> for more information.
94189418
</entry>
94199419
</row>
@@ -9888,7 +9888,7 @@ SELECT * FROM pg_locks pl LEFT JOIN pg_prepared_xacts ppx
98889888
<entry><structfield>usebypassrls</structfield></entry>
98899889
<entry><type>bool</type></entry>
98909890
<entry>
9891-
User can bypass row level security policies, see
9891+
User bypasses every row level security policy, see
98929892
<xref linkend="ddl-rowsecurity"> for more information.
98939893
</entry>
98949894
</row>

doc/src/sgml/config.sgml

+9-16
Original file line numberDiff line numberDiff line change
@@ -5591,22 +5591,15 @@ COPY postgres_log FROM '/full/path/to/logfile.csv' WITH csv;
55915591
</term>
55925592
<listitem>
55935593
<para>
5594-
This variable controls if row security policies are to be applied
5595-
to queries which are run against tables that have row security enabled.
5596-
The default is <literal>on</>. When set to <literal>on</>, all users,
5597-
except superusers and the owner of the table, will have the row
5598-
policies for the table applied to their queries. When set to
5599-
<literal>off</>, queries will bypass row policies for the table, if
5600-
possible, and error if not.
5601-
</para>
5602-
5603-
<para>
5604-
For a user who is not a superuser and not the table owner to bypass
5605-
row policies for the table, they must have the <literal>BYPASSRLS</>
5606-
role attribute. If this is set to <literal>off</> and the user queries
5607-
a table which has row policies enabled and the user does not have the
5608-
right to bypass row policies then a permission denied error will be
5609-
returned.
5594+
This variable controls whether to raise an error in lieu of applying a
5595+
row security policy. When set to <literal>on</>, policies apply
5596+
normally. When set to <literal>off</>, queries fail which would
5597+
otherwise apply at least one policy. The default is <literal>on</>.
5598+
Change to <literal>off</> where limited row visibility could cause
5599+
incorrect results; for example, <application>pg_dump</> makes that
5600+
change by default. This variable has no effect on roles which bypass
5601+
every row security policy, to wit, superusers and roles with
5602+
the <literal>BYPASSRLS</> attribute.
56105603
</para>
56115604

56125605
<para>

doc/src/sgml/ddl.sgml

+6-13
Original file line numberDiff line numberDiff line change
@@ -1543,8 +1543,12 @@ REVOKE ALL ON accounts FROM PUBLIC;
15431543
Row security policies can be specific to commands, or to roles, or to
15441544
both. The commands available are <literal>ALL</literal>,
15451545
<literal>SELECT</>, <literal>INSERT</>, <literal>UPDATE</>, and
1546-
<literal>DELETE</>. Multiple roles can be assigned to a given policy
1547-
and normal role membership and inheritance rules apply.
1546+
<literal>DELETE</>. Multiple roles can be assigned to a given policy and
1547+
normal role membership and inheritance rules apply. Table owners,
1548+
superusers, and roles with the <literal>BYPASSRLS</> attribute bypass the
1549+
row security system when querying a table. Applications that expect to
1550+
bypass all row security through those mechanisms should
1551+
set <xref linkend="guc-row-security"> to <literal>off</>.
15481552
</para>
15491553

15501554
<para>
@@ -1574,17 +1578,6 @@ REVOKE ALL ON accounts FROM PUBLIC;
15741578
<xref linkend="sql-altertable"> command.
15751579
</para>
15761580

1577-
<para>
1578-
The table owners and superusers bypass the row security system when
1579-
querying a table. Any user can request that row security be bypassed by
1580-
setting <xref linkend="guc-row-security"> to <literal>off</literal>. If
1581-
the user does not have privileges to bypass row security when querying a
1582-
given table then an error will be returned instead. Other users can be
1583-
granted the ability to bypass the row security system with
1584-
the <literal>BYPASSRLS</literal> role attribute. This attribute can only
1585-
be set by a superuser.
1586-
</para>
1587-
15881581
<para>
15891582
Each policy has a name and multiple policies can be defined for a
15901583
table. As policies are table-specific, each policy for a table must

doc/src/sgml/ref/create_role.sgml

+3-6
Original file line numberDiff line numberDiff line change
@@ -196,16 +196,13 @@ CREATE ROLE <replaceable class="PARAMETER">name</replaceable> [ [ WITH ] <replac
196196
<term><literal>NOBYPASSRLS</literal></term>
197197
<listitem>
198198
<para>
199-
These clauses determine whether a role is allowed to bypass row-level security (RLS)
200-
policies. A role having the <literal>BYPASSRLS</literal> attribute will
201-
be allowed to bypass row-security policies by setting
202-
<literal>row_security</literal> to
203-
<literal>OFF</literal>. <literal>NOBYPASSRLS</literal> is the default.
199+
These clauses determine whether a role bypasses every row-level
200+
security (RLS) policy. <literal>NOBYPASSRLS</literal> is the default.
204201
Note that pg_dump will set <literal>row_security</literal> to
205202
<literal>OFF</literal> by default, to ensure all contents of a table are
206203
dumped out. If the user running pg_dump does not have appropriate
207204
permissions, an error will be returned. The superuser and owner of the
208-
table being dumped are considered to always have the right to bypass RLS.
205+
table being dumped always bypass RLS.
209206
</para>
210207
</listitem>
211208
</varlistentry>

src/backend/utils/misc/rls.c

+12-27
Original file line numberDiff line numberDiff line change
@@ -40,10 +40,8 @@ extern int check_enable_rls(Oid relid, Oid checkAsUser, bool noError);
4040
* for the table and the plan cache needs to be invalidated if the environment
4141
* changes.
4242
*
43-
* Handle checking as another role via checkAsUser (for views, etc). Note that
44-
* if *not* checking as another role, the caller should pass InvalidOid rather
45-
* than GetUserId(). Otherwise the check for row_security = OFF is skipped, and
46-
* so we may falsely report that RLS is active when the user has bypassed it.
43+
* Handle checking as another role via checkAsUser (for views, etc). Pass
44+
* InvalidOid to check the current user.
4745
*
4846
* If noError is set to 'true' then we just return RLS_ENABLED instead of doing
4947
* an ereport() if the user has attempted to bypass RLS and they are not
@@ -78,32 +76,19 @@ check_enable_rls(Oid relid, Oid checkAsUser, bool noError)
7876
return RLS_NONE;
7977

8078
/*
81-
* Check permissions
82-
*
83-
* Table owners always bypass RLS. Note that superuser is always
84-
* considered an owner. Return RLS_NONE_ENV to indicate that this
85-
* decision depends on the environment (in this case, the user_id).
79+
* Table owners and BYPASSRLS users bypass RLS. Note that a superuser
80+
* qualifies as both. Return RLS_NONE_ENV to indicate that this decision
81+
* depends on the environment (in this case, the user_id).
8682
*/
87-
if (pg_class_ownercheck(relid, user_id))
83+
if (pg_class_ownercheck(relid, user_id) ||
84+
has_bypassrls_privilege(user_id))
8885
return RLS_NONE_ENV;
8986

90-
/*
91-
* If the row_security GUC is 'off', check if the user has permission to
92-
* bypass RLS. row_security is always considered 'on' when querying
93-
* through a view or other cases where checkAsUser is valid.
94-
*/
95-
if (!row_security && !checkAsUser)
96-
{
97-
if (has_bypassrls_privilege(user_id))
98-
/* OK to bypass */
99-
return RLS_NONE_ENV;
100-
else if (noError)
101-
return RLS_ENABLED;
102-
else
103-
ereport(ERROR,
104-
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
105-
errmsg("insufficient privilege to bypass row security.")));
106-
}
87+
/* row_security GUC says to bypass RLS, but user lacks permission */
88+
if (!row_security && !noError)
89+
ereport(ERROR,
90+
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
91+
errmsg("insufficient privilege to bypass row security.")));
10792

10893
/* RLS should be fully enabled for this relation. */
10994
return RLS_ENABLED;

src/include/catalog/pg_authid.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ CATALOG(pg_authid,1260) BKI_SHARED_RELATION BKI_ROWTYPE_OID(2842) BKI_SCHEMA_MAC
5151
bool rolcreatedb; /* allowed to create databases? */
5252
bool rolcanlogin; /* allowed to log in as session user? */
5353
bool rolreplication; /* role used for streaming replication */
54-
bool rolbypassrls; /* allowed to bypass row level security? */
54+
bool rolbypassrls; /* bypasses row level security? */
5555
int32 rolconnlimit; /* max connections allowed (-1=no limit) */
5656

5757
/* remaining fields may be null; use heap_getattr to read them! */

src/test/regress/expected/rowsecurity.out

+8-6
Original file line numberDiff line numberDiff line change
@@ -2584,10 +2584,15 @@ COPY (SELECT * FROM copy_t ORDER BY a ASC) TO STDOUT WITH DELIMITER ','; --ok
25842584
SET row_security TO ON;
25852585
COPY (SELECT * FROM copy_t ORDER BY a ASC) TO STDOUT WITH DELIMITER ','; --ok
25862586
0,cfcd208495d565ef66e7dff9f98764da
2587+
1,c4ca4238a0b923820dcc509a6f75849b
25872588
2,c81e728d9d4c2f636f067f89cc14862c
2589+
3,eccbc87e4b5ce2fe28308fd9f2a7baf3
25882590
4,a87ff679a2f3e71d9181a67b7542122c
2591+
5,e4da3b7fbbce2345d7772b0674a318d5
25892592
6,1679091c5a880faf6fb5e6087eb1b2dc
2593+
7,8f14e45fceea167a5a36dedd4bea2543
25902594
8,c9f0f895fb98ab9159f51fd0297e236d
2595+
9,45c48cce2e2d7fbdea1afc51c7c6ad26
25912596
10,d3d9446802a44259755d38e6d163e820
25922597
-- Check COPY TO as user without permissions. SET row_security TO OFF;
25932598
SET SESSION AUTHORIZATION rls_regress_user2;
@@ -2627,6 +2632,7 @@ COPY copy_rel_to TO STDOUT WITH DELIMITER ','; --ok
26272632
1,c4ca4238a0b923820dcc509a6f75849b
26282633
SET row_security TO ON;
26292634
COPY copy_rel_to TO STDOUT WITH DELIMITER ','; --ok
2635+
1,c4ca4238a0b923820dcc509a6f75849b
26302636
-- Check COPY TO as user without permissions. SET row_security TO OFF;
26312637
SET SESSION AUTHORIZATION rls_regress_user2;
26322638
SET row_security TO OFF;
@@ -2650,14 +2656,10 @@ SET row_security TO ON;
26502656
COPY copy_t FROM STDIN; --fail - COPY FROM not supported by RLS.
26512657
ERROR: COPY FROM not supported with row level security.
26522658
HINT: Use direct INSERT statements instead.
2653-
-- Check COPY TO as user with permissions and BYPASSRLS
2659+
-- Check COPY FROM as user with permissions and BYPASSRLS
26542660
SET SESSION AUTHORIZATION rls_regress_exempt_user;
2655-
SET row_security TO OFF;
2656-
COPY copy_t FROM STDIN; --ok
26572661
SET row_security TO ON;
2658-
COPY copy_t FROM STDIN; --fail - COPY FROM not supported by RLS.
2659-
ERROR: COPY FROM not supported with row level security.
2660-
HINT: Use direct INSERT statements instead.
2662+
COPY copy_t FROM STDIN; --ok
26612663
-- Check COPY FROM as user without permissions.
26622664
SET SESSION AUTHORIZATION rls_regress_user2;
26632665
SET row_security TO OFF;

src/test/regress/sql/rowsecurity.sql

+2-4
Original file line numberDiff line numberDiff line change
@@ -1070,17 +1070,15 @@ COPY copy_t FROM STDIN; --fail - insufficient privilege to bypass rls.
10701070
SET row_security TO ON;
10711071
COPY copy_t FROM STDIN; --fail - COPY FROM not supported by RLS.
10721072

1073-
-- Check COPY TO as user with permissions and BYPASSRLS
1073+
-- Check COPY FROM as user with permissions and BYPASSRLS
10741074
SET SESSION AUTHORIZATION rls_regress_exempt_user;
1075-
SET row_security TO OFF;
1075+
SET row_security TO ON;
10761076
COPY copy_t FROM STDIN; --ok
10771077
1 abc
10781078
2 bcd
10791079
3 cde
10801080
4 def
10811081
\.
1082-
SET row_security TO ON;
1083-
COPY copy_t FROM STDIN; --fail - COPY FROM not supported by RLS.
10841082

10851083
-- Check COPY FROM as user without permissions.
10861084
SET SESSION AUTHORIZATION rls_regress_user2;

0 commit comments

Comments
 (0)