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([[
#endif
#include <errno.h>
+#ifdef HAVE_UNSHARE
+#include <sched.h>
+#endif
#ifndef NSIG
# ifdef SIGRTMAX
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[] = {
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
};
#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)
#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)
}
/* }}} */
+#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();
--- /dev/null
+--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)
--- /dev/null
+--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)
--- /dev/null
+--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"