Re: BUG #19483: pg_upgrade fails with orphan records in pg_init_priv catalog table

From: Hüseyin Demir <huseyin(dot)d3r(at)gmail(dot)com>
To: Laurenz Albe <laurenz(dot)albe(at)cybertec(dot)at>
Cc: Tom Lane <tgl(at)sss(dot)pgh(dot)pa(dot)us>, Greg Sabino Mullane <htamfids(at)gmail(dot)com>, pgsql-bugs(at)lists(dot)postgresql(dot)org
Subject: Re: BUG #19483: pg_upgrade fails with orphan records in pg_init_priv catalog table
Date: 2026-06-24 12:19:47
Message-ID: CAB5wL7Zy89DeVXHFvTL72KChkq=2jLXhH14zrC2n5sutLTqZDg@mail.gmail.com
Views: Whole Thread | Raw Message | Download mbox | Resend email
Thread:
Lists: pgsql-bugs

>
> While the technique of fetching the all-numeric role names in advance
> is certainly much cheaper than running a complicated subquery for
> every object dumped, I have one remaining doubt:
>
> What if there is a dangling role OID 65432 in pg_init_privs *and*
> a valid role with the same name (but a different OID)? Then the patch
> would tacitly restore the dangling reference to the latter role.
> Apart from the result being wrong, I wonder if that could be used for
> a privilege escalation attack: you detect that there are dangling
> pg_init_privs entries that grant high privileges. Then you abuse your
> CREATEROLE to create a role with the same name as the dangling OID.
> After a dump and restore, your role has been assigned those privileges.
>
> Perhaps it would be a better approach to fetch the data from
> pg_init_privs once at the beginning of the dump, ignoring the entries
> with dangling OIDs?
>
> Yours,
> Laurenz Albe

Thank you for the reviews.

This v6 patch adds a SAFE_INITPRIVS macro that filters aclitem[]
arrays server-side by checking that each entry's grantor and grantee
OID still exists in pg_roles. It is applied in exactly two queries:

1. getAdditionalACLs() -- the one-time fetch of pg_init_privs at startup
2. dumpTable() column ACL prepared statement -- per-table column initprivs

Crucially, the WHERE clauses in getAggregates()/getFuncs() are NOT
modified. Those queries use raw pip.initprivs only for object
selection (not output), and any spuriously-selected objects produce
zero output because the stored initprivs (from getAdditionalACLs) is
already filtered.

pg_roles is used instead of pg_authid to support non-superuser pg_dump.

So this patch covers the security and performance concerns together I
believe. In addition to this, I tried to introduce different tests to
verify it.

When it comes to performance results I tried to draw a conclusion.
Performance testing shows the overhead is ~1-2ms on the one-time
pg_init_privs fetch (249-749 rows) and zero measurable impact on a
database with 10,000 functions + 500 aggregates.

The filtering adds ~1ms (249 rows) to ~2ms (749 rows) to the one-time
getAdditionalACLs() query that runs at pg_dump startup. This is a
fixed cost that does NOT scale with the number of functions,
aggregates, or other objects in the database.

Let me know if you have additional feedback and concerns.

Regards,
Demir

Attachment Content-Type Size
performance_tests.txt text/plain 5.6 KB
v6-0001-pg_dump-skip-dangling-initprivs.patch application/octet-stream 9.6 KB

In response to

Browse pgsql-bugs by date

  From Date Subject
Next Message Tom Lane 2026-06-24 14:57:58 Re: BUG #19483: pg_upgrade fails with orphan records in pg_init_priv catalog table
Previous Message Amit Langote 2026-06-24 11:20:29 Re: BUG #19484: Segmentation fault triggered by FDW