Patch php-fpm-74083-sig-block-reexec_7.2.11_2018-09-28.patch for FPM related Bug #74083
Patch version 2018-10-16 04:49 UTC
Return to Bug #74083 |
Download this patch
Patch Revisions:
Developer: mnikulin@plesk.com
Fix php-fpm failure after concurrent reload attempts. Bug #74083
Postpone signal delivery to the fpm master process till proper signal handlers is set.
Prevent the following case:
* 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.
Index: php-7.2.11/sapi/fpm/fpm/fpm_main.c
===================================================================
--- php-7.2.11.orig/sapi/fpm/fpm/fpm_main.c
+++ php-7.2.11/sapi/fpm/fpm/fpm_main.c
@@ -109,6 +109,10 @@ int __riscosify_control = __RISCOSIFY_ST
#include "fpm_log.h"
#include "zlog.h"
+#if HAVE_SIGNAL_H
+# include "fpm_signals.h"
+#endif
+
#ifndef PHP_WIN32
/* XXX this will need to change later when threaded fastcgi is implemented. shane */
struct sigaction act, old_term, old_quit, old_int;
@@ -1604,6 +1608,15 @@ int main(int argc, char *argv[])
closes it. in apache|apxs mode apache
does that for us! thies@thieso.net
20000419 */
+
+ /* Subset of signals from fpm_signals_init_main() to avoid unexpected death during early init
+ or during reload just after execvp() or fork */
+ int init_signal_array[] = { SIGUSR1, SIGUSR2, SIGCHLD };
+ if (0 > fpm_signals_init_mask(init_signal_array, sizeof(init_signal_array)/sizeof(init_signal_array[0])) ||
+ 0 > fpm_signals_block()) {
+ zlog(ZLOG_WARNING, "Could die in the case of too early reload signal");
+ }
+ zlog(ZLOG_DEBUG, "Blocked some signals");
#endif
#endif
Index: php-7.2.11/sapi/fpm/fpm/fpm_process_ctl.c
===================================================================
--- php-7.2.11.orig/sapi/fpm/fpm/fpm_process_ctl.c
+++ php-7.2.11/sapi/fpm/fpm/fpm_process_ctl.c
@@ -79,6 +79,10 @@ static void fpm_pctl_exit() /* {{{ */
static void fpm_pctl_exec() /* {{{ */
{
+ zlog(ZLOG_DEBUG, "Blocking some signals before reexec");
+ if (0 > fpm_signals_block()) {
+ zlog(ZLOG_WARNING, "concurrent reloads may be unstable");
+ }
zlog(ZLOG_NOTICE, "reloading: execvp(\"%s\", {\"%s\""
"%s%s%s" "%s%s%s" "%s%s%s" "%s%s%s" "%s%s%s"
Index: php-7.2.11/sapi/fpm/fpm/fpm_signals.c
===================================================================
--- php-7.2.11.orig/sapi/fpm/fpm/fpm_signals.c
+++ php-7.2.11/sapi/fpm/fpm/fpm_signals.c
@@ -21,6 +21,7 @@
#include "zlog.h"
static int sp[2];
+static sigset_t block_sigset;
const char *fpm_signal_names[NSIG + 1] = {
#ifdef SIGHUP
@@ -212,6 +213,11 @@ int fpm_signals_init_main() /* {{{ */
zlog(ZLOG_SYSERROR, "failed to init signals: sigaction()");
return -1;
}
+
+ zlog(ZLOG_DEBUG, "Unblocking all signals");
+ if (0 > fpm_signals_unblock()) {
+ return -1;
+ }
return 0;
}
/* }}} */
@@ -253,3 +259,50 @@ int fpm_signals_get_fd() /* {{{ */
}
/* }}} */
+int fpm_signals_init_mask(int *signum_array, size_t size) /* {{{ */
+{
+ size_t i = 0;
+ if (0 > sigemptyset(&block_sigset)) {
+ zlog(ZLOG_SYSERROR, "failed to prepare signal block mask: sigemptyset()");
+ return -1;
+ }
+ for (i = 0; i < size; ++i) {
+ int sig_i = signum_array[i];
+ if (0 > sigaddset(&block_sigset, sig_i)) {
+ if (sig_i <= NSIG && fpm_signal_names[sig_i] != NULL) {
+ zlog(ZLOG_SYSERROR, "failed to prepare signal block mask: sigaddset(%s)",
+ fpm_signal_names[sig_i]);
+ } else {
+ zlog(ZLOG_SYSERROR, "failed to prepare signal block mask: sigaddset(%d)", sig_i);
+ }
+ return -1;
+ }
+ }
+ return 0;
+}
+/* }}} */
+
+int fpm_signals_block() /* {{{ */
+{
+ if (0 > sigprocmask(SIG_BLOCK, &block_sigset, NULL)) {
+ zlog(ZLOG_SYSERROR, "failed to block signals");
+ return -1;
+ }
+ return 0;
+}
+/* }}} */
+
+int fpm_signals_unblock() /* {{{ */
+{
+ /* Ensure that during reload after upgrade all signals are unblocked.
+ block_sigset could have different value before execve() */
+ sigset_t all_signals;
+ sigfillset(&all_signals);
+ if (0 > sigprocmask(SIG_UNBLOCK, &all_signals, NULL)) {
+ zlog(ZLOG_SYSERROR, "failed to unblock signals");
+ return -1;
+ }
+ return 0;
+}
+/* }}} */
+
Index: php-7.2.11/sapi/fpm/fpm/fpm_signals.h
===================================================================
--- php-7.2.11.orig/sapi/fpm/fpm/fpm_signals.h
+++ php-7.2.11/sapi/fpm/fpm/fpm_signals.h
@@ -10,6 +10,9 @@
int fpm_signals_init_main();
int fpm_signals_init_child();
int fpm_signals_get_fd();
+int fpm_signals_init_mask(int *signum_array, size_t size);
+int fpm_signals_block();
+int fpm_signals_unblock();
extern const char *fpm_signal_names[NSIG + 1];
|