@@ -410,7 +410,8 @@ static void SIGHUP_handler(SIGNAL_ARGS);
410
410
static void pmdie (SIGNAL_ARGS );
411
411
static void reaper (SIGNAL_ARGS );
412
412
static void sigusr1_handler (SIGNAL_ARGS );
413
- static void startup_die (SIGNAL_ARGS );
413
+ static void process_startup_packet_die (SIGNAL_ARGS );
414
+ static void process_startup_packet_quickdie (SIGNAL_ARGS );
414
415
static void dummy_handler (SIGNAL_ARGS );
415
416
static void StartupPacketTimeoutHandler (void );
416
417
static void CleanupBackend (int pid , int exitstatus );
@@ -4151,22 +4152,30 @@ BackendInitialize(Port *port)
4151
4152
whereToSendOutput = DestRemote ; /* now safe to ereport to client */
4152
4153
4153
4154
/*
4154
- * We arrange for a simple exit(1) if we receive SIGTERM or SIGQUIT or
4155
- * timeout while trying to collect the startup packet. Otherwise the
4156
- * postmaster cannot shutdown the database FAST or IMMED cleanly if a
4157
- * buggy client fails to send the packet promptly. XXX it follows that
4158
- * the remainder of this function must tolerate losing control at any
4159
- * instant. Likewise, any pg_on_exit_callback registered before or during
4160
- * this function must be prepared to execute at any instant between here
4161
- * and the end of this function. Furthermore, affected callbacks execute
4162
- * partially or not at all when a second exit-inducing signal arrives
4163
- * after proc_exit_prepare() decrements on_proc_exit_index. (Thanks to
4164
- * that mechanic, callbacks need not anticipate more than one call.) This
4165
- * is fragile; it ought to instead follow the norm of handling interrupts
4166
- * at selected, safe opportunities.
4167
- */
4168
- pqsignal (SIGTERM , startup_die );
4169
- pqsignal (SIGQUIT , startup_die );
4155
+ * We arrange to do proc_exit(1) if we receive SIGTERM or timeout while
4156
+ * trying to collect the startup packet; while SIGQUIT results in
4157
+ * _exit(2). Otherwise the postmaster cannot shutdown the database FAST
4158
+ * or IMMED cleanly if a buggy client fails to send the packet promptly.
4159
+ *
4160
+ * XXX this is pretty dangerous; signal handlers should not call anything
4161
+ * as complex as proc_exit() directly. We minimize the hazard by not
4162
+ * keeping these handlers active for longer than we must. However, it
4163
+ * seems necessary to be able to escape out of DNS lookups as well as the
4164
+ * startup packet reception proper, so we can't narrow the scope further
4165
+ * than is done here.
4166
+ *
4167
+ * XXX it follows that the remainder of this function must tolerate losing
4168
+ * control at any instant. Likewise, any pg_on_exit_callback registered
4169
+ * before or during this function must be prepared to execute at any
4170
+ * instant between here and the end of this function. Furthermore,
4171
+ * affected callbacks execute partially or not at all when a second
4172
+ * exit-inducing signal arrives after proc_exit_prepare() decrements
4173
+ * on_proc_exit_index. (Thanks to that mechanic, callbacks need not
4174
+ * anticipate more than one call.) This is fragile; it ought to instead
4175
+ * follow the norm of handling interrupts at selected, safe opportunities.
4176
+ */
4177
+ pqsignal (SIGTERM , process_startup_packet_die );
4178
+ pqsignal (SIGQUIT , process_startup_packet_quickdie );
4170
4179
InitializeTimeouts (); /* establishes SIGALRM handler */
4171
4180
PG_SETMASK (& StartupBlockSig );
4172
4181
@@ -4226,8 +4235,8 @@ BackendInitialize(Port *port)
4226
4235
port -> remote_hostname = strdup (remote_host );
4227
4236
4228
4237
/*
4229
- * Ready to begin client interaction. We will give up and exit (1) after a
4230
- * time delay, so that a broken client can't hog a connection
4238
+ * Ready to begin client interaction. We will give up and proc_exit (1)
4239
+ * after a time delay, so that a broken client can't hog a connection
4231
4240
* indefinitely. PreAuthDelay and any DNS interactions above don't count
4232
4241
* against the time limit.
4233
4242
*
@@ -4249,6 +4258,12 @@ BackendInitialize(Port *port)
4249
4258
*/
4250
4259
status = ProcessStartupPacket (port , false);
4251
4260
4261
+ /*
4262
+ * Disable the timeout, and prevent SIGTERM/SIGQUIT again.
4263
+ */
4264
+ disable_timeout (STARTUP_PACKET_TIMEOUT , false);
4265
+ PG_SETMASK (& BlockSig );
4266
+
4252
4267
/*
4253
4268
* Stop here if it was bad or a cancel packet. ProcessStartupPacket
4254
4269
* already did any appropriate error reporting.
@@ -4274,12 +4289,6 @@ BackendInitialize(Port *port)
4274
4289
else
4275
4290
init_ps_display (port -> user_name , port -> database_name , remote_ps_data ,
4276
4291
update_process_title ? "authentication" : "" );
4277
-
4278
- /*
4279
- * Disable the timeout, and prevent SIGTERM/SIGQUIT again.
4280
- */
4281
- disable_timeout (STARTUP_PACKET_TIMEOUT , false);
4282
- PG_SETMASK (& BlockSig );
4283
4292
}
4284
4293
4285
4294
@@ -5168,20 +5177,49 @@ sigusr1_handler(SIGNAL_ARGS)
5168
5177
}
5169
5178
5170
5179
/*
5171
- * SIGTERM or SIGQUIT while processing startup packet.
5180
+ * SIGTERM while processing startup packet.
5172
5181
* Clean up and exit(1).
5173
5182
*
5174
- * XXX: possible future improvement: try to send a message indicating
5175
- * why we are disconnecting. Problem is to be sure we don't block while
5176
- * doing so, nor mess up SSL initialization. In practice, if the client
5177
- * has wedged here, it probably couldn't do anything with the message anyway.
5183
+ * Running proc_exit() from a signal handler is pretty unsafe, since we
5184
+ * can't know what code we've interrupted. But the alternative of using
5185
+ * _exit(2) is also unpalatable, since it'd mean that a "fast shutdown"
5186
+ * would cause a database crash cycle (forcing WAL replay at restart)
5187
+ * if any sessions are in authentication. So we live with it for now.
5188
+ *
5189
+ * One might be tempted to try to send a message indicating why we are
5190
+ * disconnecting. However, that would make this even more unsafe. Also,
5191
+ * it seems undesirable to provide clues about the database's state to
5192
+ * a client that has not yet completed authentication.
5178
5193
*/
5179
5194
static void
5180
- startup_die (SIGNAL_ARGS )
5195
+ process_startup_packet_die (SIGNAL_ARGS )
5181
5196
{
5182
5197
proc_exit (1 );
5183
5198
}
5184
5199
5200
+ /*
5201
+ * SIGQUIT while processing startup packet.
5202
+ *
5203
+ * Some backend has bought the farm,
5204
+ * so we need to stop what we're doing and exit.
5205
+ */
5206
+ static void
5207
+ process_startup_packet_quickdie (SIGNAL_ARGS )
5208
+ {
5209
+ /*
5210
+ * We DO NOT want to run proc_exit() or atexit() callbacks; they wouldn't
5211
+ * be safe to run from a signal handler. Just nail the windows shut and
5212
+ * get out of town.
5213
+ *
5214
+ * Note we do _exit(2) not _exit(1). This is to force the postmaster into
5215
+ * a system reset cycle if someone sends a manual SIGQUIT to a random
5216
+ * backend. (While it might be safe to do _exit(1), since this session
5217
+ * shouldn't have touched shared memory yet, there seems little point in
5218
+ * taking any risks.)
5219
+ */
5220
+ _exit (2 );
5221
+ }
5222
+
5185
5223
/*
5186
5224
* Dummy signal handler
5187
5225
*
@@ -5198,7 +5236,11 @@ dummy_handler(SIGNAL_ARGS)
5198
5236
5199
5237
/*
5200
5238
* Timeout while processing startup packet.
5201
- * As for startup_die(), we clean up and exit(1).
5239
+ * As for process_startup_packet_die(), we clean up and exit(1).
5240
+ *
5241
+ * This is theoretically just as hazardous as in process_startup_packet_die(),
5242
+ * although in practice we're almost certainly waiting for client input,
5243
+ * which greatly reduces the risk.
5202
5244
*/
5203
5245
static void
5204
5246
StartupPacketTimeoutHandler (void )
0 commit comments