]> granicus.if.org Git - php/commitdiff
Implement pcntl_unshare
authorPedro Magalhães <pmmaga@php.net>
Mon, 21 Jan 2019 23:56:43 +0000 (23:56 +0000)
committerPedro Magalhães <pmmaga@php.net>
Mon, 18 Feb 2019 19:20:18 +0000 (19:20 +0000)
ext/pcntl/config.m4
ext/pcntl/pcntl.c
ext/pcntl/php_pcntl.h
ext/pcntl/tests/pcntl_unshare_01.phpt [new file with mode: 0644]
ext/pcntl/tests/pcntl_unshare_02.phpt [new file with mode: 0644]
ext/pcntl/tests/pcntl_unshare_03.phpt [new file with mode: 0644]

index fadc7d05b19c9faad4f1068785b9a48feebbf313..41fd0f2ad1092219be970fb6d4ea91f6b29529d6 100644 (file)
@@ -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([[
index e4f940eb02957eec67db44a62d90370943989e9f..14378c6db8b26ab0cce0afd711f42b6906db41e1 100644 (file)
@@ -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();
index 2ddb45dbe8c941bbec8b3aa6b89dfe7a062e66c2..3a912337546304ff28087aff561493dd7006c3db 100644 (file)
@@ -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 (file)
index 0000000..d914723
--- /dev/null
@@ -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 (file)
index 0000000..a046759
--- /dev/null
@@ -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 (file)
index 0000000..d69bd40
--- /dev/null
@@ -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"