Disallow LISTEN in background workers.
authorTom Lane <tgl@sss.pgh.pa.us>
Wed, 15 Sep 2021 16:31:56 +0000 (12:31 -0400)
committerTom Lane <tgl@sss.pgh.pa.us>
Wed, 15 Sep 2021 16:31:56 +0000 (12:31 -0400)
It's possible to execute user-defined SQL in some background processes;
for example, logical replication workers can fire triggers.  This opens
the possibility that someone would try to execute LISTEN in such a
context.  But since only regular backends ever call
ProcessNotifyInterrupt, no messages would actually be received, and
thus the registered listener would simply prevent the message queue
from being cleaned.  Eventually NOTIFY would stop working, which is bad.

Perhaps someday somebody will invent infrastructure to make listening
in a background worker actually useful.  In the meantime, forbid it.

Back-patch to v13, which is where we introduced the MyBackendType
variable.  It'd be a lot harder to implement the check without that,
and it doesn't seem worth the trouble.

Discussion: https://postgr.es/m/153243441449.1404.2274116228506175596@wrigleys.postgresql.org

src/backend/tcop/utility.c

index 27fbf1f3aae4a58473fd11c612df2a5b05f2e751..bf085aa93b2055012a8adb9f34265c3f91e8133c 100644 (file)
@@ -803,6 +803,23 @@ standard_ProcessUtility(PlannedStmt *pstmt,
                                ListenStmt *stmt = (ListenStmt *) parsetree;
 
                                CheckRestrictedOperation("LISTEN");
+
+                               /*
+                                * We don't allow LISTEN in background processes, as there is
+                                * no mechanism for them to collect NOTIFY messages, so they'd
+                                * just block cleanout of the async SLRU indefinitely.
+                                * (Authors of custom background workers could bypass this
+                                * restriction by calling Async_Listen directly, but then it's
+                                * on them to provide some mechanism to process the message
+                                * queue.)  Note there seems no reason to forbid UNLISTEN.
+                                */
+                               if (MyBackendType != B_BACKEND)
+                                       ereport(ERROR,
+                                                       (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+                                       /* translator: %s is name of a SQL command, eg LISTEN */
+                                                        errmsg("cannot execute %s within a background process",
+                                                                       "LISTEN")));
+
                                Async_Listen(stmt->conditionname);
                        }
                        break;