]> git.ipfire.org Git - thirdparty/postgresql.git/commitdiff
Allow pg_{read,write}_all_data to access large objects.
authorNathan Bossart <nathan@postgresql.org>
Mon, 23 Feb 2026 20:55:21 +0000 (14:55 -0600)
committerNathan Bossart <nathan@postgresql.org>
Mon, 23 Feb 2026 20:55:21 +0000 (14:55 -0600)
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

doc/src/sgml/user-manag.sgml
src/backend/catalog/aclchk.c
src/test/regress/expected/privileges.out
src/test/regress/sql/privileges.sql

index ed18704a9c2ab0f172d372923a033451a93bbe52..0ec32700bd4d0fe1cce3a6ba825ef0fdc7fc90dd 100644 (file)
@@ -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
index aef855abccc136dba9466124097c52444183cc0e..8811d41df24fb6d9d80feb0c91c8e9dbac79e334 100644 (file)
@@ -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;
 }
 
index 84c1c1ca38dd87f4cf7c1b78cf14af7835b3dab5..7bc274566c38cb2c14d56584f89d8751422b8bbb 100644 (file)
@@ -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
index 66e06d91a415401e19ed918f08c700f84639cd87..540f73ea9b1719d5aa67031bb40b8fcd89b38953 100644 (file)
@@ -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;