Fix for https://bugs.php.net/74083 master PHP-fpm is stopped on multiple reloads
backported for 7.4 from

From ae5154c6c6af7ba7c592f8af006b7cadd0d66d6e Mon Sep 17 00:00:00 2001
From: Maksim Nikulin <mnikulin@plesk.com>
Date: Wed, 24 Jul 2019 16:50:57 +0700
Subject: [PATCH] Block signals during fpm master initialization
 
From e37bd5dcc2e8f269c6031d86429311c8cf243060 Mon Sep 17 00:00:00 2001
From: Maksim Nikulin <mnikulin@plesk.com>
Date: Mon, 21 Oct 2019 14:23:29 +0700
Subject: [PATCH] Do not let PHP-FPM children miss SIGTERM, SIGQUIT


diff -up ./sapi/fpm/fpm/fpm_children.c.fpmsig ./sapi/fpm/fpm/fpm_children.c
--- ./sapi/fpm/fpm/fpm_children.c.fpmsig	2020-10-23 10:36:31.423925856 +0200
+++ ./sapi/fpm/fpm/fpm_children.c	2020-10-23 10:36:38.872900642 +0200
@@ -404,6 +404,11 @@ int fpm_children_make(struct fpm_worker_
 			return 2;
 		}
 
+		zlog(ZLOG_DEBUG, "blocking signals before child birth");
+		if (0 > fpm_signals_child_block()) {
+			zlog(ZLOG_WARNING, "child may miss signals");
+		}
+
 		pid = fork();
 
 		switch (pid) {
@@ -415,12 +420,16 @@ int fpm_children_make(struct fpm_worker_
 				return 0;
 
 			case -1 :
+				zlog(ZLOG_DEBUG, "unblocking signals");
+				fpm_signals_unblock();
 				zlog(ZLOG_SYSERROR, "fork() failed");
 
 				fpm_resources_discard(child);
 				return 2;
 
 			default :
+				zlog(ZLOG_DEBUG, "unblocking signals, child born");
+				fpm_signals_unblock();
 				child->pid = pid;
 				fpm_clock_get(&child->started);
 				fpm_parent_resources_use(child);
diff -up ./sapi/fpm/fpm/fpm_main.c.fpmsig ./sapi/fpm/fpm/fpm_main.c
--- ./sapi/fpm/fpm/fpm_main.c.fpmsig	2020-10-13 11:27:02.000000000 +0200
+++ ./sapi/fpm/fpm/fpm_main.c	2020-10-23 10:36:38.873900639 +0200
@@ -90,6 +90,7 @@ int __riscosify_control = __RISCOSIFY_ST
 #include "fpm.h"
 #include "fpm_request.h"
 #include "fpm_status.h"
+#include "fpm_signals.h"
 #include "fpm_conf.h"
 #include "fpm_php.h"
 #include "fpm_log.h"
@@ -1584,6 +1585,11 @@ int main(int argc, char *argv[])
 								closes it.  in apache|apxs mode apache
 								does that for us!  thies@thieso.net
 								20000419 */
+
+	if (0 > fpm_signals_init_mask() || 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
 
diff -up ./sapi/fpm/fpm/fpm_process_ctl.c.fpmsig ./sapi/fpm/fpm/fpm_process_ctl.c
--- ./sapi/fpm/fpm/fpm_process_ctl.c.fpmsig	2020-10-13 11:27:02.000000000 +0200
+++ ./sapi/fpm/fpm/fpm_process_ctl.c	2020-10-23 10:36:11.921991864 +0200
@@ -77,6 +77,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"
diff -up ./sapi/fpm/fpm/fpm_signals.c.fpmsig ./sapi/fpm/fpm/fpm_signals.c
--- ./sapi/fpm/fpm/fpm_signals.c.fpmsig	2020-10-13 11:27:02.000000000 +0200
+++ ./sapi/fpm/fpm/fpm_signals.c	2020-10-23 10:36:38.873900639 +0200
@@ -19,6 +19,8 @@
 #include "zlog.h"
 
 static int sp[2];
+static sigset_t block_sigset;
+static sigset_t child_block_sigset;
 
 const char *fpm_signal_names[NSIG + 1] = {
 #ifdef SIGHUP
@@ -165,8 +167,11 @@ static void sig_handler(int signo) /* {{
 	int saved_errno;
 
 	if (fpm_globals.parent_pid != getpid()) {
-		/* prevent a signal race condition when child process
-			have not set up it's own signal handler yet */
+		/* Avoid using of signal handlers from the master process in a worker
+			before the child sets up its own signal handlers.
+			Normally it is prevented by the sigprocmask() calls
+			around fork(). This execution branch is a last resort trap
+			that has no protection against #76601. */
 		return;
 	}
 
@@ -210,6 +215,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;
 }
 /* }}} */
@@ -241,6 +251,10 @@ int fpm_signals_init_child() /* {{{ */
 	}
 
 	zend_signal_init();
+
+	if (0 > fpm_signals_unblock()) {
+		return -1;
+	}
 	return 0;
 }
 /* }}} */
@@ -250,3 +264,72 @@ int fpm_signals_get_fd() /* {{{ */
 	return sp[0];
 }
 /* }}} */
+
+int fpm_signals_init_mask() /* {{{ */
+{
+	/* Subset of signals from fpm_signals_init_main() and fpm_got_signal()
+		blocked to avoid unexpected death during early init
+		or during reload just after execvp() or fork */
+	int init_signal_array[] = { SIGUSR1, SIGUSR2, SIGCHLD };
+	size_t size = sizeof(init_signal_array)/sizeof(init_signal_array[0]);
+	size_t i = 0;
+	if (0 > sigemptyset(&block_sigset) ||
+	    0 > sigemptyset(&child_block_sigset)) {
+		zlog(ZLOG_SYSERROR, "failed to prepare signal block mask: sigemptyset()");
+		return -1;
+	}
+	for (i = 0; i < size; ++i) {
+		int sig_i = init_signal_array[i];
+		if (0 > sigaddset(&block_sigset, sig_i) ||
+		    0 > sigaddset(&child_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;
+		}
+	}
+	if (0 > sigaddset(&child_block_sigset, SIGTERM) ||
+	    0 > sigaddset(&child_block_sigset, SIGQUIT)) {
+		zlog(ZLOG_SYSERROR, "failed to prepare child signal block mask: sigaddset()");
+		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_child_block() /* {{{ */
+{
+	if (0 > sigprocmask(SIG_BLOCK, &child_block_sigset, NULL)) {
+		zlog(ZLOG_SYSERROR, "failed to block child 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;
+}
+/* }}} */
diff -up ./sapi/fpm/fpm/fpm_signals.h.fpmsig ./sapi/fpm/fpm/fpm_signals.h
--- ./sapi/fpm/fpm/fpm_signals.h.fpmsig	2020-10-13 11:27:02.000000000 +0200
+++ ./sapi/fpm/fpm/fpm_signals.h	2020-10-23 10:36:38.873900639 +0200
@@ -8,6 +8,10 @@
 int fpm_signals_init_main();
 int fpm_signals_init_child();
 int fpm_signals_get_fd();
+int fpm_signals_init_mask();
+int fpm_signals_block();
+int fpm_signals_child_block();
+int fpm_signals_unblock();
 
 extern const char *fpm_signal_names[NSIG + 1];