Re: BUG #19483: pg_upgrade fails with orphan records in pg_init_priv catalog table
Hüseyin Demir <huseyin.d3r@gmail.com>
From: Hüseyin Demir <huseyin.d3r@gmail.com>
To: Laurenz Albe <laurenz.albe@cybertec.at>
Cc: Tom Lane <tgl@sss.pgh.pa.us>, Greg Sabino Mullane <htamfids@gmail.com>, pgsql-bugs@lists.postgresql.org
Date: 2026-06-24T12:19:47Z
Lists: pgsql-bugs
Attachments
- performance_tests.txt (text/plain)
- v6-0001-pg_dump-skip-dangling-initprivs.patch (application/octet-stream) patch v6-0001
> > 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