Skip to content

Commit ecc3fc1

Browse files
committed
Use PDEATHSIG to kill cli-server workers if parent exists
Closes phpGH-9476
1 parent c200623 commit ecc3fc1

File tree

8 files changed

+114
-32
lines changed

8 files changed

+114
-32
lines changed

Diff for: Zend/zend_mmap.h

+3-3
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717

1818
#include "zend_portability.h"
1919

20-
#ifdef __linux__
20+
#ifdef HAVE_PRCTL
2121
# include <sys/prctl.h>
2222

2323
/* fallback definitions if our libc is older than the kernel */
@@ -27,7 +27,7 @@
2727
# ifndef PR_SET_VMA_ANON_NAME
2828
# define PR_SET_VMA_ANON_NAME 0
2929
# endif
30-
#endif // __linux__
30+
#endif // HAVE_PRCTL
3131

3232
/**
3333
* Set a name for the specified memory area.
@@ -36,7 +36,7 @@
3636
*/
3737
static zend_always_inline void zend_mmap_set_name(const void *start, size_t len, const char *name)
3838
{
39-
#ifdef __linux__
39+
#ifdef HAVE_PRCTL
4040
prctl(PR_SET_VMA, PR_SET_VMA_ANON_NAME, (unsigned long)start, len, (unsigned long)name);
4141
#endif
4242
}

Diff for: build/php.m4

+26
Original file line numberDiff line numberDiff line change
@@ -2748,3 +2748,29 @@ AC_DEFUN([PHP_PATCH_CONFIG_HEADERS], [
27482748
$SED -e 's/^#undef PACKAGE_[^ ]*/\/\* & \*\//g' < $srcdir/$1 \
27492749
> $srcdir/$1.tmp && mv $srcdir/$1.tmp $srcdir/$1
27502750
])
2751+
2752+
dnl Check if we have prctl
2753+
AC_DEFUN([PHP_CHECK_PRCTL],
2754+
[
2755+
AC_MSG_CHECKING([for prctl])
2756+
2757+
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include <sys/prctl.h>]], [[prctl(0, 0, 0, 0, 0);]])], [
2758+
AC_DEFINE([HAVE_PRCTL], 1, [do we have prctl?])
2759+
AC_MSG_RESULT([yes])
2760+
], [
2761+
AC_MSG_RESULT([no])
2762+
])
2763+
])
2764+
2765+
dnl Check if we have procctl
2766+
AC_DEFUN([PHP_CHECK_PROCCTL],
2767+
[
2768+
AC_MSG_CHECKING([for procctl])
2769+
2770+
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include <sys/procctl.h>]], [[procctl(0, 0, 0, 0);]])], [
2771+
AC_DEFINE([HAVE_PROCCTL], 1, [do we have procctl?])
2772+
AC_MSG_RESULT([yes])
2773+
], [
2774+
AC_MSG_RESULT([no])
2775+
])
2776+
])

Diff for: configure.ac

+4
Original file line numberDiff line numberDiff line change
@@ -510,6 +510,10 @@ dnl Check __builtin_cpu_init
510510
PHP_CHECK_BUILTIN_CPU_INIT
511511
dnl Check __builtin_cpu_supports
512512
PHP_CHECK_BUILTIN_CPU_SUPPORTS
513+
dnl Check prctl
514+
PHP_CHECK_PRCTL
515+
dnl Check procctl
516+
PHP_CHECK_PROCCTL
513517

514518
dnl Check for __alignof__ support in the compiler
515519
AC_CACHE_CHECK(whether the compiler supports __alignof__, ac_cv_alignof_exists,[

Diff for: sapi/cli/php_cli_server.c

+30
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
#include <stdlib.h>
2020
#include <fcntl.h>
2121
#include <assert.h>
22+
#include <signal.h>
2223

2324
#ifdef PHP_WIN32
2425
# include <process.h>
@@ -49,6 +50,14 @@
4950
#include <dlfcn.h>
5051
#endif
5152

53+
#ifdef HAVE_PRCTL
54+
# include <sys/prctl.h>
55+
#endif
56+
57+
#ifdef HAVE_PROCCTL
58+
# include <sys/procctl.h>
59+
#endif
60+
5261
#include "SAPI.h"
5362
#include "php.h"
5463
#include "php_ini.h"
@@ -2432,6 +2441,24 @@ static char *php_cli_server_parse_addr(const char *addr, int *pport) {
24322441
return pestrndup(addr, end - addr, 1);
24332442
}
24342443

2444+
#if defined(HAVE_PRCTL) || defined(HAVE_PROCCTL)
2445+
static void php_cli_server_worker_install_pdeathsig(void)
2446+
{
2447+
// Ignore failure to register PDEATHSIG, it's not available on all platforms anyway
2448+
#if defined(HAVE_PRCTL)
2449+
prctl(PR_SET_PDEATHSIG, SIGTERM);
2450+
#elif defined(HAVE_PROCCTL)
2451+
int signal = SIGTERM;
2452+
procctl(P_PID, 0, PROC_PDEATHSIG_CTL, &signal);
2453+
#endif
2454+
2455+
// Check if parent has exited just after the fork
2456+
if (getppid() != php_cli_server_master) {
2457+
exit(1);
2458+
}
2459+
}
2460+
#endif
2461+
24352462
static void php_cli_server_startup_workers(void) {
24362463
char *workers = getenv("PHP_CLI_SERVER_WORKERS");
24372464
if (!workers) {
@@ -2459,6 +2486,9 @@ static void php_cli_server_startup_workers(void) {
24592486
php_cli_server_worker + 1;
24602487
return;
24612488
} else if (pid == 0) {
2489+
#if defined(HAVE_PRCTL) || defined(HAVE_PROCCTL)
2490+
php_cli_server_worker_install_pdeathsig();
2491+
#endif
24622492
return;
24632493
} else {
24642494
php_cli_server_workers[php_cli_server_worker] = pid;

Diff for: sapi/cli/tests/php_cli_server.inc

+2-1
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
class CliServerInfo {
55
public function __construct(
66
public string $docRoot,
7+
public $processHandle,
78
) {}
89
}
910

@@ -113,7 +114,7 @@ function php_cli_server_start(
113114
define("PHP_CLI_SERVER_PORT", $port);
114115
define("PHP_CLI_SERVER_ADDRESS", PHP_CLI_SERVER_HOSTNAME.":".PHP_CLI_SERVER_PORT);
115116

116-
return new CliServerInfo($doc_root);
117+
return new CliServerInfo($doc_root, $handle);
117118
}
118119

119120
function php_cli_server_connect() {

Diff for: sapi/cli/tests/php_cli_server_pdeathsig.phpt

+46
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
--TEST--
2+
Killing server should terminate all worker processes
3+
--ENV--
4+
PHP_CLI_SERVER_WORKERS=2
5+
--SKIPIF--
6+
<?php
7+
include "skipif.inc";
8+
if (!(str_contains(PHP_OS, 'Linux') || str_contains(PHP_OS, 'FreeBSD'))) {
9+
die('skip PDEATHSIG is only supported on Linux and FreeBSD');
10+
}
11+
?>
12+
--FILE--
13+
<?php
14+
15+
function split_words(?string $lines): array {
16+
return preg_split('(\s)', trim($lines ?? ''), flags: PREG_SPLIT_NO_EMPTY);
17+
}
18+
19+
function find_workers_by_ppid(string $ppid) {
20+
return split_words(shell_exec('pgrep -P ' . $ppid));
21+
}
22+
23+
function find_workers_by_pids(array $pids) {
24+
return split_words(shell_exec('ps -o pid= -p ' . join(',', $pids)));
25+
}
26+
27+
include "php_cli_server.inc";
28+
$cliServerInfo = php_cli_server_start('');
29+
30+
$master = proc_get_status($cliServerInfo->processHandle)['pid'];
31+
$workers = find_workers_by_ppid($master);
32+
if (count($workers) === 0) {
33+
throw new \Exception('Could not find worker pids');
34+
}
35+
36+
proc_terminate($cliServerInfo->processHandle, 9); // SIGKILL
37+
38+
$workers = find_workers_by_pids($workers);
39+
if (count($workers) !== 0) {
40+
throw new \Exception('Workers were not properly terminated');
41+
}
42+
43+
echo 'Done';
44+
?>
45+
--EXPECT--
46+
Done

Diff for: sapi/fpm/config.m4

-26
Original file line numberDiff line numberDiff line change
@@ -13,30 +13,6 @@ AC_DEFUN([AC_FPM_STDLIBS],
1313
AC_SEARCH_LIBS(inet_addr, nsl)
1414
])
1515

16-
AC_DEFUN([AC_FPM_PRCTL],
17-
[
18-
AC_MSG_CHECKING([for prctl])
19-
20-
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include <sys/prctl.h>]], [[prctl(0, 0, 0, 0, 0);]])], [
21-
AC_DEFINE([HAVE_PRCTL], 1, [do we have prctl?])
22-
AC_MSG_RESULT([yes])
23-
], [
24-
AC_MSG_RESULT([no])
25-
])
26-
])
27-
28-
AC_DEFUN([AC_FPM_PROCCTL],
29-
[
30-
AC_MSG_CHECKING([for procctl])
31-
32-
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include <sys/procctl.h>]], [[procctl(0, 0, 0, 0);]])], [
33-
AC_DEFINE([HAVE_PROCCTL], 1, [do we have procctl?])
34-
AC_MSG_RESULT([yes])
35-
], [
36-
AC_MSG_RESULT([no])
37-
])
38-
])
39-
4016
AC_DEFUN([AC_FPM_SETPFLAGS],
4117
[
4218
AC_MSG_CHECKING([for setpflags])
@@ -530,8 +506,6 @@ if test "$PHP_FPM" != "no"; then
530506
AC_MSG_RESULT($PHP_FPM)
531507

532508
AC_FPM_STDLIBS
533-
AC_FPM_PRCTL
534-
AC_FPM_PROCCTL
535509
AC_FPM_SETPFLAGS
536510
AC_FPM_CLOCK
537511
AC_FPM_TRACE

Diff for: sapi/litespeed/lsapilib.c

+3-2
Original file line numberDiff line numberDiff line change
@@ -74,10 +74,11 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
7474
#include <netinet/in.h>
7575
#include <netinet/tcp.h>
7676
#include <sys/un.h>
77+
#include <php_config.h>
7778

7879
#include "lsapilib.h"
7980

80-
#if defined(linux) || defined(__linux) || defined(__linux__) || defined(__gnu_linux__)
81+
#ifdef HAVE_PRCTL
8182
#include <sys/prctl.h>
8283
#endif
8384

@@ -381,7 +382,7 @@ static void lsapi_enable_core_dump(void)
381382

382383
#endif
383384

384-
#if defined(linux) || defined(__linux) || defined(__linux__) || defined(__gnu_linux__)
385+
#ifdef HAVE_PRCTL
385386
if (prctl(PR_SET_DUMPABLE, s_enable_core_dump,0,0,0) == -1)
386387
perror( "prctl: Failed to set dumpable, "
387388
"core dump may not be available!");

0 commit comments

Comments
 (0)