BUG #19511: contrib/dblink: NULL dereference in dblink_get_notify() when called without a prior connection

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.

Responses

Browse pgsql-bugs by date

  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