| From: | PG Bug reporting form <noreply(at)postgresql(dot)org> |
|---|---|
| To: | pgsql-bugs(at)lists(dot)postgresql(dot)org |
| Cc: | amjadshahzad2000(at)gmail(dot)com |
| Subject: | BUG #19511: contrib/dblink: NULL dereference in dblink_get_notify() when called without a prior connection |
| Date: | 2026-06-05 01:15:40 |
| Message-ID: | 19511-f9f251767b658232@postgresql.org |
| Views: | Whole Thread | Raw Message | Download mbox | Resend email |
| Thread: | |
| Lists: | pgsql-bugs |
The following bug has been logged on the website:
Bug reference: 19511
Logged by: Amjad Shahzad
Email address: amjadshahzad2000(at)gmail(dot)com
PostgreSQL version: 18.4
Operating system: Ubuntu 24.04 x86_64
Description:
I found a NULL pointer dereference in contrib/dblink/dblink.c in the
dblink_get_notify() function. Any user with EXECUTE on the function
can crash their backend process with a single call. Confirmed against master
commit 0392fb900eb.
WHAT IS THE ISSUE
=================
dblink_get_notify() retrieves async notifications from a remote connection.
When called with no arguments it uses the default
(unnamed) connection. If no default connection has been established first,
pconn->conn is NULL. The code assigns this NULL to conn and
then passes it directly to PQconsumeInput() and PQnotifies():
/* line 1893 (master) */
else
conn = pconn->conn; /* NULL — no connection established */
InitMaterializedSRF(fcinfo, 0);
PQconsumeInput(conn); /* passes NULL to libpq */
while ((notify = PQnotifies(conn)) != NULL) /* NULL dereference */
PQnotifies(NULL) dereferences a null pointer internally, causing a backend
SIGSEGV.
Every other function in dblink.c that uses the default connection already
has an explicit NULL guard:
if (!conn)
dblink_conn_not_avail(conname);
dblink_get_notify() is the only function that skips this guard.
WHAT CAN BE COMPROMISED
=========================
Any user with EXECUTE on dblink_get_notify(), granted to PUBLIC by default
can crash their backend process
on demand. No password, no connection, no special privileges required.
In a shared server environment this can be used as a denial-of-service
against a specific session. Combined with
connection pooling or persistent connections it could repeatedly crash
backend processes.
PREREQUISITES
===============
1. Any connected database user
2. EXECUTE on dblink_get_notify (granted to PUBLIC by default)
3. contrib/dblink installed (CREATE EXTENSION dblink)
No dblink connection needed. No password needed.
STEPS TO REPRODUCE
====================
-- STEP 1: Install dblink
CREATE EXTENSION dblink;
-- STEP 2: As any user, call without connecting first
SELECT * FROM dblink_get_notify();
-- Result before fix:
-- server closed the connection unexpectedly
-- SIGSEGV in server log
-- Result after fix:
-- ERROR: connection not available
THE FIX
=======
Add the same NULL guard that every other dblink function already has:
/* BEFORE */
else
conn = pconn->conn;
/* AFTER */
else
{
conn = pconn->conn;
if (!conn)
dblink_conn_not_avail(NULL);
}
4 lines added. Patch attached.
BEHAVIOUR AFTER THE FIX
========================
-- No prior connection:
SELECT * FROM dblink_get_notify();
-- ERROR: connection not available (clean error, no crash)
-- With valid connection:
SELECT * FROM dblink_get_notify('myconn');
-- (0 rows) (works exactly as before)
REGRESSION TEST RESULTS
=========================
$ meson test --suite dblink
1/2 dblink - postgresql:dblink/regress OK (all SQL tests pass)
2/2 dblink - postgresql:dblink/001_auth_scram OK 12 subtests passed
Ok: 2 Fail: 0
$ meson test --suite regress
1/1 regress - postgresql:regress/regress OK 245 subtests passed
Ok: 1 Fail: 0
Tested on: PostgreSQL master 0392fb900eb, Ubuntu 24.04, x86_64.
| From | Date | Subject | |
|---|---|---|---|
| Next Message | Amjad Shahzad | 2026-06-05 01:19:48 | Re: BUG #19511: contrib/dblink: NULL dereference in dblink_get_notify() when called without a prior connection |
| Previous Message | Amjad Shahzad | 2026-06-05 00:29:16 | Re: BUG #19510: refint.c: SQL injection via unquoted identifier arguments in check_primary_key and check_foreign_key |