Skip to content

Commit f26e14c

Browse files
committed
ext/pcntl: adding pcntl_setns for Linux > 5.3
allows a given process to join an existing Linux namespace, relatively complementary to the existing pcntl_unshare.
1 parent bb1688d commit f26e14c

File tree

2 files changed

+69
-1
lines changed

2 files changed

+69
-1
lines changed

ext/pcntl/config.m4

+1-1
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ if test "$PHP_PCNTL" != "no"; then
77
AC_CHECK_FUNCS([fork], [], [AC_MSG_ERROR([pcntl: fork() not supported by this platform])])
88
AC_CHECK_FUNCS([waitpid], [], [AC_MSG_ERROR([pcntl: waitpid() not supported by this platform])])
99
AC_CHECK_FUNCS([sigaction], [], [AC_MSG_ERROR([pcntl: sigaction() not supported by this platform])])
10-
AC_CHECK_FUNCS([getpriority setpriority wait3 wait4 sigwaitinfo sigtimedwait unshare rfork forkx])
10+
AC_CHECK_FUNCS([getpriority setpriority wait3 wait4 sigwaitinfo sigtimedwait unshare rfork forkx pidfd_open])
1111

1212
AC_CHECK_TYPE([siginfo_t],[PCNTL_CFLAGS="-DHAVE_STRUCT_SIGINFO_T"],,[#include <signal.h>])
1313

ext/pcntl/pcntl.c

+68
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,10 @@
4646
#include <sched.h>
4747
#endif
4848

49+
#ifdef HAVE_PIDFD_OPEN
50+
#include <sys/syscall.h>
51+
#endif
52+
4953
#ifdef HAVE_FORKX
5054
#include <sys/fork.h>
5155
#endif
@@ -1402,6 +1406,70 @@ PHP_FUNCTION(pcntl_forkx)
14021406
#endif
14031407
/* }}} */
14041408

1409+
#ifdef HAVE_PIDFD_OPEN
1410+
// The `pidfd_open` syscall is available since 5.3
1411+
// and `setns` since 3.0.
1412+
PHP_FUNCTION(pcntl_setns)
1413+
{
1414+
zend_long pid, nstype = CLONE_NEWNET;
1415+
bool pid_is_null = 1;
1416+
int fd, ret;
1417+
1418+
ZEND_PARSE_PARAMETERS_START(0, 2)
1419+
Z_PARAM_OPTIONAL
1420+
Z_PARAM_LONG_OR_NULL(pid, pid_is_null)
1421+
Z_PARAM_LONG(nstype)
1422+
ZEND_PARSE_PARAMETERS_END();
1423+
1424+
pid = pid_is_null ? getpid() : pid;
1425+
fd = syscall(SYS_pidfd_open, pid, 0);
1426+
if (errno) {
1427+
PCNTL_G(last_error) = errno;
1428+
switch (errno) {
1429+
case EINVAL:
1430+
case ESRCH:
1431+
zend_argument_value_error(1, "is not a valid process (%d)", pid);
1432+
RETURN_THROWS();
1433+
1434+
case ENFILE:
1435+
php_error_docref(NULL, E_WARNING, "Error %d: File descriptors per-process limit reached", errno);
1436+
break;
1437+
1438+
case ENODEV:
1439+
php_error_docref(NULL, E_WARNING, "Error %d: Anonymous inode fs unsupported", errno);
1440+
break;
1441+
1442+
case ENOMEM:
1443+
php_error_docref(NULL, E_WARNING, "Error %d: Insufficient memory for pidfd_open", errno);
1444+
break;
1445+
}
1446+
RETURN_FALSE;
1447+
}
1448+
ret = setns(fd, (int)nstype);
1449+
close(fd);
1450+
1451+
if (ret == -1) {
1452+
PCNTL_G(last_error) = errno;
1453+
switch (errno) {
1454+
case ESRCH:
1455+
zend_argument_value_error(1, "process no longer available (%d)", pid);
1456+
RETURN_THROWS();
1457+
1458+
case EINVAL:
1459+
zend_argument_value_error(2, "is an invalid nstype (%d)", nstype);
1460+
RETURN_THROWS();
1461+
1462+
case EPERM:
1463+
php_error_docref(NULL, E_WARNING, "Error %d: No required capability for this process", errno);
1464+
break;
1465+
}
1466+
RETURN_FALSE;
1467+
} else {
1468+
RETURN_TRUE;
1469+
}
1470+
}
1471+
#endif
1472+
14051473
static void pcntl_interrupt_function(zend_execute_data *execute_data)
14061474
{
14071475
pcntl_signal_dispatch();

0 commit comments

Comments
 (0)