Skip to content

Commit ae5154c

Browse files
plmnikulinbukka
authored andcommitted
Block signals during fpm master initialization
Fix PHP-FPM failure in the case of concurrent reload attempts. Postpone signal delivery to the fpm master process till proper signal handlers are set. Prevent the following case: - Running master process receives `SIGUSR2` and performs `execvp()`. - Another `SIGUSR2` is arrived before signal handlers are set. - Master process dies. - Requests to the HTTP server handled by PHP-fpm can not be served any more. Block some signals using `sigprocmask()` before `execvp()` and early in the `main()` function. Unblock signals as soon as proper handlers are set. Fixes bug #74083
1 parent 62b053a commit ae5154c

File tree

4 files changed

+70
-0
lines changed

4 files changed

+70
-0
lines changed

sapi/fpm/fpm/fpm_main.c

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,7 @@ int __riscosify_control = __RISCOSIFY_STRICT_UNIX_SPECS;
8686
#include "fpm.h"
8787
#include "fpm_request.h"
8888
#include "fpm_status.h"
89+
#include "fpm_signals.h"
8990
#include "fpm_conf.h"
9091
#include "fpm_php.h"
9192
#include "fpm_log.h"
@@ -1570,6 +1571,15 @@ int main(int argc, char *argv[])
15701571
closes it. in apache|apxs mode apache
15711572
does that for us! thies@thieso.net
15721573
20000419 */
1574+
1575+
/* Subset of signals from fpm_signals_init_main() to avoid unexpected death during early init
1576+
or during reload just after execvp() or fork */
1577+
int init_signal_array[] = { SIGUSR1, SIGUSR2, SIGCHLD };
1578+
if (0 > fpm_signals_init_mask(init_signal_array, sizeof(init_signal_array)/sizeof(init_signal_array[0])) ||
1579+
0 > fpm_signals_block()) {
1580+
zlog(ZLOG_WARNING, "Could die in the case of too early reload signal");
1581+
}
1582+
zlog(ZLOG_DEBUG, "Blocked some signals");
15731583
#endif
15741584

15751585
#ifdef ZTS

sapi/fpm/fpm/fpm_process_ctl.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,10 @@ static void fpm_pctl_exit() /* {{{ */
7777

7878
static void fpm_pctl_exec() /* {{{ */
7979
{
80+
zlog(ZLOG_DEBUG, "Blocking some signals before reexec");
81+
if (0 > fpm_signals_block()) {
82+
zlog(ZLOG_WARNING, "concurrent reloads may be unstable");
83+
}
8084

8185
zlog(ZLOG_NOTICE, "reloading: execvp(\"%s\", {\"%s\""
8286
"%s%s%s" "%s%s%s" "%s%s%s" "%s%s%s" "%s%s%s"

sapi/fpm/fpm/fpm_signals.c

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
#include "zlog.h"
2020

2121
static int sp[2];
22+
static sigset_t block_sigset;
2223

2324
const char *fpm_signal_names[NSIG + 1] = {
2425
#ifdef SIGHUP
@@ -210,6 +211,11 @@ int fpm_signals_init_main() /* {{{ */
210211
zlog(ZLOG_SYSERROR, "failed to init signals: sigaction()");
211212
return -1;
212213
}
214+
215+
zlog(ZLOG_DEBUG, "Unblocking all signals");
216+
if (0 > fpm_signals_unblock()) {
217+
return -1;
218+
}
213219
return 0;
214220
}
215221
/* }}} */
@@ -250,3 +256,50 @@ int fpm_signals_get_fd() /* {{{ */
250256
return sp[0];
251257
}
252258
/* }}} */
259+
260+
int fpm_signals_init_mask(int *signum_array, size_t size) /* {{{ */
261+
{
262+
size_t i = 0;
263+
if (0 > sigemptyset(&block_sigset)) {
264+
zlog(ZLOG_SYSERROR, "failed to prepare signal block mask: sigemptyset()");
265+
return -1;
266+
}
267+
for (i = 0; i < size; ++i) {
268+
int sig_i = signum_array[i];
269+
if (0 > sigaddset(&block_sigset, sig_i)) {
270+
if (sig_i <= NSIG && fpm_signal_names[sig_i] != NULL) {
271+
zlog(ZLOG_SYSERROR, "failed to prepare signal block mask: sigaddset(%s)",
272+
fpm_signal_names[sig_i]);
273+
} else {
274+
zlog(ZLOG_SYSERROR, "failed to prepare signal block mask: sigaddset(%d)", sig_i);
275+
}
276+
return -1;
277+
}
278+
}
279+
return 0;
280+
}
281+
/* }}} */
282+
283+
int fpm_signals_block() /* {{{ */
284+
{
285+
if (0 > sigprocmask(SIG_BLOCK, &block_sigset, NULL)) {
286+
zlog(ZLOG_SYSERROR, "failed to block signals");
287+
return -1;
288+
}
289+
return 0;
290+
}
291+
/* }}} */
292+
293+
int fpm_signals_unblock() /* {{{ */
294+
{
295+
/* Ensure that during reload after upgrade all signals are unblocked.
296+
block_sigset could have different value before execve() */
297+
sigset_t all_signals;
298+
sigfillset(&all_signals);
299+
if (0 > sigprocmask(SIG_UNBLOCK, &all_signals, NULL)) {
300+
zlog(ZLOG_SYSERROR, "failed to unblock signals");
301+
return -1;
302+
}
303+
return 0;
304+
}
305+
/* }}} */

sapi/fpm/fpm/fpm_signals.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,9 @@
88
int fpm_signals_init_main();
99
int fpm_signals_init_child();
1010
int fpm_signals_get_fd();
11+
int fpm_signals_init_mask(int *signum_array, size_t size);
12+
int fpm_signals_block();
13+
int fpm_signals_unblock();
1114

1215
extern const char *fpm_signal_names[NSIG + 1];
1316

0 commit comments

Comments
 (0)