From 0444cc5bcc57b08b60f326c1a855a4a229cd7bf3 Mon Sep 17 00:00:00 2001
From: "Chao Li (Evan)" <lic@highgo.com>
Date: Fri, 24 Jul 2026 11:22:41 +0800
Subject: [PATCH v2] Protect PGPROC lookup when terminating background workers

TerminateBackgroundWorkersForDatabase() used BackendPidGetProc()
and accessed the returned PGPROC after ProcArrayLock had been
released. The PGPROC could be recycled in the meantime, causing
the database ID of another process to be examined.

Hold ProcArrayLock while looking up the process with
BackendPidGetProcWithLock() and checking its database ID. Also
save the worker PID locally so that the lookup and log message
use the same value if the postmaster updates the background
worker slot concurrently.

This issue was introduced by f1e251be8.

Author: Chao Li <lic@highgo.com>
Reviewed-by: Aya Iwata <iwata.aya@fujitsu.com>
Reviewed-by: Haibo Yan <tristan.yim@gmail.com>
Reviewed-by: Michael Paquier <michael@paquier.xyz>
Discussion: https://postgr.es/m/78E81763-EA1D-4788-9741-4092BCB997A5@gmail.com
---
 src/backend/postmaster/bgworker.c | 8 ++++++--
 1 file changed, 6 insertions(+), 2 deletions(-)

diff --git a/src/backend/postmaster/bgworker.c b/src/backend/postmaster/bgworker.c
index f2cffce3ff6..3da2a90417f 100644
--- a/src/backend/postmaster/bgworker.c
+++ b/src/backend/postmaster/bgworker.c
@@ -1442,16 +1442,20 @@ TerminateBackgroundWorkersForDatabase(Oid databaseId)
 		if (slot->in_use &&
 			(slot->worker.bgw_flags & BGWORKER_INTERRUPTIBLE))
 		{
-			PGPROC	   *proc = BackendPidGetProc(slot->pid);
+			PGPROC	   *proc;
+			pid_t		pid = slot->pid;
 
+			LWLockAcquire(ProcArrayLock, LW_SHARED);
+			proc = BackendPidGetProcWithLock(pid);
 			if (proc && proc->databaseId == databaseId)
 			{
 				slot->terminate = true;
 				signal_postmaster = true;
 
 				elog(DEBUG1, "termination requested for worker (PID %d) on database %u",
-					 (int) slot->pid, databaseId);
+					 (int) pid, databaseId);
 			}
+			LWLockRelease(ProcArrayLock);
 		}
 	}
 
-- 
2.50.1 (Apple Git-155)

