diff options
| author | Pedro Magalhães <pmmaga@php.net> | 2019-01-21 23:56:43 +0000 |
|---|---|---|
| committer | Pedro Magalhães <pmmaga@php.net> | 2019-02-18 19:20:18 +0000 |
| commit | bc54e59a3a8bd72ceadb82cf32f2068e38accebf (patch) | |
| tree | 7c9f05e5652eb518aeae147693f689620482ff60 | |
| parent | 3068a32cd04ba09fe87dc59bda701b9c542a6b2a (diff) | |
| download | php-git-bc54e59a3a8bd72ceadb82cf32f2068e38accebf.tar.gz | |
Implement pcntl_unshare
| -rw-r--r-- | ext/pcntl/config.m4 | 2 | ||||
| -rw-r--r-- | ext/pcntl/pcntl.c | 94 | ||||
| -rw-r--r-- | ext/pcntl/php_pcntl.h | 3 | ||||
| -rw-r--r-- | ext/pcntl/tests/pcntl_unshare_01.phpt | 21 | ||||
| -rw-r--r-- | ext/pcntl/tests/pcntl_unshare_02.phpt | 30 | ||||
| -rw-r--r-- | ext/pcntl/tests/pcntl_unshare_03.phpt | 28 |
6 files changed, 177 insertions, 1 deletions
diff --git a/ext/pcntl/config.m4 b/ext/pcntl/config.m4 index fadc7d05b1..41fd0f2ad1 100644 --- a/ext/pcntl/config.m4 +++ b/ext/pcntl/config.m4 @@ -7,7 +7,7 @@ if test "$PHP_PCNTL" != "no"; then AC_CHECK_FUNCS(fork, [ AC_DEFINE(HAVE_FORK,1,[ ]) ], [ AC_MSG_ERROR(pcntl: fork() not supported by this platform) ]) AC_CHECK_FUNCS(waitpid, [ AC_DEFINE(HAVE_WAITPID,1,[ ]) ], [ AC_MSG_ERROR(pcntl: waitpid() not supported by this platform) ]) AC_CHECK_FUNCS(sigaction, [ AC_DEFINE(HAVE_SIGACTION,1,[ ]) ], [ AC_MSG_ERROR(pcntl: sigaction() not supported by this platform) ]) - AC_CHECK_FUNCS([getpriority setpriority wait3 wait4 sigprocmask sigwaitinfo sigtimedwait]) + AC_CHECK_FUNCS([getpriority setpriority wait3 wait4 sigprocmask sigwaitinfo sigtimedwait unshare]) AC_MSG_CHECKING([for siginfo_t]) AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ diff --git a/ext/pcntl/pcntl.c b/ext/pcntl/pcntl.c index e4f940eb02..14378c6db8 100644 --- a/ext/pcntl/pcntl.c +++ b/ext/pcntl/pcntl.c @@ -43,6 +43,9 @@ #endif #include <errno.h> +#ifdef HAVE_UNSHARE +#include <sched.h> +#endif #ifndef NSIG # ifdef SIGRTMAX @@ -166,6 +169,12 @@ ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_INFO_EX(arginfo_pcntl_async_signals, 0, 0, 1) ZEND_ARG_INFO(0, on) ZEND_END_ARG_INFO() + +#ifdef HAVE_UNSHARE +ZEND_BEGIN_ARG_INFO_EX(arginfo_pcntl_unshare, 0, 0, 1) + ZEND_ARG_INFO(0, flags) +ZEND_END_ARG_INFO() +#endif /* }}} */ static const zend_function_entry pcntl_functions[] = { @@ -205,6 +214,9 @@ static const zend_function_entry pcntl_functions[] = { PHP_FE(pcntl_wifcontinued, arginfo_pcntl_wifcontinued) #endif PHP_FE(pcntl_async_signals, arginfo_pcntl_async_signals) +#ifdef HAVE_UNSHARE + PHP_FE(pcntl_unshare, arginfo_pcntl_unshare) +#endif PHP_FE_END }; @@ -464,6 +476,29 @@ void php_register_signal_constants(INIT_FUNC_ARGS) #endif #endif /* HAVE_SIGWAITINFO && HAVE_SIGTIMEDWAIT */ /* }}} */ + + /* unshare(/clone) constants */ +#ifdef HAVE_UNSHARE + REGISTER_LONG_CONSTANT("CLONE_NEWNS", CLONE_NEWNS, CONST_CS | CONST_PERSISTENT); +#ifdef CLONE_NEWIPC + REGISTER_LONG_CONSTANT("CLONE_NEWIPC", CLONE_NEWIPC, CONST_CS | CONST_PERSISTENT); +#endif +#ifdef CLONE_NEWUTS + REGISTER_LONG_CONSTANT("CLONE_NEWUTS", CLONE_NEWUTS, CONST_CS | CONST_PERSISTENT); +#endif +#ifdef CLONE_NEWNET + REGISTER_LONG_CONSTANT("CLONE_NEWNET", CLONE_NEWNET, CONST_CS | CONST_PERSISTENT); +#endif +#ifdef CLONE_NEWPID + REGISTER_LONG_CONSTANT("CLONE_NEWPID", CLONE_NEWPID, CONST_CS | CONST_PERSISTENT); +#endif +#ifdef CLONE_NEWUSER + REGISTER_LONG_CONSTANT("CLONE_NEWUSER", CLONE_NEWUSER, CONST_CS | CONST_PERSISTENT); +#endif +#ifdef CLONE_NEWCGROUP + REGISTER_LONG_CONSTANT("CLONE_NEWCGROUP", CLONE_NEWCGROUP, CONST_CS | CONST_PERSISTENT); +#endif +#endif } static void php_pcntl_register_errno_constants(INIT_FUNC_ARGS) @@ -531,6 +566,12 @@ static void php_pcntl_register_errno_constants(INIT_FUNC_ARGS) #ifdef ETXTBSY REGISTER_PCNTL_ERRNO_CONSTANT(ETXTBSY); #endif +#ifdef ENOSPC + REGISTER_PCNTL_ERRNO_CONSTANT(ENOSPC); +#endif +#ifdef EUSERS + REGISTER_PCNTL_ERRNO_CONSTANT(EUSERS); +#endif } static PHP_GINIT_FUNCTION(pcntl) @@ -1496,6 +1537,59 @@ PHP_FUNCTION(pcntl_async_signals) } /* }}} */ +#ifdef HAVE_UNSHARE +/* {{{ proto bool pcntl_unshare(int flags) + disassociate parts of the process execution context */ +PHP_FUNCTION(pcntl_unshare) +{ + zend_long flags; + int ret; + + ZEND_PARSE_PARAMETERS_START(1, 1) + Z_PARAM_LONG(flags) + ZEND_PARSE_PARAMETERS_END(); + + ret = unshare(flags); + if (ret == -1) { + PCNTL_G(last_error) = errno; + switch (errno) { +#ifdef EINVAL + case EINVAL: + php_error_docref(NULL, E_WARNING, "Error %d: Invalid flag specified", errno); + break; +#endif +#ifdef ENOMEM + case ENOMEM: + php_error_docref(NULL, E_WARNING, "Error %d: Insufficient memory for unshare", errno); + break; +#endif +#ifdef EPERM + case EPERM: + php_error_docref(NULL, E_WARNING, "Error %d: No privilege to use these flags", errno); + break; +#endif +#ifdef ENOSPC + case ENOSPC: + php_error_docref(NULL, E_WARNING, "Error %d: Reached the maximum nesting limit for one of the specified namespaces", errno); + break; +#endif +#ifdef EUSERS + case EUSERS: + php_error_docref(NULL, E_WARNING, "Error %d: Reached the maximum nesting limit for the user namespace", errno); + break; +#endif + default: + php_error_docref(NULL, E_WARNING, "Unknown error %d has occurred", errno); + break; + } + RETURN_FALSE; + } + + RETURN_TRUE; +} +/* }}} */ +#endif + static void pcntl_interrupt_function(zend_execute_data *execute_data) { pcntl_signal_dispatch(); diff --git a/ext/pcntl/php_pcntl.h b/ext/pcntl/php_pcntl.h index 2ddb45dbe8..3a91233754 100644 --- a/ext/pcntl/php_pcntl.h +++ b/ext/pcntl/php_pcntl.h @@ -70,6 +70,9 @@ PHP_FUNCTION(pcntl_getpriority); PHP_FUNCTION(pcntl_setpriority); #endif PHP_FUNCTION(pcntl_async_signals); +#ifdef HAVE_UNSHARE +PHP_FUNCTION(pcntl_unshare); +#endif struct php_pcntl_pending_signal { struct php_pcntl_pending_signal *next; diff --git a/ext/pcntl/tests/pcntl_unshare_01.phpt b/ext/pcntl/tests/pcntl_unshare_01.phpt new file mode 100644 index 0000000000..d914723dc1 --- /dev/null +++ b/ext/pcntl/tests/pcntl_unshare_01.phpt @@ -0,0 +1,21 @@ +--TEST-- +pcntl_unshare() with CLONE_NEWUSER +--SKIPIF-- +<?php +if (!extension_loaded("pcntl")) die("skip"); +if (!extension_loaded("posix")) die("skip posix extension not available"); +if (!function_exists("pcntl_unshare")) die("skip pcntl_unshare is not available"); +if (!defined("CLONE_NEWUSER")) die("skip flag unavailable"); +if (pcntl_unshare(CLONE_NEWUSER) == false && pcntl_get_last_error() == PCNTL_EPERM) { + die("skip Insufficient previleges to use CLONE_NEWUSER"); +} + +--FILE-- +<?php + +$olduid = posix_getuid(); +pcntl_unshare(CLONE_NEWUSER); +$newuid = posix_getuid(); +var_dump($olduid === $newuid); +--EXPECT-- +bool(false) diff --git a/ext/pcntl/tests/pcntl_unshare_02.phpt b/ext/pcntl/tests/pcntl_unshare_02.phpt new file mode 100644 index 0000000000..a046759730 --- /dev/null +++ b/ext/pcntl/tests/pcntl_unshare_02.phpt @@ -0,0 +1,30 @@ +--TEST-- +pcntl_unshare() with CLONE_NEWPID +--SKIPIF-- +<?php +if (!extension_loaded("pcntl")) die("skip"); +if (!extension_loaded("posix")) die("skip posix extension not available"); +if (!function_exists("pcntl_unshare")) die("skip pcntl_unshare is not available"); +if (!defined("CLONE_NEWPID")) die("skip flag unavailable"); +if (posix_getuid() !== 0 && + (!defined("CLONE_NEWUSER") || + (pcntl_unshare(CLONE_NEWUSER) == false && pcntl_get_last_error() == PCNTL_EPERM))) { + die("skip Insufficient previleges to run test"); +} + +--FILE-- +<?php + +if(posix_getuid() !== 0) { + pcntl_unshare(CLONE_NEWUSER); +} + +var_dump(getmypid()); +pcntl_unshare(CLONE_NEWPID); +if(!pcntl_fork()) { + var_dump(getmypid()); + exit(); +} +--EXPECTF-- +int(%d) +int(1) diff --git a/ext/pcntl/tests/pcntl_unshare_03.phpt b/ext/pcntl/tests/pcntl_unshare_03.phpt new file mode 100644 index 0000000000..d69bd40d40 --- /dev/null +++ b/ext/pcntl/tests/pcntl_unshare_03.phpt @@ -0,0 +1,28 @@ +--TEST-- +pcntl_unshare() with CLONE_NEWNET +--SKIPIF-- +<?php +if (!extension_loaded("pcntl")) die("skip"); +if (!extension_loaded("posix")) die("skip posix extension not available"); +if (!function_exists("pcntl_unshare")) die("skip pcntl_unshare is not available"); +if (!defined("CLONE_NEWNET")) die("skip flag unavailable"); +if (posix_getuid() !== 0 && + (!defined("CLONE_NEWUSER") || + (pcntl_unshare(CLONE_NEWUSER) == false && pcntl_get_last_error() == PCNTL_EPERM))) { + die("skip Insufficient previleges to run test"); +} +if (getenv("SKIP_ONLINE_TESTS")) die("skip online test"); + +--FILE-- +<?php + +if(posix_getuid() !== 0) { + pcntl_unshare(CLONE_NEWUSER); +} + +var_dump(gethostbyname('php.net')); +pcntl_unshare(CLONE_NEWNET); +var_dump(gethostbyname('php.net')); +--EXPECTF-- +string(%d) %s +string(7) "php.net" |
