Allow pg_{read,write}_all_data to access large objects.

Since the initial goal of pg_read_all_data was to be able to run
pg_dump as a non-superuser without explicitly granting access to
every object, it follows that it should allow reading all large
objects.  For consistency, pg_write_all_data should allow writing
all large objects, too.

Author: Nitin Motiani <nitinmotiani@google.com>
Co-authored-by: Nathan Bossart <nathandbossart@gmail.com>
Reviewed-by: Dilip Kumar <dilipbalaut@gmail.com>
Discussion: https://postgr.es/m/CAH5HC96dxAEvP78s1-JK_nDABH5c4w2MDfyx4vEWxBEfofGWsw%40mail.gmail.com
pull/275/head
Nathan Bossart 2 months ago
parent d743545d84
commit d981976027
  1. 4
      doc/src/sgml/user-manag.sgml
  2. 18
      src/backend/catalog/aclchk.c
  3. 49
      src/test/regress/expected/privileges.out
  4. 23
      src/test/regress/sql/privileges.sql

@ -713,7 +713,7 @@ GRANT pg_signal_backend TO admin_user;
<listitem>
<para>
<literal>pg_read_all_data</literal> allows reading all data (tables,
views, sequences), as if having <command>SELECT</command> rights on
views, sequences, large objects), as if having <command>SELECT</command> rights on
those objects and <literal>USAGE</literal> rights on all schemas. This
role does not bypass row-level security (RLS) policies. If RLS is being
used, an administrator may wish to set <literal>BYPASSRLS</literal> on
@ -721,7 +721,7 @@ GRANT pg_signal_backend TO admin_user;
</para>
<para>
<literal>pg_write_all_data</literal> allows writing all data (tables,
views, sequences), as if having <command>INSERT</command>,
views, sequences, large objects), as if having <command>INSERT</command>,
<command>UPDATE</command>, and <command>DELETE</command> rights on those
objects and <literal>USAGE</literal> rights on all schemas. This role
does not bypass row-level security (RLS) policies. If RLS is being

@ -3598,6 +3598,24 @@ pg_largeobject_aclmask_snapshot(Oid lobj_oid, Oid roleid,
table_close(pg_lo_meta, AccessShareLock);
/*
* Check if ACL_SELECT is being checked and, if so, and not set already as
* part of the result, then check if the user has privileges of the
* pg_read_all_data role, which allows read access to all large objects.
*/
if (mask & ACL_SELECT && !(result & ACL_SELECT) &&
has_privs_of_role(roleid, ROLE_PG_READ_ALL_DATA))
result |= ACL_SELECT;
/*
* Check if ACL_UPDATE is being checked and, if so, and not set already as
* part of the result, then check if the user has privileges of the
* pg_write_all_data role, which allows write access to all large objects.
*/
if (mask & ACL_UPDATE && !(result & ACL_UPDATE) &&
has_privs_of_role(roleid, ROLE_PG_WRITE_ALL_DATA))
result |= ACL_UPDATE;
return result;
}

@ -2175,6 +2175,53 @@ SELECT lo_truncate(lo_open(2001, x'20000'::int), 10);
0
(1 row)
\c -
-- confirm role with privileges of pg_read_all_data can read large objects
SET SESSION AUTHORIZATION regress_priv_user6;
SELECT loread(lo_open(1002, x'40000'::int), 32);
loread
--------
\x
(1 row)
SELECT lo_get(1002);
lo_get
--------
\x
(1 row)
SELECT lowrite(lo_open(1002, x'20000'::int), 'abcd'); -- to be denied
ERROR: permission denied for large object 1002
SELECT lo_put(1002, 1, 'abcd'); -- to be denied
ERROR: permission denied for large object 1002
SELECT lo_truncate(lo_open(1002, x'20000'::int), 0); -- to be denied
ERROR: permission denied for large object 1002
SELECT lo_unlink(1002); -- to be denied
ERROR: must be owner of large object 1002
\c -
-- confirm role with privileges of pg_write_all_data can write large objects
GRANT SELECT ON LARGE OBJECT 1002 TO regress_priv_user7;
SET SESSION AUTHORIZATION regress_priv_user7;
SELECT lowrite(lo_open(1002, x'20000'::int), 'abcd');
lowrite
---------
4
(1 row)
SELECT lo_put(1002, 1, 'abcd');
lo_put
--------
(1 row)
SELECT lo_truncate(lo_open(1002, x'20000'::int), 0);
lo_truncate
-------------
0
(1 row)
SELECT lo_unlink(1002); -- to be denied
ERROR: must be owner of large object 1002
-- has_largeobject_privilege function
-- superuser
\c -
@ -2727,7 +2774,7 @@ SELECT has_largeobject_privilege('regress_priv_user2', 1008, 'SELECT'); -- yes
t
(1 row)
SELECT has_largeobject_privilege('regress_priv_user6', 1008, 'SELECT'); -- no
SELECT has_largeobject_privilege('regress_priv_user3', 1008, 'SELECT'); -- no
has_largeobject_privilege
---------------------------
f

@ -1384,6 +1384,27 @@ SELECT loread(lo_open(1005, x'40000'::int), 32);
SELECT lo_truncate(lo_open(1005, x'20000'::int), 10); -- to be denied
SELECT lo_truncate(lo_open(2001, x'20000'::int), 10);
\c -
-- confirm role with privileges of pg_read_all_data can read large objects
SET SESSION AUTHORIZATION regress_priv_user6;
SELECT loread(lo_open(1002, x'40000'::int), 32);
SELECT lo_get(1002);
SELECT lowrite(lo_open(1002, x'20000'::int), 'abcd'); -- to be denied
SELECT lo_put(1002, 1, 'abcd'); -- to be denied
SELECT lo_truncate(lo_open(1002, x'20000'::int), 0); -- to be denied
SELECT lo_unlink(1002); -- to be denied
\c -
-- confirm role with privileges of pg_write_all_data can write large objects
GRANT SELECT ON LARGE OBJECT 1002 TO regress_priv_user7;
SET SESSION AUTHORIZATION regress_priv_user7;
SELECT lowrite(lo_open(1002, x'20000'::int), 'abcd');
SELECT lo_put(1002, 1, 'abcd');
SELECT lo_truncate(lo_open(1002, x'20000'::int), 0);
SELECT lo_unlink(1002); -- to be denied
-- has_largeobject_privilege function
-- superuser
@ -1619,7 +1640,7 @@ ALTER DEFAULT PRIVILEGES GRANT SELECT ON LARGE OBJECTS TO regress_priv_user2;
SELECT lo_create(1008);
SELECT has_largeobject_privilege('regress_priv_user2', 1008, 'SELECT'); -- yes
SELECT has_largeobject_privilege('regress_priv_user6', 1008, 'SELECT'); -- no
SELECT has_largeobject_privilege('regress_priv_user3', 1008, 'SELECT'); -- no
SELECT has_largeobject_privilege('regress_priv_user2', 1008, 'UPDATE'); -- no
ALTER DEFAULT PRIVILEGES GRANT ALL ON LARGE OBJECTS TO regress_priv_user2;

Loading…
Cancel
Save