Skip to content

Commit 8f488f9

Browse files
Mask USR1/HUP while waiting for preloading
Preloading may fork and wait for the child to exit. In case waitpid() is interrupted, the parent exits with a fatal error. This is fine when the syscall is interrupted by a signal whose disposition is set to terminate the process, but not otherwise. In the apache2handler SAPI, the parent is the control process. Restarting apache2 is done by sending SIGUSR1 or SIGHUP to the control process. Doing that during the waitpid() syscall would cause the control process to exit instead. Block the USR1 and HUP signals from being delivered during the syscall when running the apache2handler SAPI, as these are not supposed to terminate the process. FPM is fine as it masks relevant signals during php startup. Fixes GH-20051 Closes GH-20079 Co-authored-by: mycozyhom <[email protected]>
1 parent ce7d4e7 commit 8f488f9

File tree

1 file changed

+33
-1
lines changed

1 file changed

+33
-1
lines changed

ext/opcache/ZendAccelerator.c

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5090,13 +5090,45 @@ static zend_result accel_finish_startup(void)
50905090

50915091
exit(ret == SUCCESS ? 0 : 1);
50925092
} else { /* parent */
5093-
int status;
5093+
# ifdef HAVE_SIGPROCMASK
5094+
/* Interrupting the waitpid() call below with a signal would cause the
5095+
* process to exit. This is fine when the signal disposition is set to
5096+
* terminate the process, but not otherwise.
5097+
* When running the apache2handler, preloading is performed in the
5098+
* control process. SIGUSR1 and SIGHUP are used to tell the control
5099+
* process to restart children. Exiting when these signals are received
5100+
* would unexpectedly shutdown the server instead of restarting it.
5101+
* Block the USR1 and HUP signals from being delivered during the
5102+
* syscall when running the apache2handler SAPI, as these are not
5103+
* supposed to terminate the process. See GH-20051. */
5104+
bool is_apache2handler = strcmp(sapi_module.name, "apache2handler") == 0;
5105+
sigset_t set, oldset;
5106+
if (is_apache2handler) {
5107+
if (sigemptyset(&set)
5108+
|| sigaddset(&set, SIGUSR1)
5109+
|| sigaddset(&set, SIGHUP)) {
5110+
ZEND_UNREACHABLE();
5111+
}
5112+
if (sigprocmask(SIG_BLOCK, &set, &oldset)) {
5113+
ZEND_UNREACHABLE();
5114+
}
5115+
}
5116+
# endif
50945117

5118+
int status;
50955119
if (waitpid(pid, &status, 0) < 0) {
50965120
zend_shared_alloc_unlock();
50975121
zend_accel_error_noreturn(ACCEL_LOG_FATAL, "Preloading failed to waitpid(%d)", pid);
50985122
}
50995123

5124+
# ifdef HAVE_SIGPROCMASK
5125+
if (is_apache2handler) {
5126+
if (sigprocmask(SIG_SETMASK, &oldset, NULL)) {
5127+
ZEND_UNREACHABLE();
5128+
}
5129+
}
5130+
# endif
5131+
51005132
if (ZCSG(preload_script)) {
51015133
preload_load(zend_map_ptr_static_last);
51025134
}

0 commit comments

Comments
 (0)