Use PDEATHSIG to kill cli-server workers if parent exists

Closes GH-9476
This commit is contained in:
Ilija Tovilo 2022-09-02 20:17:27 +02:00
parent c200623f28
commit ecc3fc180f
No known key found for this signature in database
GPG key ID: A4F5D403F118200A
8 changed files with 114 additions and 32 deletions

View file

@ -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 */
@ -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.
@ -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
}

View file

@ -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])
])
])

View file

@ -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,[

View file

@ -19,6 +19,7 @@
#include <stdlib.h>
#include <fcntl.h>
#include <assert.h>
#include <signal.h>
#ifdef PHP_WIN32
# include <process.h>
@ -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"
@ -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) {
@ -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;

View file

@ -4,6 +4,7 @@
class CliServerInfo {
public function __construct(
public string $docRoot,
public $processHandle,
) {}
}
@ -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() {

View file

@ -0,0 +1,46 @@
--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_words(?string $lines): array {
return preg_split('(\s)', trim($lines ?? ''), flags: PREG_SPLIT_NO_EMPTY);
}
function find_workers_by_ppid(string $ppid) {
return split_words(shell_exec('pgrep -P ' . $ppid));
}
function find_workers_by_pids(array $pids) {
return split_words(shell_exec('ps -o pid= -p ' . join(',', $pids)));
}
include "php_cli_server.inc";
$cliServerInfo = php_cli_server_start('');
$master = proc_get_status($cliServerInfo->processHandle)['pid'];
$workers = find_workers_by_ppid($master);
if (count($workers) === 0) {
throw new \Exception('Could not find worker pids');
}
proc_terminate($cliServerInfo->processHandle, 9); // SIGKILL
$workers = find_workers_by_pids($workers);
if (count($workers) !== 0) {
throw new \Exception('Workers were not properly terminated');
}
echo 'Done';
?>
--EXPECT--
Done

View file

@ -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])
@ -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

View file

@ -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
@ -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!");