Received: from malur.postgresql.org ([217.196.149.56]) by arkaria.postgresql.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.96) (envelope-from ) id 1vuZP7-00DzY5-1v for pgsql-hackers@arkaria.postgresql.org; Mon, 23 Feb 2026 17:07:29 +0000 Received: from localhost ([127.0.0.1] helo=malur.postgresql.org) by malur.postgresql.org with esmtp (Exim 4.96) (envelope-from ) id 1vuZP6-00ENzy-1y for pgsql-hackers@arkaria.postgresql.org; Mon, 23 Feb 2026 17:07:28 +0000 Received: from magus.postgresql.org ([2a02:c0:301:0:ffff::29]) by malur.postgresql.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.96) (envelope-from ) id 1vuZP6-00ENzp-0u for pgsql-hackers@lists.postgresql.org; Mon, 23 Feb 2026 17:07:28 +0000 Received: from mail-oi1-x234.google.com ([2607:f8b0:4864:20::234]) by magus.postgresql.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 (Exim 4.98.2) (envelope-from ) id 1vuZP3-00000000th8-0EQT for pgsql-hackers@postgresql.org; Mon, 23 Feb 2026 17:07:28 +0000 Received: by mail-oi1-x234.google.com with SMTP id 5614622812f47-46392972257so2933131b6e.2 for ; Mon, 23 Feb 2026 09:07:25 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1771866444; x=1772471244; darn=postgresql.org; h=in-reply-to:content-disposition:mime-version:references:message-id :subject:cc:to:from:date:from:to:cc:subject:date:message-id:reply-to; bh=vgHizb2ZX2uQb5pfKGbyyeKI49zKKnQk3Y9qvA755jU=; b=CI6mygJox25IVquUhRFA+fBW7NIH7xD3G6VmjaH2LEIn0S+sBlKax+XjElqprCW1ZO WLE6aEKHPr2HGoDf2nAvIQSkeJDZEeFYoLPNKNoRl6BPyTkheouDngGRHpcXjig+Jj7l 3x+8hltxer4yLqoirii527pvXpbbKmldXRZjsL+LnyOoY6o5oC8IXkLNJbRh+tJgA7R0 fLd3k0hS+7Djid4NsIKfLuteNHIY1AvHcxYn5xaHcUJK5SSiv0NFKlEhyC43XTvl3psu spbsQcIcNJJKp+s3DvQ6NDam8tWFcxlHS561ub0Ew6p5Q9Sz5Z9WnaWss/ZQeKz6fl/6 LQrA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1771866444; x=1772471244; h=in-reply-to:content-disposition:mime-version:references:message-id :subject:cc:to:from:date:x-gm-gg:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=vgHizb2ZX2uQb5pfKGbyyeKI49zKKnQk3Y9qvA755jU=; b=REIngHumuLm8CfXW6RCsOakI512okWQMmnnp18RDEUh2ELuJNDkChGOnEI3QPl7p45 +f0kptk8mqRT7Bt8Mff1LuTXPRkaPo05C48Zx8HIj0Tp4rLzrjTY1cC37vm8bStfca/h /loPor9Bj8LQFGSFuYYG1257L++dH5xmX/QHlnZeR1d4MkV32M9TTpbLd30hKfzNB3DF grI4CdLRXoLqMsvLEF2CyKLDw72UFGlIyCjhv0rfUWngv9WFO73S3WMtVgUVGksqT08C BiLXUWMVrVHlXU31q87a2NI43UXo5nq1OAozscNVQ2zQwKvXBAaVsYFD6IqiVoJA+fv1 AGOg== X-Forwarded-Encrypted: i=1; AJvYcCWRP0E8umIEY6yR0ixSqBbfz/96dR2TM9MHbEcSZijHVbAFBK18vre7gBMDZTsCGcwfWGqpYmhYNYmOCvCC@postgresql.org X-Gm-Message-State: AOJu0YyVFpZS0nN3LvucA/csFPCqT6JjU0WoX1ve5NiT1AZjtIIGR6NI 9NqccTS2mROnX0ZoRENZnCziBa/Skij89QKyy5gyjLnbT5tl7PzI9P2T X-Gm-Gg: AZuq6aLB3I8tWMNpjd5a5bAtZkHK9eH3OpFt1qaws6suVdxmAgVsGfAk0BLEinF9BeB Mro9YoqI26sqkDmAOoGYntQub3eIEhHprWqY540I7AoOQroVaIicKu+KZLnCXaHFO5JVPMJmgtQ zeeZLNnWM/qlb9kDD3MQrshmc9PrVXWVM8IB+d+KeirY+qgRJuryIF0lfFPQTIRx8OrIK0vPSJK vqe2uOqtTS3p+ObZrnde0kdjJ2J+9tzNXQw0N1BCieOuBgUICULMLe/ZRSV+IiMtkb/Z/uyin8A +l5NyoTXug74GpsakdRQy7TBpKI9PxQk3sMbBwJeu/ZBWt3uQwpeqcnLV/ejdUaCn3ZAdJ45YWD mKAwh/RA/+5rnH2pz8VDtpTLjig4uXQ2E+bDnbNzWUBRYd4fDM0/Z1MrxPGwxf8GMLsXjnO7jYG OZM7VTSxPI8Qb2yK/3UsuQRr0LBYH6Ikt7b8F+AwdWUU0e08cdKl5jDeJo/TeeQX5cOkB73j923 xlfglWE7q8etm5f3fSxVA== X-Received: by 2002:a05:6808:2208:b0:45e:f07a:fd0 with SMTP id 5614622812f47-4644612cb0bmr4344825b6e.6.1771866444230; Mon, 23 Feb 2026 09:07:24 -0800 (PST) Received: from nathan (162-195-168-172.lightspeed.stlsmo.sbcglobal.net. [162.195.168.172]) by smtp.gmail.com with ESMTPSA id 46e09a7af769-7d52cf78736sm8126065a34.5.2026.02.23.09.07.23 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 23 Feb 2026 09:07:23 -0800 (PST) Date: Mon, 23 Feb 2026 11:07:21 -0600 From: Nathan Bossart To: Nitin Motiani Cc: Dilip Kumar , pgsql-hackers@postgresql.org Subject: Re: [PATCH] Support reading large objects with pg_read_all_data Message-ID: References: MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="eI7Nsv0KG12v4PSJ" Content-Disposition: inline In-Reply-To: List-Id: List-Help: List-Subscribe: List-Post: List-Owner: List-Archive: Archived-At: Precedence: bulk --eI7Nsv0KG12v4PSJ Content-Type: text/plain; charset=us-ascii Content-Disposition: inline On Fri, Feb 13, 2026 at 11:17:28AM -0600, Nathan Bossart wrote: > This looks pretty good to me. I'd like to let it sit on the lists a little > while longer in case anyone else has feedback or objections. Assuming > those don't materialize in the next week or so, I will proceed with > committing it. Here's what I have staged for commit. I didn't understand the reasoning behind not giving pg_write_all_data privileges on large objects. Your commit message mentions that "granting write access would imply write permissions on a system catalog" (which I assume is referring to pg_largeobject), but if granting UPDATE on a large object is sufficient to allow updating portions of that catalog, then I see no reason to be so strict with pg_write_all_data. It still doesn't allow updating the catalog directly. -- nathan --eI7Nsv0KG12v4PSJ Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename=v5-0001-Allow-pg_-read-write-_all_data-to-access-large-ob.patch From fc9378f93191ee6579f95bed6034304516f15a8b Mon Sep 17 00:00:00 2001 From: Nathan Bossart Date: Mon, 23 Feb 2026 10:54:59 -0600 Subject: [PATCH v5 1/1] 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, too. For consistency, pg_write_all_data should allow writing all large objects as well. Author: Nitin Motiani Co-authored-by: Nathan Bossart Reviewed-by: Dilip Kumar Discussion: https://postgr.es/m/CAH5HC96dxAEvP78s1-JK_nDABH5c4w2MDfyx4vEWxBEfofGWsw%40mail.gmail.com --- doc/src/sgml/user-manag.sgml | 4 +- src/backend/catalog/aclchk.c | 18 +++++++++ src/test/regress/expected/privileges.out | 49 +++++++++++++++++++++++- src/test/regress/sql/privileges.sql | 23 ++++++++++- 4 files changed, 90 insertions(+), 4 deletions(-) diff --git a/doc/src/sgml/user-manag.sgml b/doc/src/sgml/user-manag.sgml index ed18704a9c2..0ec32700bd4 100644 --- a/doc/src/sgml/user-manag.sgml +++ b/doc/src/sgml/user-manag.sgml @@ -713,7 +713,7 @@ GRANT pg_signal_backend TO admin_user; pg_read_all_data allows reading all data (tables, - views, sequences), as if having SELECT rights on + views, sequences, large objects), as if having SELECT rights on those objects and USAGE 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 BYPASSRLS on @@ -721,7 +721,7 @@ GRANT pg_signal_backend TO admin_user; pg_write_all_data allows writing all data (tables, - views, sequences), as if having INSERT, + views, sequences, large objects), as if having INSERT, UPDATE, and DELETE rights on those objects and USAGE rights on all schemas. This role does not bypass row-level security (RLS) policies. If RLS is being diff --git a/src/backend/catalog/aclchk.c b/src/backend/catalog/aclchk.c index aef855abccc..8811d41df24 100644 --- a/src/backend/catalog/aclchk.c +++ b/src/backend/catalog/aclchk.c @@ -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; } diff --git a/src/test/regress/expected/privileges.out b/src/test/regress/expected/privileges.out index 84c1c1ca38d..7bc274566c3 100644 --- a/src/test/regress/expected/privileges.out +++ b/src/test/regress/expected/privileges.out @@ -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 diff --git a/src/test/regress/sql/privileges.sql b/src/test/regress/sql/privileges.sql index 66e06d91a41..540f73ea9b1 100644 --- a/src/test/regress/sql/privileges.sql +++ b/src/test/regress/sql/privileges.sql @@ -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; -- 2.50.1 (Apple Git-155) --eI7Nsv0KG12v4PSJ--