@@ -399,7 +399,8 @@ static void SIGHUP_handler(SIGNAL_ARGS);
399
399
static void pmdie (SIGNAL_ARGS );
400
400
static void reaper (SIGNAL_ARGS );
401
401
static void sigusr1_handler (SIGNAL_ARGS );
402
- static void startup_die (SIGNAL_ARGS );
402
+ static void process_startup_packet_die (SIGNAL_ARGS );
403
+ static void process_startup_packet_quickdie (SIGNAL_ARGS );
403
404
static void dummy_handler (SIGNAL_ARGS );
404
405
static void StartupPacketTimeoutHandler (void );
405
406
static void CleanupBackend (int pid , int exitstatus );
@@ -4134,22 +4135,30 @@ BackendInitialize(Port *port)
4134
4135
whereToSendOutput = DestRemote ; /* now safe to ereport to client */
4135
4136
4136
4137
/*
4137
- * We arrange for a simple exit(1) if we receive SIGTERM or SIGQUIT or
4138
- * timeout while trying to collect the startup packet. Otherwise the
4139
- * postmaster cannot shutdown the database FAST or IMMED cleanly if a
4140
- * buggy client fails to send the packet promptly. XXX it follows that
4141
- * the remainder of this function must tolerate losing control at any
4142
- * instant. Likewise, any pg_on_exit_callback registered before or during
4143
- * this function must be prepared to execute at any instant between here
4144
- * and the end of this function. Furthermore, affected callbacks execute
4145
- * partially or not at all when a second exit-inducing signal arrives
4146
- * after proc_exit_prepare() decrements on_proc_exit_index. (Thanks to
4147
- * that mechanic, callbacks need not anticipate more than one call.) This
4148
- * is fragile; it ought to instead follow the norm of handling interrupts
4149
- * at selected, safe opportunities.
4138
+ * We arrange to do proc_exit(1) if we receive SIGTERM or timeout while
4139
+ * trying to collect the startup packet; while SIGQUIT results in
4140
+ * _exit(2). Otherwise the postmaster cannot shutdown the database FAST
4141
+ * or IMMED cleanly if a buggy client fails to send the packet promptly.
4142
+ *
4143
+ * XXX this is pretty dangerous; signal handlers should not call anything
4144
+ * as complex as proc_exit() directly. We minimize the hazard by not
4145
+ * keeping these handlers active for longer than we must. However, it
4146
+ * seems necessary to be able to escape out of DNS lookups as well as the
4147
+ * startup packet reception proper, so we can't narrow the scope further
4148
+ * than is done here.
4149
+ *
4150
+ * XXX it follows that the remainder of this function must tolerate losing
4151
+ * control at any instant. Likewise, any pg_on_exit_callback registered
4152
+ * before or during this function must be prepared to execute at any
4153
+ * instant between here and the end of this function. Furthermore,
4154
+ * affected callbacks execute partially or not at all when a second
4155
+ * exit-inducing signal arrives after proc_exit_prepare() decrements
4156
+ * on_proc_exit_index. (Thanks to that mechanic, callbacks need not
4157
+ * anticipate more than one call.) This is fragile; it ought to instead
4158
+ * follow the norm of handling interrupts at selected, safe opportunities.
4150
4159
*/
4151
- pqsignal (SIGTERM , startup_die );
4152
- pqsignal (SIGQUIT , startup_die );
4160
+ pqsignal (SIGTERM , process_startup_packet_die );
4161
+ pqsignal (SIGQUIT , process_startup_packet_quickdie );
4153
4162
InitializeTimeouts (); /* establishes SIGALRM handler */
4154
4163
PG_SETMASK (& StartupBlockSig );
4155
4164
@@ -4209,8 +4218,8 @@ BackendInitialize(Port *port)
4209
4218
port -> remote_hostname = strdup (remote_host );
4210
4219
4211
4220
/*
4212
- * Ready to begin client interaction. We will give up and exit (1) after a
4213
- * time delay, so that a broken client can't hog a connection
4221
+ * Ready to begin client interaction. We will give up and proc_exit (1)
4222
+ * after a time delay, so that a broken client can't hog a connection
4214
4223
* indefinitely. PreAuthDelay and any DNS interactions above don't count
4215
4224
* against the time limit.
4216
4225
*
@@ -4232,6 +4241,12 @@ BackendInitialize(Port *port)
4232
4241
*/
4233
4242
status = ProcessStartupPacket (port , false);
4234
4243
4244
+ /*
4245
+ * Disable the timeout, and prevent SIGTERM/SIGQUIT again.
4246
+ */
4247
+ disable_timeout (STARTUP_PACKET_TIMEOUT , false);
4248
+ PG_SETMASK (& BlockSig );
4249
+
4235
4250
/*
4236
4251
* Stop here if it was bad or a cancel packet. ProcessStartupPacket
4237
4252
* already did any appropriate error reporting.
@@ -4257,12 +4272,6 @@ BackendInitialize(Port *port)
4257
4272
else
4258
4273
init_ps_display (port -> user_name , port -> database_name , remote_ps_data ,
4259
4274
update_process_title ? "authentication" : "" );
4260
-
4261
- /*
4262
- * Disable the timeout, and prevent SIGTERM/SIGQUIT again.
4263
- */
4264
- disable_timeout (STARTUP_PACKET_TIMEOUT , false);
4265
- PG_SETMASK (& BlockSig );
4266
4275
}
4267
4276
4268
4277
@@ -5115,20 +5124,49 @@ sigusr1_handler(SIGNAL_ARGS)
5115
5124
}
5116
5125
5117
5126
/*
5118
- * SIGTERM or SIGQUIT while processing startup packet.
5127
+ * SIGTERM while processing startup packet.
5119
5128
* Clean up and exit(1).
5120
5129
*
5121
- * XXX: possible future improvement: try to send a message indicating
5122
- * why we are disconnecting. Problem is to be sure we don't block while
5123
- * doing so, nor mess up SSL initialization. In practice, if the client
5124
- * has wedged here, it probably couldn't do anything with the message anyway.
5130
+ * Running proc_exit() from a signal handler is pretty unsafe, since we
5131
+ * can't know what code we've interrupted. But the alternative of using
5132
+ * _exit(2) is also unpalatable, since it'd mean that a "fast shutdown"
5133
+ * would cause a database crash cycle (forcing WAL replay at restart)
5134
+ * if any sessions are in authentication. So we live with it for now.
5135
+ *
5136
+ * One might be tempted to try to send a message indicating why we are
5137
+ * disconnecting. However, that would make this even more unsafe. Also,
5138
+ * it seems undesirable to provide clues about the database's state to
5139
+ * a client that has not yet completed authentication.
5125
5140
*/
5126
5141
static void
5127
- startup_die (SIGNAL_ARGS )
5142
+ process_startup_packet_die (SIGNAL_ARGS )
5128
5143
{
5129
5144
proc_exit (1 );
5130
5145
}
5131
5146
5147
+ /*
5148
+ * SIGQUIT while processing startup packet.
5149
+ *
5150
+ * Some backend has bought the farm,
5151
+ * so we need to stop what we're doing and exit.
5152
+ */
5153
+ static void
5154
+ process_startup_packet_quickdie (SIGNAL_ARGS )
5155
+ {
5156
+ /*
5157
+ * We DO NOT want to run proc_exit() or atexit() callbacks; they wouldn't
5158
+ * be safe to run from a signal handler. Just nail the windows shut and
5159
+ * get out of town.
5160
+ *
5161
+ * Note we do _exit(2) not _exit(1). This is to force the postmaster into
5162
+ * a system reset cycle if someone sends a manual SIGQUIT to a random
5163
+ * backend. (While it might be safe to do _exit(1), since this session
5164
+ * shouldn't have touched shared memory yet, there seems little point in
5165
+ * taking any risks.)
5166
+ */
5167
+ _exit (2 );
5168
+ }
5169
+
5132
5170
/*
5133
5171
* Dummy signal handler
5134
5172
*
@@ -5145,7 +5183,11 @@ dummy_handler(SIGNAL_ARGS)
5145
5183
5146
5184
/*
5147
5185
* Timeout while processing startup packet.
5148
- * As for startup_die(), we clean up and exit(1).
5186
+ * As for process_startup_packet_die(), we clean up and exit(1).
5187
+ *
5188
+ * This is theoretically just as hazardous as in process_startup_packet_die(),
5189
+ * although in practice we're almost certainly waiting for client input,
5190
+ * which greatly reduces the risk.
5149
5191
*/
5150
5192
static void
5151
5193
StartupPacketTimeoutHandler (void )
0 commit comments