Skip to content

Use PDEATHSIG to kill cli-server workers if parent exits #9476

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 3 commits into from
Closed
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions Zend/zend_mmap.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@

#include "zend_portability.h"

#ifdef __linux__
#ifdef HAVE_PRCTL
# include <sys/prctl.h>

/* fallback definitions if our libc is older than the kernel */
Expand All @@ -27,7 +27,7 @@
# ifndef PR_SET_VMA_ANON_NAME
# define PR_SET_VMA_ANON_NAME 0
# endif
#endif // __linux__
#endif // HAVE_PRCTL

/**
* Set a name for the specified memory area.
Expand All @@ -36,7 +36,7 @@
*/
static zend_always_inline void zend_mmap_set_name(const void *start, size_t len, const char *name)
{
#ifdef __linux__
#ifdef HAVE_PRCTL
prctl(PR_SET_VMA, PR_SET_VMA_ANON_NAME, (unsigned long)start, len, (unsigned long)name);
#endif
}
Expand Down
26 changes: 26 additions & 0 deletions build/php.m4
Original file line number Diff line number Diff line change
Expand Up @@ -2748,3 +2748,29 @@ AC_DEFUN([PHP_PATCH_CONFIG_HEADERS], [
$SED -e 's/^#undef PACKAGE_[^ ]*/\/\* & \*\//g' < $srcdir/$1 \
> $srcdir/$1.tmp && mv $srcdir/$1.tmp $srcdir/$1
])

dnl Check if we have prctl
AC_DEFUN([PHP_CHECK_PRCTL],
[
AC_MSG_CHECKING([for prctl])

AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include <sys/prctl.h>]], [[prctl(0, 0, 0, 0, 0);]])], [
AC_DEFINE([HAVE_PRCTL], 1, [do we have prctl?])
AC_MSG_RESULT([yes])
], [
AC_MSG_RESULT([no])
])
])

dnl Check if we have procctl
AC_DEFUN([PHP_CHECK_PROCCTL],
[
AC_MSG_CHECKING([for procctl])

AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include <sys/procctl.h>]], [[procctl(0, 0, 0, 0);]])], [
AC_DEFINE([HAVE_PROCCTL], 1, [do we have procctl?])
AC_MSG_RESULT([yes])
], [
AC_MSG_RESULT([no])
])
])
4 changes: 4 additions & 0 deletions configure.ac
Original file line number Diff line number Diff line change
Expand Up @@ -510,6 +510,10 @@ dnl Check __builtin_cpu_init
PHP_CHECK_BUILTIN_CPU_INIT
dnl Check __builtin_cpu_supports
PHP_CHECK_BUILTIN_CPU_SUPPORTS
dnl Check prctl
PHP_CHECK_PRCTL
dnl Check procctl
PHP_CHECK_PROCCTL

dnl Check for __alignof__ support in the compiler
AC_CACHE_CHECK(whether the compiler supports __alignof__, ac_cv_alignof_exists,[
Expand Down
30 changes: 30 additions & 0 deletions sapi/cli/php_cli_server.c
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
#include <stdlib.h>
#include <fcntl.h>
#include <assert.h>
#include <signal.h>

#ifdef PHP_WIN32
# include <process.h>
Expand Down Expand Up @@ -49,6 +50,14 @@
#include <dlfcn.h>
#endif

#ifdef HAVE_PRCTL
# include <sys/prctl.h>
#endif

#ifdef HAVE_PROCCTL
# include <sys/procctl.h>
#endif

#include "SAPI.h"
#include "php.h"
#include "php_ini.h"
Expand Down Expand Up @@ -2432,6 +2441,24 @@ static char *php_cli_server_parse_addr(const char *addr, int *pport) {
return pestrndup(addr, end - addr, 1);
}

#if defined(HAVE_PRCTL) || defined(HAVE_PROCCTL)
static void php_cli_server_worker_install_pdeathsig(void)
{
// Ignore failure to register PDEATHSIG, it's not available on all platforms anyway
#if defined(HAVE_PRCTL)
prctl(PR_SET_PDEATHSIG, SIGTERM);
#elif defined(HAVE_PROCCTL)
int signal = SIGTERM;
procctl(P_PID, 0, PROC_PDEATHSIG_CTL, &signal);
#endif

// Check if parent has exited just after the fork
if (getppid() != php_cli_server_master) {
exit(1);
}
}
#endif

static void php_cli_server_startup_workers(void) {
char *workers = getenv("PHP_CLI_SERVER_WORKERS");
if (!workers) {
Expand Down Expand Up @@ -2459,6 +2486,9 @@ static void php_cli_server_startup_workers(void) {
php_cli_server_worker + 1;
return;
} else if (pid == 0) {
#if defined(HAVE_PRCTL) || defined(HAVE_PROCCTL)
php_cli_server_worker_install_pdeathsig();
#endif
return;
} else {
php_cli_server_workers[php_cli_server_worker] = pid;
Expand Down
3 changes: 2 additions & 1 deletion sapi/cli/tests/php_cli_server.inc
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
class CliServerInfo {
public function __construct(
public string $docRoot,
public $processHandle,
) {}
}

Expand Down Expand Up @@ -113,7 +114,7 @@ function php_cli_server_start(
define("PHP_CLI_SERVER_PORT", $port);
define("PHP_CLI_SERVER_ADDRESS", PHP_CLI_SERVER_HOSTNAME.":".PHP_CLI_SERVER_PORT);

return new CliServerInfo($doc_root);
return new CliServerInfo($doc_root, $handle);
}

function php_cli_server_connect() {
Expand Down
48 changes: 48 additions & 0 deletions sapi/cli/tests/php_cli_server_pdeathsig.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
--TEST--
Killing server should terminate all worker processes
--ENV--
PHP_CLI_SERVER_WORKERS=2
--SKIPIF--
<?php
include "skipif.inc";
if (!(str_contains(PHP_OS, 'Linux') || str_contains(PHP_OS, 'FreeBSD'))) {
die('skip PDEATHSIG is only supported on Linux and FreeBSD');
}
?>
--FILE--
<?php

function split_ps_pids(?string $lines): array {
return preg_split('(\R)', trim($lines ?? ''), flags: PREG_SPLIT_NO_EMPTY);
}

function get_worker_pids_by_ppid(string $ppid): array {
return split_ps_pids(shell_exec('ps -o pid= --ppid ' . $ppid));
}

function get_worker_pids_by_pids(array $pids): array {
$pidFilters = array_map(fn (string $pid) => '--pid ' . $pid, $pids);
return split_ps_pids(shell_exec('ps -o pid= ' . join(' ', $pidFilters)));
}

include "php_cli_server.inc";
$cliServerInfo = php_cli_server_start('');

$ppid = proc_get_status($cliServerInfo->processHandle)['pid'];

$workerPids = get_worker_pids_by_ppid($ppid);
if (count($workerPids) === 0) {
throw new \Exception('Could not find worker pids');
}

proc_terminate($cliServerInfo->processHandle, 9); // SIGKILL
$workerPids = get_worker_pids_by_pids($workerPids);

if (count($workerPids) !== 0) {
throw new \Exception('Workers were not properly terminated');
}

echo 'Done';
?>
--EXPECT--
Done
26 changes: 0 additions & 26 deletions sapi/fpm/config.m4
Original file line number Diff line number Diff line change
Expand Up @@ -13,30 +13,6 @@ AC_DEFUN([AC_FPM_STDLIBS],
AC_SEARCH_LIBS(inet_addr, nsl)
])

AC_DEFUN([AC_FPM_PRCTL],
[
AC_MSG_CHECKING([for prctl])

AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include <sys/prctl.h>]], [[prctl(0, 0, 0, 0, 0);]])], [
AC_DEFINE([HAVE_PRCTL], 1, [do we have prctl?])
AC_MSG_RESULT([yes])
], [
AC_MSG_RESULT([no])
])
])

AC_DEFUN([AC_FPM_PROCCTL],
[
AC_MSG_CHECKING([for procctl])

AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include <sys/procctl.h>]], [[procctl(0, 0, 0, 0);]])], [
AC_DEFINE([HAVE_PROCCTL], 1, [do we have procctl?])
AC_MSG_RESULT([yes])
], [
AC_MSG_RESULT([no])
])
])

AC_DEFUN([AC_FPM_SETPFLAGS],
[
AC_MSG_CHECKING([for setpflags])
Expand Down Expand Up @@ -530,8 +506,6 @@ if test "$PHP_FPM" != "no"; then
AC_MSG_RESULT($PHP_FPM)

AC_FPM_STDLIBS
AC_FPM_PRCTL
AC_FPM_PROCCTL
AC_FPM_SETPFLAGS
AC_FPM_CLOCK
AC_FPM_TRACE
Expand Down
5 changes: 3 additions & 2 deletions sapi/litespeed/lsapilib.c
Original file line number Diff line number Diff line change
Expand Up @@ -74,10 +74,11 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <sys/un.h>
#include <php_config.h>

#include "lsapilib.h"

#if defined(linux) || defined(__linux) || defined(__linux__) || defined(__gnu_linux__)
#ifdef HAVE_PRCTL
#include <sys/prctl.h>
#endif

Expand Down Expand Up @@ -381,7 +382,7 @@ static void lsapi_enable_core_dump(void)

#endif

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