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

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.
This commit is contained in:
Noah Misch
2015-10-03 20:19:57 -04:00
parent 23fc0b485d
commit 3cb0a7e75a
8 changed files with 44 additions and 76 deletions

View File

@ -40,10 +40,8 @@ extern int check_enable_rls(Oid relid, Oid checkAsUser, bool noError);
* for the table and the plan cache needs to be invalidated if the environment
* changes.
*
* Handle checking as another role via checkAsUser (for views, etc). Note that
* if *not* checking as another role, the caller should pass InvalidOid rather
* than GetUserId(). Otherwise the check for row_security = OFF is skipped, and
* so we may falsely report that RLS is active when the user has bypassed it.
* Handle checking as another role via checkAsUser (for views, etc). Pass
* InvalidOid to check the current user.
*
* If noError is set to 'true' then we just return RLS_ENABLED instead of doing
* 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)
return RLS_NONE;
/*
* Check permissions
*
* Table owners always bypass RLS. Note that superuser is always
* considered an owner. Return RLS_NONE_ENV to indicate that this
* decision depends on the environment (in this case, the user_id).
* Table owners and BYPASSRLS users bypass RLS. Note that a superuser
* qualifies as both. Return RLS_NONE_ENV to indicate that this decision
* depends on the environment (in this case, the user_id).
*/
if (pg_class_ownercheck(relid, user_id))
if (pg_class_ownercheck(relid, user_id) ||
has_bypassrls_privilege(user_id))
return RLS_NONE_ENV;
/*
* If the row_security GUC is 'off', check if the user has permission to
* bypass RLS. row_security is always considered 'on' when querying
* through a view or other cases where checkAsUser is valid.
*/
if (!row_security && !checkAsUser)
{
if (has_bypassrls_privilege(user_id))
/* OK to bypass */
return RLS_NONE_ENV;
else if (noError)
return RLS_ENABLED;
else
ereport(ERROR,
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
errmsg("insufficient privilege to bypass row security.")));
}
/* row_security GUC says to bypass RLS, but user lacks permission */
if (!row_security && !noError)
ereport(ERROR,
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
errmsg("insufficient privilege to bypass row security.")));
/* RLS should be fully enabled for this relation. */
return RLS_ENABLED;

View File

@ -51,7 +51,7 @@ CATALOG(pg_authid,1260) BKI_SHARED_RELATION BKI_ROWTYPE_OID(2842) BKI_SCHEMA_MAC
bool rolcreatedb; /* allowed to create databases? */
bool rolcanlogin; /* allowed to log in as session user? */
bool rolreplication; /* role used for streaming replication */
bool rolbypassrls; /* allowed to bypass row level security? */
bool rolbypassrls; /* bypasses row level security? */
int32 rolconnlimit; /* max connections allowed (-1=no limit) */
/* remaining fields may be null; use heap_getattr to read them! */

View File

@ -2584,10 +2584,15 @@ COPY (SELECT * FROM copy_t ORDER BY a ASC) TO STDOUT WITH DELIMITER ','; --ok
SET row_security TO ON;
COPY (SELECT * FROM copy_t ORDER BY a ASC) TO STDOUT WITH DELIMITER ','; --ok
0,cfcd208495d565ef66e7dff9f98764da
1,c4ca4238a0b923820dcc509a6f75849b
2,c81e728d9d4c2f636f067f89cc14862c
3,eccbc87e4b5ce2fe28308fd9f2a7baf3
4,a87ff679a2f3e71d9181a67b7542122c
5,e4da3b7fbbce2345d7772b0674a318d5
6,1679091c5a880faf6fb5e6087eb1b2dc
7,8f14e45fceea167a5a36dedd4bea2543
8,c9f0f895fb98ab9159f51fd0297e236d
9,45c48cce2e2d7fbdea1afc51c7c6ad26
10,d3d9446802a44259755d38e6d163e820
-- Check COPY TO as user without permissions. SET row_security TO OFF;
SET SESSION AUTHORIZATION rls_regress_user2;
@ -2627,6 +2632,7 @@ COPY copy_rel_to TO STDOUT WITH DELIMITER ','; --ok
1,c4ca4238a0b923820dcc509a6f75849b
SET row_security TO ON;
COPY copy_rel_to TO STDOUT WITH DELIMITER ','; --ok
1,c4ca4238a0b923820dcc509a6f75849b
-- Check COPY TO as user without permissions. SET row_security TO OFF;
SET SESSION AUTHORIZATION rls_regress_user2;
SET row_security TO OFF;
@ -2650,14 +2656,10 @@ SET row_security TO ON;
COPY copy_t FROM STDIN; --fail - COPY FROM not supported by RLS.
ERROR: COPY FROM not supported with row level security.
HINT: Use direct INSERT statements instead.
-- Check COPY TO as user with permissions and BYPASSRLS
-- Check COPY FROM as user with permissions and BYPASSRLS
SET SESSION AUTHORIZATION rls_regress_exempt_user;
SET row_security TO OFF;
COPY copy_t FROM STDIN; --ok
SET row_security TO ON;
COPY copy_t FROM STDIN; --fail - COPY FROM not supported by RLS.
ERROR: COPY FROM not supported with row level security.
HINT: Use direct INSERT statements instead.
COPY copy_t FROM STDIN; --ok
-- Check COPY FROM as user without permissions.
SET SESSION AUTHORIZATION rls_regress_user2;
SET row_security TO OFF;

View File

@ -1070,17 +1070,15 @@ COPY copy_t FROM STDIN; --fail - insufficient privilege to bypass rls.
SET row_security TO ON;
COPY copy_t FROM STDIN; --fail - COPY FROM not supported by RLS.
-- Check COPY TO as user with permissions and BYPASSRLS
-- Check COPY FROM as user with permissions and BYPASSRLS
SET SESSION AUTHORIZATION rls_regress_exempt_user;
SET row_security TO OFF;
SET row_security TO ON;
COPY copy_t FROM STDIN; --ok
1 abc
2 bcd
3 cde
4 def
\.
SET row_security TO ON;
COPY copy_t FROM STDIN; --fail - COPY FROM not supported by RLS.
-- Check COPY FROM as user without permissions.
SET SESSION AUTHORIZATION rls_regress_user2;