diff --git a/ext/pcntl/config.m4 b/ext/pcntl/config.m4 index ce26a6efd2ead..0ce36712a6f50 100644 --- a/ext/pcntl/config.m4 +++ b/ext/pcntl/config.m4 @@ -10,7 +10,7 @@ if test "$PHP_PCNTL" != "no"; then done AC_CHECK_FUNCS(m4_normalize([ - forkx + execveat getcpuid getpriority pidfd_open diff --git a/ext/pcntl/pcntl.c b/ext/pcntl/pcntl.c index 8db1d10c698c8..ea7c190e11239 100644 --- a/ext/pcntl/pcntl.c +++ b/ext/pcntl/pcntl.c @@ -39,6 +39,11 @@ #include #endif +#if defined(HAVE_EXECVEAT) +#include +#include +#endif + #ifdef HAVE_WAITID #if defined (HAVE_DECL_P_ALL) && HAVE_DECL_P_ALL == 1 #define HAVE_POSIX_IDTYPES 1 @@ -617,6 +622,40 @@ PHP_FUNCTION(pcntl_wstopsig) } /* }}} */ +#ifdef HAVE_EXECVEAT +static zend_always_inline zend_result php_execve(const char *path, char **argv, char **envp) { + int fd = open(path, O_RDONLY | O_CLOEXEC); + if (fd < 0) { + return FAILURE; + } +#ifdef AT_EXECVE_CHECK + // Linux >= 6.14 allows to check if `path` is allowed + // for execution per kernel security policy (w/o actually running it) + if (execveat(fd, "", argv, envp, AT_EMPTY_PATH | AT_EXECVE_CHECK) < 0) { + close(fd); + return FAILURE; + } +#endif + if (execveat(fd, "", argv, envp, AT_EMPTY_PATH) < 0) { + close(fd); + return FAILURE; + } + return SUCCESS; +} + +static zend_always_inline zend_result php_execv(const char *path, char **argv) { + return php_execve(path, argv, 0); +} +#else +static zend_always_inline zend_result php_execve(const char *path, char **argv, char **envp) { + return execve(path, argv, envp) == 0 ? SUCCESS : FAILURE; +} + +static zend_always_inline zend_result php_execv(const char *path, char **argv) { + return execv(path, argv) == 0 ? SUCCESS : FAILURE; +} +#endif + /* {{{ Executes specified program in current process space as defined by exec(2) */ PHP_FUNCTION(pcntl_exec) { @@ -716,7 +755,7 @@ PHP_FUNCTION(pcntl_exec) } ZEND_HASH_FOREACH_END(); *(pair) = NULL; - if (execve(path, argv, envp) == -1) { + if (php_execve(path, argv, envp) == FAILURE) { PCNTL_G(last_error) = errno; php_error_docref(NULL, E_WARNING, "Error has occurred: (errno %d) %s", errno, strerror(errno)); } @@ -727,7 +766,7 @@ PHP_FUNCTION(pcntl_exec) efree(envp); } else { - if (execv(path, argv) == -1) { + if (php_execv(path, argv) == FAILURE) { PCNTL_G(last_error) = errno; php_error_docref(NULL, E_WARNING, "Error has occurred: (errno %d) %s", errno, strerror(errno)); }