17db96d56Sopenharmony_ci/* Authors: Gregory P. Smith & Jeffrey Yasskin */
27db96d56Sopenharmony_ci#ifndef Py_BUILD_CORE_BUILTIN
37db96d56Sopenharmony_ci#  define Py_BUILD_CORE_MODULE 1
47db96d56Sopenharmony_ci#endif
57db96d56Sopenharmony_ci
67db96d56Sopenharmony_ci#include "Python.h"
77db96d56Sopenharmony_ci#include "pycore_fileutils.h"
87db96d56Sopenharmony_ci#if defined(HAVE_PIPE2) && !defined(_GNU_SOURCE)
97db96d56Sopenharmony_ci# define _GNU_SOURCE
107db96d56Sopenharmony_ci#endif
117db96d56Sopenharmony_ci#include <unistd.h>
127db96d56Sopenharmony_ci#include <fcntl.h>
137db96d56Sopenharmony_ci#ifdef HAVE_SYS_TYPES_H
147db96d56Sopenharmony_ci#include <sys/types.h>
157db96d56Sopenharmony_ci#endif
167db96d56Sopenharmony_ci#if defined(HAVE_SYS_STAT_H)
177db96d56Sopenharmony_ci#include <sys/stat.h>
187db96d56Sopenharmony_ci#endif
197db96d56Sopenharmony_ci#ifdef HAVE_SYS_SYSCALL_H
207db96d56Sopenharmony_ci#include <sys/syscall.h>
217db96d56Sopenharmony_ci#endif
227db96d56Sopenharmony_ci#if defined(HAVE_SYS_RESOURCE_H)
237db96d56Sopenharmony_ci#include <sys/resource.h>
247db96d56Sopenharmony_ci#endif
257db96d56Sopenharmony_ci#ifdef HAVE_DIRENT_H
267db96d56Sopenharmony_ci#include <dirent.h>
277db96d56Sopenharmony_ci#endif
287db96d56Sopenharmony_ci#ifdef HAVE_GRP_H
297db96d56Sopenharmony_ci#include <grp.h>
307db96d56Sopenharmony_ci#endif /* HAVE_GRP_H */
317db96d56Sopenharmony_ci
327db96d56Sopenharmony_ci#include "posixmodule.h"
337db96d56Sopenharmony_ci
347db96d56Sopenharmony_ci#ifdef _Py_MEMORY_SANITIZER
357db96d56Sopenharmony_ci# include <sanitizer/msan_interface.h>
367db96d56Sopenharmony_ci#endif
377db96d56Sopenharmony_ci
387db96d56Sopenharmony_ci#if defined(__ANDROID__) && __ANDROID_API__ < 21 && !defined(SYS_getdents64)
397db96d56Sopenharmony_ci# include <sys/linux-syscalls.h>
407db96d56Sopenharmony_ci# define SYS_getdents64  __NR_getdents64
417db96d56Sopenharmony_ci#endif
427db96d56Sopenharmony_ci
437db96d56Sopenharmony_ci#if defined(__linux__) && defined(HAVE_VFORK) && defined(HAVE_SIGNAL_H) && \
447db96d56Sopenharmony_ci    defined(HAVE_PTHREAD_SIGMASK) && !defined(HAVE_BROKEN_PTHREAD_SIGMASK)
457db96d56Sopenharmony_ci/* If this is ever expanded to non-Linux platforms, verify what calls are
467db96d56Sopenharmony_ci * allowed after vfork(). Ex: setsid() may be disallowed on macOS? */
477db96d56Sopenharmony_ci# include <signal.h>
487db96d56Sopenharmony_ci# define VFORK_USABLE 1
497db96d56Sopenharmony_ci#endif
507db96d56Sopenharmony_ci
517db96d56Sopenharmony_ci#if defined(__sun) && defined(__SVR4)
527db96d56Sopenharmony_ci/* readdir64 is used to work around Solaris 9 bug 6395699. */
537db96d56Sopenharmony_ci# define readdir readdir64
547db96d56Sopenharmony_ci# define dirent dirent64
557db96d56Sopenharmony_ci# if !defined(HAVE_DIRFD)
567db96d56Sopenharmony_ci/* Some versions of Solaris lack dirfd(). */
577db96d56Sopenharmony_ci#  define dirfd(dirp) ((dirp)->dd_fd)
587db96d56Sopenharmony_ci#  define HAVE_DIRFD
597db96d56Sopenharmony_ci# endif
607db96d56Sopenharmony_ci#endif
617db96d56Sopenharmony_ci
627db96d56Sopenharmony_ci#if defined(__FreeBSD__) || (defined(__APPLE__) && defined(__MACH__)) || defined(__DragonFly__)
637db96d56Sopenharmony_ci# define FD_DIR "/dev/fd"
647db96d56Sopenharmony_ci#else
657db96d56Sopenharmony_ci# define FD_DIR "/proc/self/fd"
667db96d56Sopenharmony_ci#endif
677db96d56Sopenharmony_ci
687db96d56Sopenharmony_ci#ifdef NGROUPS_MAX
697db96d56Sopenharmony_ci#define MAX_GROUPS NGROUPS_MAX
707db96d56Sopenharmony_ci#else
717db96d56Sopenharmony_ci#define MAX_GROUPS 64
727db96d56Sopenharmony_ci#endif
737db96d56Sopenharmony_ci
747db96d56Sopenharmony_ci#define POSIX_CALL(call)   do { if ((call) == -1) goto error; } while (0)
757db96d56Sopenharmony_ci
767db96d56Sopenharmony_cistatic struct PyModuleDef _posixsubprocessmodule;
777db96d56Sopenharmony_ci
787db96d56Sopenharmony_ci/* Convert ASCII to a positive int, no libc call. no overflow. -1 on error. */
797db96d56Sopenharmony_cistatic int
807db96d56Sopenharmony_ci_pos_int_from_ascii(const char *name)
817db96d56Sopenharmony_ci{
827db96d56Sopenharmony_ci    int num = 0;
837db96d56Sopenharmony_ci    while (*name >= '0' && *name <= '9') {
847db96d56Sopenharmony_ci        num = num * 10 + (*name - '0');
857db96d56Sopenharmony_ci        ++name;
867db96d56Sopenharmony_ci    }
877db96d56Sopenharmony_ci    if (*name)
887db96d56Sopenharmony_ci        return -1;  /* Non digit found, not a number. */
897db96d56Sopenharmony_ci    return num;
907db96d56Sopenharmony_ci}
917db96d56Sopenharmony_ci
927db96d56Sopenharmony_ci
937db96d56Sopenharmony_ci#if defined(__FreeBSD__) || defined(__DragonFly__)
947db96d56Sopenharmony_ci/* When /dev/fd isn't mounted it is often a static directory populated
957db96d56Sopenharmony_ci * with 0 1 2 or entries for 0 .. 63 on FreeBSD, NetBSD, OpenBSD and DragonFlyBSD.
967db96d56Sopenharmony_ci * NetBSD and OpenBSD have a /proc fs available (though not necessarily
977db96d56Sopenharmony_ci * mounted) and do not have fdescfs for /dev/fd.  MacOS X has a devfs
987db96d56Sopenharmony_ci * that properly supports /dev/fd.
997db96d56Sopenharmony_ci */
1007db96d56Sopenharmony_cistatic int
1017db96d56Sopenharmony_ci_is_fdescfs_mounted_on_dev_fd(void)
1027db96d56Sopenharmony_ci{
1037db96d56Sopenharmony_ci    struct stat dev_stat;
1047db96d56Sopenharmony_ci    struct stat dev_fd_stat;
1057db96d56Sopenharmony_ci    if (stat("/dev", &dev_stat) != 0)
1067db96d56Sopenharmony_ci        return 0;
1077db96d56Sopenharmony_ci    if (stat(FD_DIR, &dev_fd_stat) != 0)
1087db96d56Sopenharmony_ci        return 0;
1097db96d56Sopenharmony_ci    if (dev_stat.st_dev == dev_fd_stat.st_dev)
1107db96d56Sopenharmony_ci        return 0;  /* / == /dev == /dev/fd means it is static. #fail */
1117db96d56Sopenharmony_ci    return 1;
1127db96d56Sopenharmony_ci}
1137db96d56Sopenharmony_ci#endif
1147db96d56Sopenharmony_ci
1157db96d56Sopenharmony_ci
1167db96d56Sopenharmony_ci/* Returns 1 if there is a problem with fd_sequence, 0 otherwise. */
1177db96d56Sopenharmony_cistatic int
1187db96d56Sopenharmony_ci_sanity_check_python_fd_sequence(PyObject *fd_sequence)
1197db96d56Sopenharmony_ci{
1207db96d56Sopenharmony_ci    Py_ssize_t seq_idx;
1217db96d56Sopenharmony_ci    long prev_fd = -1;
1227db96d56Sopenharmony_ci    for (seq_idx = 0; seq_idx < PyTuple_GET_SIZE(fd_sequence); ++seq_idx) {
1237db96d56Sopenharmony_ci        PyObject* py_fd = PyTuple_GET_ITEM(fd_sequence, seq_idx);
1247db96d56Sopenharmony_ci        long iter_fd;
1257db96d56Sopenharmony_ci        if (!PyLong_Check(py_fd)) {
1267db96d56Sopenharmony_ci            return 1;
1277db96d56Sopenharmony_ci        }
1287db96d56Sopenharmony_ci        iter_fd = PyLong_AsLong(py_fd);
1297db96d56Sopenharmony_ci        if (iter_fd < 0 || iter_fd <= prev_fd || iter_fd > INT_MAX) {
1307db96d56Sopenharmony_ci            /* Negative, overflow, unsorted, too big for a fd. */
1317db96d56Sopenharmony_ci            return 1;
1327db96d56Sopenharmony_ci        }
1337db96d56Sopenharmony_ci        prev_fd = iter_fd;
1347db96d56Sopenharmony_ci    }
1357db96d56Sopenharmony_ci    return 0;
1367db96d56Sopenharmony_ci}
1377db96d56Sopenharmony_ci
1387db96d56Sopenharmony_ci
1397db96d56Sopenharmony_ci/* Is fd found in the sorted Python Sequence? */
1407db96d56Sopenharmony_cistatic int
1417db96d56Sopenharmony_ci_is_fd_in_sorted_fd_sequence(int fd, int *fd_sequence,
1427db96d56Sopenharmony_ci                             Py_ssize_t fd_sequence_len)
1437db96d56Sopenharmony_ci{
1447db96d56Sopenharmony_ci    /* Binary search. */
1457db96d56Sopenharmony_ci    Py_ssize_t search_min = 0;
1467db96d56Sopenharmony_ci    Py_ssize_t search_max = fd_sequence_len - 1;
1477db96d56Sopenharmony_ci    if (search_max < 0)
1487db96d56Sopenharmony_ci        return 0;
1497db96d56Sopenharmony_ci    do {
1507db96d56Sopenharmony_ci        long middle = (search_min + search_max) / 2;
1517db96d56Sopenharmony_ci        long middle_fd = fd_sequence[middle];
1527db96d56Sopenharmony_ci        if (fd == middle_fd)
1537db96d56Sopenharmony_ci            return 1;
1547db96d56Sopenharmony_ci        if (fd > middle_fd)
1557db96d56Sopenharmony_ci            search_min = middle + 1;
1567db96d56Sopenharmony_ci        else
1577db96d56Sopenharmony_ci            search_max = middle - 1;
1587db96d56Sopenharmony_ci    } while (search_min <= search_max);
1597db96d56Sopenharmony_ci    return 0;
1607db96d56Sopenharmony_ci}
1617db96d56Sopenharmony_ci
1627db96d56Sopenharmony_ci/*
1637db96d56Sopenharmony_ci * Do all the Python C API calls in the parent process to turn the pass_fds
1647db96d56Sopenharmony_ci * "py_fds_to_keep" tuple into a C array.  The caller owns allocation and
1657db96d56Sopenharmony_ci * freeing of the array.
1667db96d56Sopenharmony_ci *
1677db96d56Sopenharmony_ci * On error an unknown number of array elements may have been filled in.
1687db96d56Sopenharmony_ci * A Python exception has been set when an error is returned.
1697db96d56Sopenharmony_ci *
1707db96d56Sopenharmony_ci * Returns: -1 on error, 0 on success.
1717db96d56Sopenharmony_ci */
1727db96d56Sopenharmony_cistatic int
1737db96d56Sopenharmony_ciconvert_fds_to_keep_to_c(PyObject *py_fds_to_keep, int *c_fds_to_keep)
1747db96d56Sopenharmony_ci{
1757db96d56Sopenharmony_ci    Py_ssize_t i, len;
1767db96d56Sopenharmony_ci
1777db96d56Sopenharmony_ci    len = PyTuple_GET_SIZE(py_fds_to_keep);
1787db96d56Sopenharmony_ci    for (i = 0; i < len; ++i) {
1797db96d56Sopenharmony_ci        PyObject* fdobj = PyTuple_GET_ITEM(py_fds_to_keep, i);
1807db96d56Sopenharmony_ci        long fd = PyLong_AsLong(fdobj);
1817db96d56Sopenharmony_ci        if (fd == -1 && PyErr_Occurred()) {
1827db96d56Sopenharmony_ci            return -1;
1837db96d56Sopenharmony_ci        }
1847db96d56Sopenharmony_ci        if (fd < 0 || fd > INT_MAX) {
1857db96d56Sopenharmony_ci            PyErr_SetString(PyExc_ValueError,
1867db96d56Sopenharmony_ci                            "fd out of range in fds_to_keep.");
1877db96d56Sopenharmony_ci            return -1;
1887db96d56Sopenharmony_ci        }
1897db96d56Sopenharmony_ci        c_fds_to_keep[i] = (int)fd;
1907db96d56Sopenharmony_ci    }
1917db96d56Sopenharmony_ci    return 0;
1927db96d56Sopenharmony_ci}
1937db96d56Sopenharmony_ci
1947db96d56Sopenharmony_ci
1957db96d56Sopenharmony_ci/* This function must be async-signal-safe as it is called from child_exec()
1967db96d56Sopenharmony_ci * after fork() or vfork().
1977db96d56Sopenharmony_ci */
1987db96d56Sopenharmony_cistatic int
1997db96d56Sopenharmony_cimake_inheritable(int *c_fds_to_keep, Py_ssize_t len, int errpipe_write)
2007db96d56Sopenharmony_ci{
2017db96d56Sopenharmony_ci    Py_ssize_t i;
2027db96d56Sopenharmony_ci
2037db96d56Sopenharmony_ci    for (i = 0; i < len; ++i) {
2047db96d56Sopenharmony_ci        int fd = c_fds_to_keep[i];
2057db96d56Sopenharmony_ci        if (fd == errpipe_write) {
2067db96d56Sopenharmony_ci            /* errpipe_write is part of fds_to_keep. It must be closed at
2077db96d56Sopenharmony_ci               exec(), but kept open in the child process until exec() is
2087db96d56Sopenharmony_ci               called. */
2097db96d56Sopenharmony_ci            continue;
2107db96d56Sopenharmony_ci        }
2117db96d56Sopenharmony_ci        if (_Py_set_inheritable_async_safe(fd, 1, NULL) < 0)
2127db96d56Sopenharmony_ci            return -1;
2137db96d56Sopenharmony_ci    }
2147db96d56Sopenharmony_ci    return 0;
2157db96d56Sopenharmony_ci}
2167db96d56Sopenharmony_ci
2177db96d56Sopenharmony_ci
2187db96d56Sopenharmony_ci/* Get the maximum file descriptor that could be opened by this process.
2197db96d56Sopenharmony_ci * This function is async signal safe for use between fork() and exec().
2207db96d56Sopenharmony_ci */
2217db96d56Sopenharmony_cistatic long
2227db96d56Sopenharmony_cisafe_get_max_fd(void)
2237db96d56Sopenharmony_ci{
2247db96d56Sopenharmony_ci    long local_max_fd;
2257db96d56Sopenharmony_ci#if defined(__NetBSD__)
2267db96d56Sopenharmony_ci    local_max_fd = fcntl(0, F_MAXFD);
2277db96d56Sopenharmony_ci    if (local_max_fd >= 0)
2287db96d56Sopenharmony_ci        return local_max_fd;
2297db96d56Sopenharmony_ci#endif
2307db96d56Sopenharmony_ci#if defined(HAVE_SYS_RESOURCE_H) && defined(__OpenBSD__)
2317db96d56Sopenharmony_ci    struct rlimit rl;
2327db96d56Sopenharmony_ci    /* Not on the POSIX async signal safe functions list but likely
2337db96d56Sopenharmony_ci     * safe.  TODO - Someone should audit OpenBSD to make sure. */
2347db96d56Sopenharmony_ci    if (getrlimit(RLIMIT_NOFILE, &rl) >= 0)
2357db96d56Sopenharmony_ci        return (long) rl.rlim_max;
2367db96d56Sopenharmony_ci#endif
2377db96d56Sopenharmony_ci#ifdef _SC_OPEN_MAX
2387db96d56Sopenharmony_ci    local_max_fd = sysconf(_SC_OPEN_MAX);
2397db96d56Sopenharmony_ci    if (local_max_fd == -1)
2407db96d56Sopenharmony_ci#endif
2417db96d56Sopenharmony_ci        local_max_fd = 256;  /* Matches legacy Lib/subprocess.py behavior. */
2427db96d56Sopenharmony_ci    return local_max_fd;
2437db96d56Sopenharmony_ci}
2447db96d56Sopenharmony_ci
2457db96d56Sopenharmony_ci
2467db96d56Sopenharmony_ci/* Close all file descriptors in the given range except for those in
2477db96d56Sopenharmony_ci * fds_to_keep by invoking closer on each subrange.
2487db96d56Sopenharmony_ci *
2497db96d56Sopenharmony_ci * If end_fd == -1, it's guessed via safe_get_max_fd(), but it isn't
2507db96d56Sopenharmony_ci * possible to know for sure what the max fd to go up to is for
2517db96d56Sopenharmony_ci * processes with the capability of raising their maximum, or in case
2527db96d56Sopenharmony_ci * a process opened a high fd and then lowered its maximum.
2537db96d56Sopenharmony_ci */
2547db96d56Sopenharmony_cistatic int
2557db96d56Sopenharmony_ci_close_range_except(int start_fd,
2567db96d56Sopenharmony_ci                    int end_fd,
2577db96d56Sopenharmony_ci                    int *fds_to_keep,
2587db96d56Sopenharmony_ci                    Py_ssize_t fds_to_keep_len,
2597db96d56Sopenharmony_ci                    int (*closer)(int, int))
2607db96d56Sopenharmony_ci{
2617db96d56Sopenharmony_ci    if (end_fd == -1) {
2627db96d56Sopenharmony_ci        end_fd = Py_MIN(safe_get_max_fd(), INT_MAX);
2637db96d56Sopenharmony_ci    }
2647db96d56Sopenharmony_ci    Py_ssize_t keep_seq_idx;
2657db96d56Sopenharmony_ci    /* As fds_to_keep is sorted we can loop through the list closing
2667db96d56Sopenharmony_ci     * fds in between any in the keep list falling within our range. */
2677db96d56Sopenharmony_ci    for (keep_seq_idx = 0; keep_seq_idx < fds_to_keep_len; ++keep_seq_idx) {
2687db96d56Sopenharmony_ci        int keep_fd = fds_to_keep[keep_seq_idx];
2697db96d56Sopenharmony_ci        if (keep_fd < start_fd)
2707db96d56Sopenharmony_ci            continue;
2717db96d56Sopenharmony_ci        if (closer(start_fd, keep_fd - 1) != 0)
2727db96d56Sopenharmony_ci            return -1;
2737db96d56Sopenharmony_ci        start_fd = keep_fd + 1;
2747db96d56Sopenharmony_ci    }
2757db96d56Sopenharmony_ci    if (start_fd <= end_fd) {
2767db96d56Sopenharmony_ci        if (closer(start_fd, end_fd) != 0)
2777db96d56Sopenharmony_ci            return -1;
2787db96d56Sopenharmony_ci    }
2797db96d56Sopenharmony_ci    return 0;
2807db96d56Sopenharmony_ci}
2817db96d56Sopenharmony_ci
2827db96d56Sopenharmony_ci#if defined(__linux__) && defined(HAVE_SYS_SYSCALL_H)
2837db96d56Sopenharmony_ci/* It doesn't matter if d_name has room for NAME_MAX chars; we're using this
2847db96d56Sopenharmony_ci * only to read a directory of short file descriptor number names.  The kernel
2857db96d56Sopenharmony_ci * will return an error if we didn't give it enough space.  Highly Unlikely.
2867db96d56Sopenharmony_ci * This structure is very old and stable: It will not change unless the kernel
2877db96d56Sopenharmony_ci * chooses to break compatibility with all existing binaries.  Highly Unlikely.
2887db96d56Sopenharmony_ci */
2897db96d56Sopenharmony_cistruct linux_dirent64 {
2907db96d56Sopenharmony_ci   unsigned long long d_ino;
2917db96d56Sopenharmony_ci   long long d_off;
2927db96d56Sopenharmony_ci   unsigned short d_reclen;     /* Length of this linux_dirent */
2937db96d56Sopenharmony_ci   unsigned char  d_type;
2947db96d56Sopenharmony_ci   char           d_name[256];  /* Filename (null-terminated) */
2957db96d56Sopenharmony_ci};
2967db96d56Sopenharmony_ci
2977db96d56Sopenharmony_cistatic int
2987db96d56Sopenharmony_ci_brute_force_closer(int first, int last)
2997db96d56Sopenharmony_ci{
3007db96d56Sopenharmony_ci    for (int i = first; i <= last; i++) {
3017db96d56Sopenharmony_ci        /* Ignore errors */
3027db96d56Sopenharmony_ci        (void)close(i);
3037db96d56Sopenharmony_ci    }
3047db96d56Sopenharmony_ci    return 0;
3057db96d56Sopenharmony_ci}
3067db96d56Sopenharmony_ci
3077db96d56Sopenharmony_ci/* Close all open file descriptors in the range from start_fd and higher
3087db96d56Sopenharmony_ci * Do not close any in the sorted fds_to_keep list.
3097db96d56Sopenharmony_ci *
3107db96d56Sopenharmony_ci * This version is async signal safe as it does not make any unsafe C library
3117db96d56Sopenharmony_ci * calls, malloc calls or handle any locks.  It is _unfortunate_ to be forced
3127db96d56Sopenharmony_ci * to resort to making a kernel system call directly but this is the ONLY api
3137db96d56Sopenharmony_ci * available that does no harm.  opendir/readdir/closedir perform memory
3147db96d56Sopenharmony_ci * allocation and locking so while they usually work they are not guaranteed
3157db96d56Sopenharmony_ci * to (especially if you have replaced your malloc implementation).  A version
3167db96d56Sopenharmony_ci * of this function that uses those can be found in the _maybe_unsafe variant.
3177db96d56Sopenharmony_ci *
3187db96d56Sopenharmony_ci * This is Linux specific because that is all I am ready to test it on.  It
3197db96d56Sopenharmony_ci * should be easy to add OS specific dirent or dirent64 structures and modify
3207db96d56Sopenharmony_ci * it with some cpp #define magic to work on other OSes as well if you want.
3217db96d56Sopenharmony_ci */
3227db96d56Sopenharmony_cistatic void
3237db96d56Sopenharmony_ci_close_open_fds_safe(int start_fd, int *fds_to_keep, Py_ssize_t fds_to_keep_len)
3247db96d56Sopenharmony_ci{
3257db96d56Sopenharmony_ci    int fd_dir_fd;
3267db96d56Sopenharmony_ci
3277db96d56Sopenharmony_ci    fd_dir_fd = _Py_open_noraise(FD_DIR, O_RDONLY);
3287db96d56Sopenharmony_ci    if (fd_dir_fd == -1) {
3297db96d56Sopenharmony_ci        /* No way to get a list of open fds. */
3307db96d56Sopenharmony_ci        _close_range_except(start_fd, -1,
3317db96d56Sopenharmony_ci                            fds_to_keep, fds_to_keep_len,
3327db96d56Sopenharmony_ci                            _brute_force_closer);
3337db96d56Sopenharmony_ci        return;
3347db96d56Sopenharmony_ci    } else {
3357db96d56Sopenharmony_ci        char buffer[sizeof(struct linux_dirent64)];
3367db96d56Sopenharmony_ci        int bytes;
3377db96d56Sopenharmony_ci        while ((bytes = syscall(SYS_getdents64, fd_dir_fd,
3387db96d56Sopenharmony_ci                                (struct linux_dirent64 *)buffer,
3397db96d56Sopenharmony_ci                                sizeof(buffer))) > 0) {
3407db96d56Sopenharmony_ci            struct linux_dirent64 *entry;
3417db96d56Sopenharmony_ci            int offset;
3427db96d56Sopenharmony_ci#ifdef _Py_MEMORY_SANITIZER
3437db96d56Sopenharmony_ci            __msan_unpoison(buffer, bytes);
3447db96d56Sopenharmony_ci#endif
3457db96d56Sopenharmony_ci            for (offset = 0; offset < bytes; offset += entry->d_reclen) {
3467db96d56Sopenharmony_ci                int fd;
3477db96d56Sopenharmony_ci                entry = (struct linux_dirent64 *)(buffer + offset);
3487db96d56Sopenharmony_ci                if ((fd = _pos_int_from_ascii(entry->d_name)) < 0)
3497db96d56Sopenharmony_ci                    continue;  /* Not a number. */
3507db96d56Sopenharmony_ci                if (fd != fd_dir_fd && fd >= start_fd &&
3517db96d56Sopenharmony_ci                    !_is_fd_in_sorted_fd_sequence(fd, fds_to_keep,
3527db96d56Sopenharmony_ci                                                  fds_to_keep_len)) {
3537db96d56Sopenharmony_ci                    close(fd);
3547db96d56Sopenharmony_ci                }
3557db96d56Sopenharmony_ci            }
3567db96d56Sopenharmony_ci        }
3577db96d56Sopenharmony_ci        close(fd_dir_fd);
3587db96d56Sopenharmony_ci    }
3597db96d56Sopenharmony_ci}
3607db96d56Sopenharmony_ci
3617db96d56Sopenharmony_ci#define _close_open_fds_fallback _close_open_fds_safe
3627db96d56Sopenharmony_ci
3637db96d56Sopenharmony_ci#else  /* NOT (defined(__linux__) && defined(HAVE_SYS_SYSCALL_H)) */
3647db96d56Sopenharmony_ci
3657db96d56Sopenharmony_cistatic int
3667db96d56Sopenharmony_ci_unsafe_closer(int first, int last)
3677db96d56Sopenharmony_ci{
3687db96d56Sopenharmony_ci    _Py_closerange(first, last);
3697db96d56Sopenharmony_ci    return 0;
3707db96d56Sopenharmony_ci}
3717db96d56Sopenharmony_ci
3727db96d56Sopenharmony_ci/* Close all open file descriptors from start_fd and higher.
3737db96d56Sopenharmony_ci * Do not close any in the sorted fds_to_keep tuple.
3747db96d56Sopenharmony_ci *
3757db96d56Sopenharmony_ci * This function violates the strict use of async signal safe functions. :(
3767db96d56Sopenharmony_ci * It calls opendir(), readdir() and closedir().  Of these, the one most
3777db96d56Sopenharmony_ci * likely to ever cause a problem is opendir() as it performs an internal
3787db96d56Sopenharmony_ci * malloc().  Practically this should not be a problem.  The Java VM makes the
3797db96d56Sopenharmony_ci * same calls between fork and exec in its own UNIXProcess_md.c implementation.
3807db96d56Sopenharmony_ci *
3817db96d56Sopenharmony_ci * readdir_r() is not used because it provides no benefit.  It is typically
3827db96d56Sopenharmony_ci * implemented as readdir() followed by memcpy().  See also:
3837db96d56Sopenharmony_ci *   http://womble.decadent.org.uk/readdir_r-advisory.html
3847db96d56Sopenharmony_ci */
3857db96d56Sopenharmony_cistatic void
3867db96d56Sopenharmony_ci_close_open_fds_maybe_unsafe(int start_fd, int *fds_to_keep,
3877db96d56Sopenharmony_ci                             Py_ssize_t fds_to_keep_len)
3887db96d56Sopenharmony_ci{
3897db96d56Sopenharmony_ci    DIR *proc_fd_dir;
3907db96d56Sopenharmony_ci#ifndef HAVE_DIRFD
3917db96d56Sopenharmony_ci    while (_is_fd_in_sorted_fd_sequence(start_fd, fds_to_keep,
3927db96d56Sopenharmony_ci                                        fds_to_keep_len)) {
3937db96d56Sopenharmony_ci        ++start_fd;
3947db96d56Sopenharmony_ci    }
3957db96d56Sopenharmony_ci    /* Close our lowest fd before we call opendir so that it is likely to
3967db96d56Sopenharmony_ci     * reuse that fd otherwise we might close opendir's file descriptor in
3977db96d56Sopenharmony_ci     * our loop.  This trick assumes that fd's are allocated on a lowest
3987db96d56Sopenharmony_ci     * available basis. */
3997db96d56Sopenharmony_ci    close(start_fd);
4007db96d56Sopenharmony_ci    ++start_fd;
4017db96d56Sopenharmony_ci#endif
4027db96d56Sopenharmony_ci
4037db96d56Sopenharmony_ci#if defined(__FreeBSD__) || defined(__DragonFly__)
4047db96d56Sopenharmony_ci    if (!_is_fdescfs_mounted_on_dev_fd())
4057db96d56Sopenharmony_ci        proc_fd_dir = NULL;
4067db96d56Sopenharmony_ci    else
4077db96d56Sopenharmony_ci#endif
4087db96d56Sopenharmony_ci        proc_fd_dir = opendir(FD_DIR);
4097db96d56Sopenharmony_ci    if (!proc_fd_dir) {
4107db96d56Sopenharmony_ci        /* No way to get a list of open fds. */
4117db96d56Sopenharmony_ci        _close_range_except(start_fd, -1, fds_to_keep, fds_to_keep_len,
4127db96d56Sopenharmony_ci                            _unsafe_closer);
4137db96d56Sopenharmony_ci    } else {
4147db96d56Sopenharmony_ci        struct dirent *dir_entry;
4157db96d56Sopenharmony_ci#ifdef HAVE_DIRFD
4167db96d56Sopenharmony_ci        int fd_used_by_opendir = dirfd(proc_fd_dir);
4177db96d56Sopenharmony_ci#else
4187db96d56Sopenharmony_ci        int fd_used_by_opendir = start_fd - 1;
4197db96d56Sopenharmony_ci#endif
4207db96d56Sopenharmony_ci        errno = 0;
4217db96d56Sopenharmony_ci        while ((dir_entry = readdir(proc_fd_dir))) {
4227db96d56Sopenharmony_ci            int fd;
4237db96d56Sopenharmony_ci            if ((fd = _pos_int_from_ascii(dir_entry->d_name)) < 0)
4247db96d56Sopenharmony_ci                continue;  /* Not a number. */
4257db96d56Sopenharmony_ci            if (fd != fd_used_by_opendir && fd >= start_fd &&
4267db96d56Sopenharmony_ci                !_is_fd_in_sorted_fd_sequence(fd, fds_to_keep,
4277db96d56Sopenharmony_ci                                              fds_to_keep_len)) {
4287db96d56Sopenharmony_ci                close(fd);
4297db96d56Sopenharmony_ci            }
4307db96d56Sopenharmony_ci            errno = 0;
4317db96d56Sopenharmony_ci        }
4327db96d56Sopenharmony_ci        if (errno) {
4337db96d56Sopenharmony_ci            /* readdir error, revert behavior. Highly Unlikely. */
4347db96d56Sopenharmony_ci            _close_range_except(start_fd, -1, fds_to_keep, fds_to_keep_len,
4357db96d56Sopenharmony_ci                                _unsafe_closer);
4367db96d56Sopenharmony_ci        }
4377db96d56Sopenharmony_ci        closedir(proc_fd_dir);
4387db96d56Sopenharmony_ci    }
4397db96d56Sopenharmony_ci}
4407db96d56Sopenharmony_ci
4417db96d56Sopenharmony_ci#define _close_open_fds_fallback _close_open_fds_maybe_unsafe
4427db96d56Sopenharmony_ci
4437db96d56Sopenharmony_ci#endif  /* else NOT (defined(__linux__) && defined(HAVE_SYS_SYSCALL_H)) */
4447db96d56Sopenharmony_ci
4457db96d56Sopenharmony_ci/* We can use close_range() library function only if it's known to be
4467db96d56Sopenharmony_ci * async-signal-safe.
4477db96d56Sopenharmony_ci *
4487db96d56Sopenharmony_ci * On Linux, glibc explicitly documents it to be a thin wrapper over
4497db96d56Sopenharmony_ci * the system call, and other C libraries are likely to follow glibc.
4507db96d56Sopenharmony_ci */
4517db96d56Sopenharmony_ci#if defined(HAVE_CLOSE_RANGE) && \
4527db96d56Sopenharmony_ci    (defined(__linux__) || defined(__FreeBSD__))
4537db96d56Sopenharmony_ci#define HAVE_ASYNC_SAFE_CLOSE_RANGE
4547db96d56Sopenharmony_ci
4557db96d56Sopenharmony_cistatic int
4567db96d56Sopenharmony_ci_close_range_closer(int first, int last)
4577db96d56Sopenharmony_ci{
4587db96d56Sopenharmony_ci    return close_range(first, last, 0);
4597db96d56Sopenharmony_ci}
4607db96d56Sopenharmony_ci#endif
4617db96d56Sopenharmony_ci
4627db96d56Sopenharmony_cistatic void
4637db96d56Sopenharmony_ci_close_open_fds(int start_fd, int *fds_to_keep, Py_ssize_t fds_to_keep_len)
4647db96d56Sopenharmony_ci{
4657db96d56Sopenharmony_ci#ifdef HAVE_ASYNC_SAFE_CLOSE_RANGE
4667db96d56Sopenharmony_ci    if (_close_range_except(
4677db96d56Sopenharmony_ci            start_fd, INT_MAX, fds_to_keep, fds_to_keep_len,
4687db96d56Sopenharmony_ci            _close_range_closer) == 0) {
4697db96d56Sopenharmony_ci        return;
4707db96d56Sopenharmony_ci    }
4717db96d56Sopenharmony_ci#endif
4727db96d56Sopenharmony_ci    _close_open_fds_fallback(start_fd, fds_to_keep, fds_to_keep_len);
4737db96d56Sopenharmony_ci}
4747db96d56Sopenharmony_ci
4757db96d56Sopenharmony_ci#ifdef VFORK_USABLE
4767db96d56Sopenharmony_ci/* Reset dispositions for all signals to SIG_DFL except for ignored
4777db96d56Sopenharmony_ci * signals. This way we ensure that no signal handlers can run
4787db96d56Sopenharmony_ci * after we unblock signals in a child created by vfork().
4797db96d56Sopenharmony_ci */
4807db96d56Sopenharmony_cistatic void
4817db96d56Sopenharmony_cireset_signal_handlers(const sigset_t *child_sigmask)
4827db96d56Sopenharmony_ci{
4837db96d56Sopenharmony_ci    struct sigaction sa_dfl = {.sa_handler = SIG_DFL};
4847db96d56Sopenharmony_ci    for (int sig = 1; sig < _NSIG; sig++) {
4857db96d56Sopenharmony_ci        /* Dispositions for SIGKILL and SIGSTOP can't be changed. */
4867db96d56Sopenharmony_ci        if (sig == SIGKILL || sig == SIGSTOP) {
4877db96d56Sopenharmony_ci            continue;
4887db96d56Sopenharmony_ci        }
4897db96d56Sopenharmony_ci
4907db96d56Sopenharmony_ci        /* There is no need to reset the disposition of signals that will
4917db96d56Sopenharmony_ci         * remain blocked across execve() since the kernel will do it. */
4927db96d56Sopenharmony_ci        if (sigismember(child_sigmask, sig) == 1) {
4937db96d56Sopenharmony_ci            continue;
4947db96d56Sopenharmony_ci        }
4957db96d56Sopenharmony_ci
4967db96d56Sopenharmony_ci        struct sigaction sa;
4977db96d56Sopenharmony_ci        /* C libraries usually return EINVAL for signals used
4987db96d56Sopenharmony_ci         * internally (e.g. for thread cancellation), so simply
4997db96d56Sopenharmony_ci         * skip errors here. */
5007db96d56Sopenharmony_ci        if (sigaction(sig, NULL, &sa) == -1) {
5017db96d56Sopenharmony_ci            continue;
5027db96d56Sopenharmony_ci        }
5037db96d56Sopenharmony_ci
5047db96d56Sopenharmony_ci        /* void *h works as these fields are both pointer types already. */
5057db96d56Sopenharmony_ci        void *h = (sa.sa_flags & SA_SIGINFO ? (void *)sa.sa_sigaction :
5067db96d56Sopenharmony_ci                                              (void *)sa.sa_handler);
5077db96d56Sopenharmony_ci        if (h == SIG_IGN || h == SIG_DFL) {
5087db96d56Sopenharmony_ci            continue;
5097db96d56Sopenharmony_ci        }
5107db96d56Sopenharmony_ci
5117db96d56Sopenharmony_ci        /* This call can't reasonably fail, but if it does, terminating
5127db96d56Sopenharmony_ci         * the child seems to be too harsh, so ignore errors. */
5137db96d56Sopenharmony_ci        (void) sigaction(sig, &sa_dfl, NULL);
5147db96d56Sopenharmony_ci    }
5157db96d56Sopenharmony_ci}
5167db96d56Sopenharmony_ci#endif /* VFORK_USABLE */
5177db96d56Sopenharmony_ci
5187db96d56Sopenharmony_ci
5197db96d56Sopenharmony_ci/*
5207db96d56Sopenharmony_ci * This function is code executed in the child process immediately after
5217db96d56Sopenharmony_ci * (v)fork to set things up and call exec().
5227db96d56Sopenharmony_ci *
5237db96d56Sopenharmony_ci * All of the code in this function must only use async-signal-safe functions,
5247db96d56Sopenharmony_ci * listed at `man 7 signal` or
5257db96d56Sopenharmony_ci * http://www.opengroup.org/onlinepubs/009695399/functions/xsh_chap02_04.html.
5267db96d56Sopenharmony_ci *
5277db96d56Sopenharmony_ci * This restriction is documented at
5287db96d56Sopenharmony_ci * http://www.opengroup.org/onlinepubs/009695399/functions/fork.html.
5297db96d56Sopenharmony_ci *
5307db96d56Sopenharmony_ci * If this function is called after vfork(), even more care must be taken.
5317db96d56Sopenharmony_ci * The lack of preparations that C libraries normally take on fork(),
5327db96d56Sopenharmony_ci * as well as sharing the address space with the parent, might make even
5337db96d56Sopenharmony_ci * async-signal-safe functions vfork-unsafe. In particular, on Linux,
5347db96d56Sopenharmony_ci * set*id() and setgroups() library functions must not be called, since
5357db96d56Sopenharmony_ci * they have to interact with the library-level thread list and send
5367db96d56Sopenharmony_ci * library-internal signals to implement per-process credentials semantics
5377db96d56Sopenharmony_ci * required by POSIX but not supported natively on Linux. Another reason to
5387db96d56Sopenharmony_ci * avoid this family of functions is that sharing an address space between
5397db96d56Sopenharmony_ci * processes running with different privileges is inherently insecure.
5407db96d56Sopenharmony_ci * See bpo-35823 for further discussion and references.
5417db96d56Sopenharmony_ci *
5427db96d56Sopenharmony_ci * In some C libraries, setrlimit() has the same thread list/signalling
5437db96d56Sopenharmony_ci * behavior since resource limits were per-thread attributes before
5447db96d56Sopenharmony_ci * Linux 2.6.10. Musl, as of 1.2.1, is known to have this issue
5457db96d56Sopenharmony_ci * (https://www.openwall.com/lists/musl/2020/10/15/6).
5467db96d56Sopenharmony_ci *
5477db96d56Sopenharmony_ci * If vfork-unsafe functionality is desired after vfork(), consider using
5487db96d56Sopenharmony_ci * syscall() to obtain it.
5497db96d56Sopenharmony_ci */
5507db96d56Sopenharmony_ciPy_NO_INLINE static void
5517db96d56Sopenharmony_cichild_exec(char *const exec_array[],
5527db96d56Sopenharmony_ci           char *const argv[],
5537db96d56Sopenharmony_ci           char *const envp[],
5547db96d56Sopenharmony_ci           const char *cwd,
5557db96d56Sopenharmony_ci           int p2cread, int p2cwrite,
5567db96d56Sopenharmony_ci           int c2pread, int c2pwrite,
5577db96d56Sopenharmony_ci           int errread, int errwrite,
5587db96d56Sopenharmony_ci           int errpipe_read, int errpipe_write,
5597db96d56Sopenharmony_ci           int close_fds, int restore_signals,
5607db96d56Sopenharmony_ci           int call_setsid, pid_t pgid_to_set,
5617db96d56Sopenharmony_ci           int call_setgid, gid_t gid,
5627db96d56Sopenharmony_ci           int call_setgroups, size_t groups_size, const gid_t *groups,
5637db96d56Sopenharmony_ci           int call_setuid, uid_t uid, int child_umask,
5647db96d56Sopenharmony_ci           const void *child_sigmask,
5657db96d56Sopenharmony_ci           int *fds_to_keep, Py_ssize_t fds_to_keep_len,
5667db96d56Sopenharmony_ci           PyObject *preexec_fn,
5677db96d56Sopenharmony_ci           PyObject *preexec_fn_args_tuple)
5687db96d56Sopenharmony_ci{
5697db96d56Sopenharmony_ci    int i, saved_errno, reached_preexec = 0;
5707db96d56Sopenharmony_ci    PyObject *result;
5717db96d56Sopenharmony_ci    const char* err_msg = "";
5727db96d56Sopenharmony_ci    /* Buffer large enough to hold a hex integer.  We can't malloc. */
5737db96d56Sopenharmony_ci    char hex_errno[sizeof(saved_errno)*2+1];
5747db96d56Sopenharmony_ci
5757db96d56Sopenharmony_ci    if (make_inheritable(fds_to_keep, fds_to_keep_len, errpipe_write) < 0)
5767db96d56Sopenharmony_ci        goto error;
5777db96d56Sopenharmony_ci
5787db96d56Sopenharmony_ci    /* Close parent's pipe ends. */
5797db96d56Sopenharmony_ci    if (p2cwrite != -1)
5807db96d56Sopenharmony_ci        POSIX_CALL(close(p2cwrite));
5817db96d56Sopenharmony_ci    if (c2pread != -1)
5827db96d56Sopenharmony_ci        POSIX_CALL(close(c2pread));
5837db96d56Sopenharmony_ci    if (errread != -1)
5847db96d56Sopenharmony_ci        POSIX_CALL(close(errread));
5857db96d56Sopenharmony_ci    POSIX_CALL(close(errpipe_read));
5867db96d56Sopenharmony_ci
5877db96d56Sopenharmony_ci    /* When duping fds, if there arises a situation where one of the fds is
5887db96d56Sopenharmony_ci       either 0, 1 or 2, it is possible that it is overwritten (#12607). */
5897db96d56Sopenharmony_ci    if (c2pwrite == 0) {
5907db96d56Sopenharmony_ci        POSIX_CALL(c2pwrite = dup(c2pwrite));
5917db96d56Sopenharmony_ci        /* issue32270 */
5927db96d56Sopenharmony_ci        if (_Py_set_inheritable_async_safe(c2pwrite, 0, NULL) < 0) {
5937db96d56Sopenharmony_ci            goto error;
5947db96d56Sopenharmony_ci        }
5957db96d56Sopenharmony_ci    }
5967db96d56Sopenharmony_ci    while (errwrite == 0 || errwrite == 1) {
5977db96d56Sopenharmony_ci        POSIX_CALL(errwrite = dup(errwrite));
5987db96d56Sopenharmony_ci        /* issue32270 */
5997db96d56Sopenharmony_ci        if (_Py_set_inheritable_async_safe(errwrite, 0, NULL) < 0) {
6007db96d56Sopenharmony_ci            goto error;
6017db96d56Sopenharmony_ci        }
6027db96d56Sopenharmony_ci    }
6037db96d56Sopenharmony_ci
6047db96d56Sopenharmony_ci    /* Dup fds for child.
6057db96d56Sopenharmony_ci       dup2() removes the CLOEXEC flag but we must do it ourselves if dup2()
6067db96d56Sopenharmony_ci       would be a no-op (issue #10806). */
6077db96d56Sopenharmony_ci    if (p2cread == 0) {
6087db96d56Sopenharmony_ci        if (_Py_set_inheritable_async_safe(p2cread, 1, NULL) < 0)
6097db96d56Sopenharmony_ci            goto error;
6107db96d56Sopenharmony_ci    }
6117db96d56Sopenharmony_ci    else if (p2cread != -1)
6127db96d56Sopenharmony_ci        POSIX_CALL(dup2(p2cread, 0));  /* stdin */
6137db96d56Sopenharmony_ci
6147db96d56Sopenharmony_ci    if (c2pwrite == 1) {
6157db96d56Sopenharmony_ci        if (_Py_set_inheritable_async_safe(c2pwrite, 1, NULL) < 0)
6167db96d56Sopenharmony_ci            goto error;
6177db96d56Sopenharmony_ci    }
6187db96d56Sopenharmony_ci    else if (c2pwrite != -1)
6197db96d56Sopenharmony_ci        POSIX_CALL(dup2(c2pwrite, 1));  /* stdout */
6207db96d56Sopenharmony_ci
6217db96d56Sopenharmony_ci    if (errwrite == 2) {
6227db96d56Sopenharmony_ci        if (_Py_set_inheritable_async_safe(errwrite, 1, NULL) < 0)
6237db96d56Sopenharmony_ci            goto error;
6247db96d56Sopenharmony_ci    }
6257db96d56Sopenharmony_ci    else if (errwrite != -1)
6267db96d56Sopenharmony_ci        POSIX_CALL(dup2(errwrite, 2));  /* stderr */
6277db96d56Sopenharmony_ci
6287db96d56Sopenharmony_ci    /* We no longer manually close p2cread, c2pwrite, and errwrite here as
6297db96d56Sopenharmony_ci     * _close_open_fds takes care when it is not already non-inheritable. */
6307db96d56Sopenharmony_ci
6317db96d56Sopenharmony_ci    if (cwd)
6327db96d56Sopenharmony_ci        POSIX_CALL(chdir(cwd));
6337db96d56Sopenharmony_ci
6347db96d56Sopenharmony_ci    if (child_umask >= 0)
6357db96d56Sopenharmony_ci        umask(child_umask);  /* umask() always succeeds. */
6367db96d56Sopenharmony_ci
6377db96d56Sopenharmony_ci    if (restore_signals)
6387db96d56Sopenharmony_ci        _Py_RestoreSignals();
6397db96d56Sopenharmony_ci
6407db96d56Sopenharmony_ci#ifdef VFORK_USABLE
6417db96d56Sopenharmony_ci    if (child_sigmask) {
6427db96d56Sopenharmony_ci        reset_signal_handlers(child_sigmask);
6437db96d56Sopenharmony_ci        if ((errno = pthread_sigmask(SIG_SETMASK, child_sigmask, NULL))) {
6447db96d56Sopenharmony_ci            goto error;
6457db96d56Sopenharmony_ci        }
6467db96d56Sopenharmony_ci    }
6477db96d56Sopenharmony_ci#endif
6487db96d56Sopenharmony_ci
6497db96d56Sopenharmony_ci#ifdef HAVE_SETSID
6507db96d56Sopenharmony_ci    if (call_setsid)
6517db96d56Sopenharmony_ci        POSIX_CALL(setsid());
6527db96d56Sopenharmony_ci#endif
6537db96d56Sopenharmony_ci
6547db96d56Sopenharmony_ci#ifdef HAVE_SETPGID
6557db96d56Sopenharmony_ci    if (pgid_to_set >= 0)
6567db96d56Sopenharmony_ci        POSIX_CALL(setpgid(0, pgid_to_set));
6577db96d56Sopenharmony_ci#endif
6587db96d56Sopenharmony_ci
6597db96d56Sopenharmony_ci#ifdef HAVE_SETGROUPS
6607db96d56Sopenharmony_ci    if (call_setgroups)
6617db96d56Sopenharmony_ci        POSIX_CALL(setgroups(groups_size, groups));
6627db96d56Sopenharmony_ci#endif /* HAVE_SETGROUPS */
6637db96d56Sopenharmony_ci
6647db96d56Sopenharmony_ci#ifdef HAVE_SETREGID
6657db96d56Sopenharmony_ci    if (call_setgid)
6667db96d56Sopenharmony_ci        POSIX_CALL(setregid(gid, gid));
6677db96d56Sopenharmony_ci#endif /* HAVE_SETREGID */
6687db96d56Sopenharmony_ci
6697db96d56Sopenharmony_ci#ifdef HAVE_SETREUID
6707db96d56Sopenharmony_ci    if (call_setuid)
6717db96d56Sopenharmony_ci        POSIX_CALL(setreuid(uid, uid));
6727db96d56Sopenharmony_ci#endif /* HAVE_SETREUID */
6737db96d56Sopenharmony_ci
6747db96d56Sopenharmony_ci
6757db96d56Sopenharmony_ci    reached_preexec = 1;
6767db96d56Sopenharmony_ci    if (preexec_fn != Py_None && preexec_fn_args_tuple) {
6777db96d56Sopenharmony_ci        /* This is where the user has asked us to deadlock their program. */
6787db96d56Sopenharmony_ci        result = PyObject_Call(preexec_fn, preexec_fn_args_tuple, NULL);
6797db96d56Sopenharmony_ci        if (result == NULL) {
6807db96d56Sopenharmony_ci            /* Stringifying the exception or traceback would involve
6817db96d56Sopenharmony_ci             * memory allocation and thus potential for deadlock.
6827db96d56Sopenharmony_ci             * We've already faced potential deadlock by calling back
6837db96d56Sopenharmony_ci             * into Python in the first place, so it probably doesn't
6847db96d56Sopenharmony_ci             * matter but we avoid it to minimize the possibility. */
6857db96d56Sopenharmony_ci            err_msg = "Exception occurred in preexec_fn.";
6867db96d56Sopenharmony_ci            errno = 0;  /* We don't want to report an OSError. */
6877db96d56Sopenharmony_ci            goto error;
6887db96d56Sopenharmony_ci        }
6897db96d56Sopenharmony_ci        /* Py_DECREF(result); - We're about to exec so why bother? */
6907db96d56Sopenharmony_ci    }
6917db96d56Sopenharmony_ci
6927db96d56Sopenharmony_ci    /* close FDs after executing preexec_fn, which might open FDs */
6937db96d56Sopenharmony_ci    if (close_fds) {
6947db96d56Sopenharmony_ci        /* TODO HP-UX could use pstat_getproc() if anyone cares about it. */
6957db96d56Sopenharmony_ci        _close_open_fds(3, fds_to_keep, fds_to_keep_len);
6967db96d56Sopenharmony_ci    }
6977db96d56Sopenharmony_ci
6987db96d56Sopenharmony_ci    /* This loop matches the Lib/os.py _execvpe()'s PATH search when */
6997db96d56Sopenharmony_ci    /* given the executable_list generated by Lib/subprocess.py.     */
7007db96d56Sopenharmony_ci    saved_errno = 0;
7017db96d56Sopenharmony_ci    for (i = 0; exec_array[i] != NULL; ++i) {
7027db96d56Sopenharmony_ci        const char *executable = exec_array[i];
7037db96d56Sopenharmony_ci        if (envp) {
7047db96d56Sopenharmony_ci            execve(executable, argv, envp);
7057db96d56Sopenharmony_ci        } else {
7067db96d56Sopenharmony_ci            execv(executable, argv);
7077db96d56Sopenharmony_ci        }
7087db96d56Sopenharmony_ci        if (errno != ENOENT && errno != ENOTDIR && saved_errno == 0) {
7097db96d56Sopenharmony_ci            saved_errno = errno;
7107db96d56Sopenharmony_ci        }
7117db96d56Sopenharmony_ci    }
7127db96d56Sopenharmony_ci    /* Report the first exec error, not the last. */
7137db96d56Sopenharmony_ci    if (saved_errno)
7147db96d56Sopenharmony_ci        errno = saved_errno;
7157db96d56Sopenharmony_ci
7167db96d56Sopenharmony_cierror:
7177db96d56Sopenharmony_ci    saved_errno = errno;
7187db96d56Sopenharmony_ci    /* Report the posix error to our parent process. */
7197db96d56Sopenharmony_ci    /* We ignore all write() return values as the total size of our writes is
7207db96d56Sopenharmony_ci       less than PIPEBUF and we cannot do anything about an error anyways.
7217db96d56Sopenharmony_ci       Use _Py_write_noraise() to retry write() if it is interrupted by a
7227db96d56Sopenharmony_ci       signal (fails with EINTR). */
7237db96d56Sopenharmony_ci    if (saved_errno) {
7247db96d56Sopenharmony_ci        char *cur;
7257db96d56Sopenharmony_ci        _Py_write_noraise(errpipe_write, "OSError:", 8);
7267db96d56Sopenharmony_ci        cur = hex_errno + sizeof(hex_errno);
7277db96d56Sopenharmony_ci        while (saved_errno != 0 && cur != hex_errno) {
7287db96d56Sopenharmony_ci            *--cur = Py_hexdigits[saved_errno % 16];
7297db96d56Sopenharmony_ci            saved_errno /= 16;
7307db96d56Sopenharmony_ci        }
7317db96d56Sopenharmony_ci        _Py_write_noraise(errpipe_write, cur, hex_errno + sizeof(hex_errno) - cur);
7327db96d56Sopenharmony_ci        _Py_write_noraise(errpipe_write, ":", 1);
7337db96d56Sopenharmony_ci        if (!reached_preexec) {
7347db96d56Sopenharmony_ci            /* Indicate to the parent that the error happened before exec(). */
7357db96d56Sopenharmony_ci            _Py_write_noraise(errpipe_write, "noexec", 6);
7367db96d56Sopenharmony_ci        }
7377db96d56Sopenharmony_ci        /* We can't call strerror(saved_errno).  It is not async signal safe.
7387db96d56Sopenharmony_ci         * The parent process will look the error message up. */
7397db96d56Sopenharmony_ci    } else {
7407db96d56Sopenharmony_ci        _Py_write_noraise(errpipe_write, "SubprocessError:0:", 18);
7417db96d56Sopenharmony_ci        _Py_write_noraise(errpipe_write, err_msg, strlen(err_msg));
7427db96d56Sopenharmony_ci    }
7437db96d56Sopenharmony_ci}
7447db96d56Sopenharmony_ci
7457db96d56Sopenharmony_ci
7467db96d56Sopenharmony_ci/* The main purpose of this wrapper function is to isolate vfork() from both
7477db96d56Sopenharmony_ci * subprocess_fork_exec() and child_exec(). A child process created via
7487db96d56Sopenharmony_ci * vfork() executes on the same stack as the parent process while the latter is
7497db96d56Sopenharmony_ci * suspended, so this function should not be inlined to avoid compiler bugs
7507db96d56Sopenharmony_ci * that might clobber data needed by the parent later. Additionally,
7517db96d56Sopenharmony_ci * child_exec() should not be inlined to avoid spurious -Wclobber warnings from
7527db96d56Sopenharmony_ci * GCC (see bpo-35823).
7537db96d56Sopenharmony_ci */
7547db96d56Sopenharmony_ciPy_NO_INLINE static pid_t
7557db96d56Sopenharmony_cido_fork_exec(char *const exec_array[],
7567db96d56Sopenharmony_ci             char *const argv[],
7577db96d56Sopenharmony_ci             char *const envp[],
7587db96d56Sopenharmony_ci             const char *cwd,
7597db96d56Sopenharmony_ci             int p2cread, int p2cwrite,
7607db96d56Sopenharmony_ci             int c2pread, int c2pwrite,
7617db96d56Sopenharmony_ci             int errread, int errwrite,
7627db96d56Sopenharmony_ci             int errpipe_read, int errpipe_write,
7637db96d56Sopenharmony_ci             int close_fds, int restore_signals,
7647db96d56Sopenharmony_ci             int call_setsid, pid_t pgid_to_set,
7657db96d56Sopenharmony_ci             int call_setgid, gid_t gid,
7667db96d56Sopenharmony_ci             int call_setgroups, size_t groups_size, const gid_t *groups,
7677db96d56Sopenharmony_ci             int call_setuid, uid_t uid, int child_umask,
7687db96d56Sopenharmony_ci             const void *child_sigmask,
7697db96d56Sopenharmony_ci             int *fds_to_keep, Py_ssize_t fds_to_keep_len,
7707db96d56Sopenharmony_ci             PyObject *preexec_fn,
7717db96d56Sopenharmony_ci             PyObject *preexec_fn_args_tuple)
7727db96d56Sopenharmony_ci{
7737db96d56Sopenharmony_ci
7747db96d56Sopenharmony_ci    pid_t pid;
7757db96d56Sopenharmony_ci
7767db96d56Sopenharmony_ci#ifdef VFORK_USABLE
7777db96d56Sopenharmony_ci    if (child_sigmask) {
7787db96d56Sopenharmony_ci        /* These are checked by our caller; verify them in debug builds. */
7797db96d56Sopenharmony_ci        assert(!call_setuid);
7807db96d56Sopenharmony_ci        assert(!call_setgid);
7817db96d56Sopenharmony_ci        assert(!call_setgroups);
7827db96d56Sopenharmony_ci        assert(preexec_fn == Py_None);
7837db96d56Sopenharmony_ci
7847db96d56Sopenharmony_ci        pid = vfork();
7857db96d56Sopenharmony_ci        if (pid == -1) {
7867db96d56Sopenharmony_ci            /* If vfork() fails, fall back to using fork(). When it isn't
7877db96d56Sopenharmony_ci             * allowed in a process by the kernel, vfork can return -1
7887db96d56Sopenharmony_ci             * with errno EINVAL. https://bugs.python.org/issue47151. */
7897db96d56Sopenharmony_ci            pid = fork();
7907db96d56Sopenharmony_ci        }
7917db96d56Sopenharmony_ci    } else
7927db96d56Sopenharmony_ci#endif
7937db96d56Sopenharmony_ci    {
7947db96d56Sopenharmony_ci        pid = fork();
7957db96d56Sopenharmony_ci    }
7967db96d56Sopenharmony_ci
7977db96d56Sopenharmony_ci    if (pid != 0) {
7987db96d56Sopenharmony_ci        return pid;
7997db96d56Sopenharmony_ci    }
8007db96d56Sopenharmony_ci
8017db96d56Sopenharmony_ci    /* Child process.
8027db96d56Sopenharmony_ci     * See the comment above child_exec() for restrictions imposed on
8037db96d56Sopenharmony_ci     * the code below.
8047db96d56Sopenharmony_ci     */
8057db96d56Sopenharmony_ci
8067db96d56Sopenharmony_ci    if (preexec_fn != Py_None) {
8077db96d56Sopenharmony_ci        /* We'll be calling back into Python later so we need to do this.
8087db96d56Sopenharmony_ci         * This call may not be async-signal-safe but neither is calling
8097db96d56Sopenharmony_ci         * back into Python.  The user asked us to use hope as a strategy
8107db96d56Sopenharmony_ci         * to avoid deadlock... */
8117db96d56Sopenharmony_ci        PyOS_AfterFork_Child();
8127db96d56Sopenharmony_ci    }
8137db96d56Sopenharmony_ci
8147db96d56Sopenharmony_ci    child_exec(exec_array, argv, envp, cwd,
8157db96d56Sopenharmony_ci               p2cread, p2cwrite, c2pread, c2pwrite,
8167db96d56Sopenharmony_ci               errread, errwrite, errpipe_read, errpipe_write,
8177db96d56Sopenharmony_ci               close_fds, restore_signals, call_setsid, pgid_to_set,
8187db96d56Sopenharmony_ci               call_setgid, gid, call_setgroups, groups_size, groups,
8197db96d56Sopenharmony_ci               call_setuid, uid, child_umask, child_sigmask,
8207db96d56Sopenharmony_ci               fds_to_keep, fds_to_keep_len,
8217db96d56Sopenharmony_ci               preexec_fn, preexec_fn_args_tuple);
8227db96d56Sopenharmony_ci    _exit(255);
8237db96d56Sopenharmony_ci    return 0;  /* Dead code to avoid a potential compiler warning. */
8247db96d56Sopenharmony_ci}
8257db96d56Sopenharmony_ci
8267db96d56Sopenharmony_ci
8277db96d56Sopenharmony_cistatic PyObject *
8287db96d56Sopenharmony_cisubprocess_fork_exec(PyObject *module, PyObject *args)
8297db96d56Sopenharmony_ci{
8307db96d56Sopenharmony_ci    PyObject *gc_module = NULL;
8317db96d56Sopenharmony_ci    PyObject *executable_list, *py_fds_to_keep;
8327db96d56Sopenharmony_ci    PyObject *env_list, *preexec_fn;
8337db96d56Sopenharmony_ci    PyObject *process_args, *converted_args = NULL, *fast_args = NULL;
8347db96d56Sopenharmony_ci    PyObject *preexec_fn_args_tuple = NULL;
8357db96d56Sopenharmony_ci    PyObject *groups_list;
8367db96d56Sopenharmony_ci    PyObject *uid_object, *gid_object;
8377db96d56Sopenharmony_ci    int p2cread, p2cwrite, c2pread, c2pwrite, errread, errwrite;
8387db96d56Sopenharmony_ci    int errpipe_read, errpipe_write, close_fds, restore_signals;
8397db96d56Sopenharmony_ci    int call_setsid;
8407db96d56Sopenharmony_ci    pid_t pgid_to_set = -1;
8417db96d56Sopenharmony_ci    int call_setgid = 0, call_setgroups = 0, call_setuid = 0;
8427db96d56Sopenharmony_ci    uid_t uid;
8437db96d56Sopenharmony_ci    gid_t gid, *groups = NULL;
8447db96d56Sopenharmony_ci    int child_umask;
8457db96d56Sopenharmony_ci    PyObject *cwd_obj, *cwd_obj2 = NULL;
8467db96d56Sopenharmony_ci    const char *cwd;
8477db96d56Sopenharmony_ci    pid_t pid = -1;
8487db96d56Sopenharmony_ci    int need_to_reenable_gc = 0;
8497db96d56Sopenharmony_ci    char *const *exec_array, *const *argv = NULL, *const *envp = NULL;
8507db96d56Sopenharmony_ci    Py_ssize_t arg_num, num_groups = 0;
8517db96d56Sopenharmony_ci    int need_after_fork = 0;
8527db96d56Sopenharmony_ci    int saved_errno = 0;
8537db96d56Sopenharmony_ci    int allow_vfork;
8547db96d56Sopenharmony_ci    int *c_fds_to_keep = NULL;
8557db96d56Sopenharmony_ci
8567db96d56Sopenharmony_ci    if (!PyArg_ParseTuple(
8577db96d56Sopenharmony_ci            args, "OOpO!OOiiiiiiiiii" _Py_PARSE_PID "OOOiOp:fork_exec",
8587db96d56Sopenharmony_ci            &process_args, &executable_list,
8597db96d56Sopenharmony_ci            &close_fds, &PyTuple_Type, &py_fds_to_keep,
8607db96d56Sopenharmony_ci            &cwd_obj, &env_list,
8617db96d56Sopenharmony_ci            &p2cread, &p2cwrite, &c2pread, &c2pwrite,
8627db96d56Sopenharmony_ci            &errread, &errwrite, &errpipe_read, &errpipe_write,
8637db96d56Sopenharmony_ci            &restore_signals, &call_setsid, &pgid_to_set,
8647db96d56Sopenharmony_ci            &gid_object, &groups_list, &uid_object, &child_umask,
8657db96d56Sopenharmony_ci            &preexec_fn, &allow_vfork))
8667db96d56Sopenharmony_ci        return NULL;
8677db96d56Sopenharmony_ci
8687db96d56Sopenharmony_ci    if ((preexec_fn != Py_None) &&
8697db96d56Sopenharmony_ci            (PyInterpreterState_Get() != PyInterpreterState_Main())) {
8707db96d56Sopenharmony_ci        PyErr_SetString(PyExc_RuntimeError,
8717db96d56Sopenharmony_ci                        "preexec_fn not supported within subinterpreters");
8727db96d56Sopenharmony_ci        return NULL;
8737db96d56Sopenharmony_ci    }
8747db96d56Sopenharmony_ci
8757db96d56Sopenharmony_ci    if (close_fds && errpipe_write < 3) {  /* precondition */
8767db96d56Sopenharmony_ci        PyErr_SetString(PyExc_ValueError, "errpipe_write must be >= 3");
8777db96d56Sopenharmony_ci        return NULL;
8787db96d56Sopenharmony_ci    }
8797db96d56Sopenharmony_ci    if (_sanity_check_python_fd_sequence(py_fds_to_keep)) {
8807db96d56Sopenharmony_ci        PyErr_SetString(PyExc_ValueError, "bad value(s) in fds_to_keep");
8817db96d56Sopenharmony_ci        return NULL;
8827db96d56Sopenharmony_ci    }
8837db96d56Sopenharmony_ci
8847db96d56Sopenharmony_ci    PyInterpreterState *interp = PyInterpreterState_Get();
8857db96d56Sopenharmony_ci    const PyConfig *config = _PyInterpreterState_GetConfig(interp);
8867db96d56Sopenharmony_ci    if (config->_isolated_interpreter) {
8877db96d56Sopenharmony_ci        PyErr_SetString(PyExc_RuntimeError,
8887db96d56Sopenharmony_ci                        "subprocess not supported for isolated subinterpreters");
8897db96d56Sopenharmony_ci        return NULL;
8907db96d56Sopenharmony_ci    }
8917db96d56Sopenharmony_ci
8927db96d56Sopenharmony_ci    /* We need to call gc.disable() when we'll be calling preexec_fn */
8937db96d56Sopenharmony_ci    if (preexec_fn != Py_None) {
8947db96d56Sopenharmony_ci        need_to_reenable_gc = PyGC_Disable();
8957db96d56Sopenharmony_ci    }
8967db96d56Sopenharmony_ci
8977db96d56Sopenharmony_ci    exec_array = _PySequence_BytesToCharpArray(executable_list);
8987db96d56Sopenharmony_ci    if (!exec_array)
8997db96d56Sopenharmony_ci        goto cleanup;
9007db96d56Sopenharmony_ci
9017db96d56Sopenharmony_ci    /* Convert args and env into appropriate arguments for exec() */
9027db96d56Sopenharmony_ci    /* These conversions are done in the parent process to avoid allocating
9037db96d56Sopenharmony_ci       or freeing memory in the child process. */
9047db96d56Sopenharmony_ci    if (process_args != Py_None) {
9057db96d56Sopenharmony_ci        Py_ssize_t num_args;
9067db96d56Sopenharmony_ci        /* Equivalent to:  */
9077db96d56Sopenharmony_ci        /*  tuple(PyUnicode_FSConverter(arg) for arg in process_args)  */
9087db96d56Sopenharmony_ci        fast_args = PySequence_Fast(process_args, "argv must be a tuple");
9097db96d56Sopenharmony_ci        if (fast_args == NULL)
9107db96d56Sopenharmony_ci            goto cleanup;
9117db96d56Sopenharmony_ci        num_args = PySequence_Fast_GET_SIZE(fast_args);
9127db96d56Sopenharmony_ci        converted_args = PyTuple_New(num_args);
9137db96d56Sopenharmony_ci        if (converted_args == NULL)
9147db96d56Sopenharmony_ci            goto cleanup;
9157db96d56Sopenharmony_ci        for (arg_num = 0; arg_num < num_args; ++arg_num) {
9167db96d56Sopenharmony_ci            PyObject *borrowed_arg, *converted_arg;
9177db96d56Sopenharmony_ci            if (PySequence_Fast_GET_SIZE(fast_args) != num_args) {
9187db96d56Sopenharmony_ci                PyErr_SetString(PyExc_RuntimeError, "args changed during iteration");
9197db96d56Sopenharmony_ci                goto cleanup;
9207db96d56Sopenharmony_ci            }
9217db96d56Sopenharmony_ci            borrowed_arg = PySequence_Fast_GET_ITEM(fast_args, arg_num);
9227db96d56Sopenharmony_ci            if (PyUnicode_FSConverter(borrowed_arg, &converted_arg) == 0)
9237db96d56Sopenharmony_ci                goto cleanup;
9247db96d56Sopenharmony_ci            PyTuple_SET_ITEM(converted_args, arg_num, converted_arg);
9257db96d56Sopenharmony_ci        }
9267db96d56Sopenharmony_ci
9277db96d56Sopenharmony_ci        argv = _PySequence_BytesToCharpArray(converted_args);
9287db96d56Sopenharmony_ci        Py_CLEAR(converted_args);
9297db96d56Sopenharmony_ci        Py_CLEAR(fast_args);
9307db96d56Sopenharmony_ci        if (!argv)
9317db96d56Sopenharmony_ci            goto cleanup;
9327db96d56Sopenharmony_ci    }
9337db96d56Sopenharmony_ci
9347db96d56Sopenharmony_ci    if (env_list != Py_None) {
9357db96d56Sopenharmony_ci        envp = _PySequence_BytesToCharpArray(env_list);
9367db96d56Sopenharmony_ci        if (!envp)
9377db96d56Sopenharmony_ci            goto cleanup;
9387db96d56Sopenharmony_ci    }
9397db96d56Sopenharmony_ci
9407db96d56Sopenharmony_ci    if (cwd_obj != Py_None) {
9417db96d56Sopenharmony_ci        if (PyUnicode_FSConverter(cwd_obj, &cwd_obj2) == 0)
9427db96d56Sopenharmony_ci            goto cleanup;
9437db96d56Sopenharmony_ci        cwd = PyBytes_AsString(cwd_obj2);
9447db96d56Sopenharmony_ci    } else {
9457db96d56Sopenharmony_ci        cwd = NULL;
9467db96d56Sopenharmony_ci    }
9477db96d56Sopenharmony_ci
9487db96d56Sopenharmony_ci    if (groups_list != Py_None) {
9497db96d56Sopenharmony_ci#ifdef HAVE_SETGROUPS
9507db96d56Sopenharmony_ci        Py_ssize_t i;
9517db96d56Sopenharmony_ci        gid_t gid;
9527db96d56Sopenharmony_ci
9537db96d56Sopenharmony_ci        if (!PyList_Check(groups_list)) {
9547db96d56Sopenharmony_ci            PyErr_SetString(PyExc_TypeError,
9557db96d56Sopenharmony_ci                    "setgroups argument must be a list");
9567db96d56Sopenharmony_ci            goto cleanup;
9577db96d56Sopenharmony_ci        }
9587db96d56Sopenharmony_ci        num_groups = PySequence_Size(groups_list);
9597db96d56Sopenharmony_ci
9607db96d56Sopenharmony_ci        if (num_groups < 0)
9617db96d56Sopenharmony_ci            goto cleanup;
9627db96d56Sopenharmony_ci
9637db96d56Sopenharmony_ci        if (num_groups > MAX_GROUPS) {
9647db96d56Sopenharmony_ci            PyErr_SetString(PyExc_ValueError, "too many groups");
9657db96d56Sopenharmony_ci            goto cleanup;
9667db96d56Sopenharmony_ci        }
9677db96d56Sopenharmony_ci
9687db96d56Sopenharmony_ci        if ((groups = PyMem_RawMalloc(num_groups * sizeof(gid_t))) == NULL) {
9697db96d56Sopenharmony_ci            PyErr_SetString(PyExc_MemoryError,
9707db96d56Sopenharmony_ci                    "failed to allocate memory for group list");
9717db96d56Sopenharmony_ci            goto cleanup;
9727db96d56Sopenharmony_ci        }
9737db96d56Sopenharmony_ci
9747db96d56Sopenharmony_ci        for (i = 0; i < num_groups; i++) {
9757db96d56Sopenharmony_ci            PyObject *elem;
9767db96d56Sopenharmony_ci            elem = PySequence_GetItem(groups_list, i);
9777db96d56Sopenharmony_ci            if (!elem)
9787db96d56Sopenharmony_ci                goto cleanup;
9797db96d56Sopenharmony_ci            if (!PyLong_Check(elem)) {
9807db96d56Sopenharmony_ci                PyErr_SetString(PyExc_TypeError,
9817db96d56Sopenharmony_ci                                "groups must be integers");
9827db96d56Sopenharmony_ci                Py_DECREF(elem);
9837db96d56Sopenharmony_ci                goto cleanup;
9847db96d56Sopenharmony_ci            } else {
9857db96d56Sopenharmony_ci                if (!_Py_Gid_Converter(elem, &gid)) {
9867db96d56Sopenharmony_ci                    Py_DECREF(elem);
9877db96d56Sopenharmony_ci                    PyErr_SetString(PyExc_ValueError, "invalid group id");
9887db96d56Sopenharmony_ci                    goto cleanup;
9897db96d56Sopenharmony_ci                }
9907db96d56Sopenharmony_ci                groups[i] = gid;
9917db96d56Sopenharmony_ci            }
9927db96d56Sopenharmony_ci            Py_DECREF(elem);
9937db96d56Sopenharmony_ci        }
9947db96d56Sopenharmony_ci        call_setgroups = 1;
9957db96d56Sopenharmony_ci
9967db96d56Sopenharmony_ci#else /* HAVE_SETGROUPS */
9977db96d56Sopenharmony_ci        PyErr_BadInternalCall();
9987db96d56Sopenharmony_ci        goto cleanup;
9997db96d56Sopenharmony_ci#endif /* HAVE_SETGROUPS */
10007db96d56Sopenharmony_ci    }
10017db96d56Sopenharmony_ci
10027db96d56Sopenharmony_ci    if (gid_object != Py_None) {
10037db96d56Sopenharmony_ci#ifdef HAVE_SETREGID
10047db96d56Sopenharmony_ci        if (!_Py_Gid_Converter(gid_object, &gid))
10057db96d56Sopenharmony_ci            goto cleanup;
10067db96d56Sopenharmony_ci
10077db96d56Sopenharmony_ci        call_setgid = 1;
10087db96d56Sopenharmony_ci
10097db96d56Sopenharmony_ci#else /* HAVE_SETREGID */
10107db96d56Sopenharmony_ci        PyErr_BadInternalCall();
10117db96d56Sopenharmony_ci        goto cleanup;
10127db96d56Sopenharmony_ci#endif /* HAVE_SETREUID */
10137db96d56Sopenharmony_ci    }
10147db96d56Sopenharmony_ci
10157db96d56Sopenharmony_ci    if (uid_object != Py_None) {
10167db96d56Sopenharmony_ci#ifdef HAVE_SETREUID
10177db96d56Sopenharmony_ci        if (!_Py_Uid_Converter(uid_object, &uid))
10187db96d56Sopenharmony_ci            goto cleanup;
10197db96d56Sopenharmony_ci
10207db96d56Sopenharmony_ci        call_setuid = 1;
10217db96d56Sopenharmony_ci
10227db96d56Sopenharmony_ci#else /* HAVE_SETREUID */
10237db96d56Sopenharmony_ci        PyErr_BadInternalCall();
10247db96d56Sopenharmony_ci        goto cleanup;
10257db96d56Sopenharmony_ci#endif /* HAVE_SETREUID */
10267db96d56Sopenharmony_ci    }
10277db96d56Sopenharmony_ci
10287db96d56Sopenharmony_ci    Py_ssize_t fds_to_keep_len = PyTuple_GET_SIZE(py_fds_to_keep);
10297db96d56Sopenharmony_ci    c_fds_to_keep = PyMem_Malloc(fds_to_keep_len * sizeof(int));
10307db96d56Sopenharmony_ci    if (c_fds_to_keep == NULL) {
10317db96d56Sopenharmony_ci        PyErr_SetString(PyExc_MemoryError, "failed to malloc c_fds_to_keep");
10327db96d56Sopenharmony_ci        goto cleanup;
10337db96d56Sopenharmony_ci    }
10347db96d56Sopenharmony_ci    if (convert_fds_to_keep_to_c(py_fds_to_keep, c_fds_to_keep) < 0) {
10357db96d56Sopenharmony_ci        goto cleanup;
10367db96d56Sopenharmony_ci    }
10377db96d56Sopenharmony_ci
10387db96d56Sopenharmony_ci    /* This must be the last thing done before fork() because we do not
10397db96d56Sopenharmony_ci     * want to call PyOS_BeforeFork() if there is any chance of another
10407db96d56Sopenharmony_ci     * error leading to the cleanup: code without calling fork(). */
10417db96d56Sopenharmony_ci    if (preexec_fn != Py_None) {
10427db96d56Sopenharmony_ci        preexec_fn_args_tuple = PyTuple_New(0);
10437db96d56Sopenharmony_ci        if (!preexec_fn_args_tuple)
10447db96d56Sopenharmony_ci            goto cleanup;
10457db96d56Sopenharmony_ci        PyOS_BeforeFork();
10467db96d56Sopenharmony_ci        need_after_fork = 1;
10477db96d56Sopenharmony_ci    }
10487db96d56Sopenharmony_ci
10497db96d56Sopenharmony_ci    /* NOTE: When old_sigmask is non-NULL, do_fork_exec() may use vfork(). */
10507db96d56Sopenharmony_ci    const void *old_sigmask = NULL;
10517db96d56Sopenharmony_ci#ifdef VFORK_USABLE
10527db96d56Sopenharmony_ci    /* Use vfork() only if it's safe. See the comment above child_exec(). */
10537db96d56Sopenharmony_ci    sigset_t old_sigs;
10547db96d56Sopenharmony_ci    if (preexec_fn == Py_None && allow_vfork &&
10557db96d56Sopenharmony_ci        !call_setuid && !call_setgid && !call_setgroups) {
10567db96d56Sopenharmony_ci        /* Block all signals to ensure that no signal handlers are run in the
10577db96d56Sopenharmony_ci         * child process while it shares memory with us. Note that signals
10587db96d56Sopenharmony_ci         * used internally by C libraries won't be blocked by
10597db96d56Sopenharmony_ci         * pthread_sigmask(), but signal handlers installed by C libraries
10607db96d56Sopenharmony_ci         * normally service only signals originating from *within the process*,
10617db96d56Sopenharmony_ci         * so it should be sufficient to consider any library function that
10627db96d56Sopenharmony_ci         * might send such a signal to be vfork-unsafe and do not call it in
10637db96d56Sopenharmony_ci         * the child.
10647db96d56Sopenharmony_ci         */
10657db96d56Sopenharmony_ci        sigset_t all_sigs;
10667db96d56Sopenharmony_ci        sigfillset(&all_sigs);
10677db96d56Sopenharmony_ci        if ((saved_errno = pthread_sigmask(SIG_BLOCK, &all_sigs, &old_sigs))) {
10687db96d56Sopenharmony_ci            goto cleanup;
10697db96d56Sopenharmony_ci        }
10707db96d56Sopenharmony_ci        old_sigmask = &old_sigs;
10717db96d56Sopenharmony_ci    }
10727db96d56Sopenharmony_ci#endif
10737db96d56Sopenharmony_ci
10747db96d56Sopenharmony_ci    pid = do_fork_exec(exec_array, argv, envp, cwd,
10757db96d56Sopenharmony_ci                       p2cread, p2cwrite, c2pread, c2pwrite,
10767db96d56Sopenharmony_ci                       errread, errwrite, errpipe_read, errpipe_write,
10777db96d56Sopenharmony_ci                       close_fds, restore_signals, call_setsid, pgid_to_set,
10787db96d56Sopenharmony_ci                       call_setgid, gid, call_setgroups, num_groups, groups,
10797db96d56Sopenharmony_ci                       call_setuid, uid, child_umask, old_sigmask,
10807db96d56Sopenharmony_ci                       c_fds_to_keep, fds_to_keep_len,
10817db96d56Sopenharmony_ci                       preexec_fn, preexec_fn_args_tuple);
10827db96d56Sopenharmony_ci
10837db96d56Sopenharmony_ci    /* Parent (original) process */
10847db96d56Sopenharmony_ci    if (pid == -1) {
10857db96d56Sopenharmony_ci        /* Capture errno for the exception. */
10867db96d56Sopenharmony_ci        saved_errno = errno;
10877db96d56Sopenharmony_ci    }
10887db96d56Sopenharmony_ci
10897db96d56Sopenharmony_ci#ifdef VFORK_USABLE
10907db96d56Sopenharmony_ci    if (old_sigmask) {
10917db96d56Sopenharmony_ci        /* vfork() semantics guarantees that the parent is blocked
10927db96d56Sopenharmony_ci         * until the child performs _exit() or execve(), so it is safe
10937db96d56Sopenharmony_ci         * to unblock signals once we're here.
10947db96d56Sopenharmony_ci         * Note that in environments where vfork() is implemented as fork(),
10957db96d56Sopenharmony_ci         * such as QEMU user-mode emulation, the parent won't be blocked,
10967db96d56Sopenharmony_ci         * but it won't share the address space with the child,
10977db96d56Sopenharmony_ci         * so it's still safe to unblock the signals.
10987db96d56Sopenharmony_ci         *
10997db96d56Sopenharmony_ci         * We don't handle errors here because this call can't fail
11007db96d56Sopenharmony_ci         * if valid arguments are given, and because there is no good
11017db96d56Sopenharmony_ci         * way for the caller to deal with a failure to restore
11027db96d56Sopenharmony_ci         * the thread signal mask. */
11037db96d56Sopenharmony_ci        (void) pthread_sigmask(SIG_SETMASK, old_sigmask, NULL);
11047db96d56Sopenharmony_ci    }
11057db96d56Sopenharmony_ci#endif
11067db96d56Sopenharmony_ci
11077db96d56Sopenharmony_ci    if (need_after_fork)
11087db96d56Sopenharmony_ci        PyOS_AfterFork_Parent();
11097db96d56Sopenharmony_ci
11107db96d56Sopenharmony_cicleanup:
11117db96d56Sopenharmony_ci    if (c_fds_to_keep != NULL) {
11127db96d56Sopenharmony_ci        PyMem_Free(c_fds_to_keep);
11137db96d56Sopenharmony_ci    }
11147db96d56Sopenharmony_ci
11157db96d56Sopenharmony_ci    if (saved_errno != 0) {
11167db96d56Sopenharmony_ci        errno = saved_errno;
11177db96d56Sopenharmony_ci        /* We can't call this above as PyOS_AfterFork_Parent() calls back
11187db96d56Sopenharmony_ci         * into Python code which would see the unreturned error. */
11197db96d56Sopenharmony_ci        PyErr_SetFromErrno(PyExc_OSError);
11207db96d56Sopenharmony_ci    }
11217db96d56Sopenharmony_ci
11227db96d56Sopenharmony_ci    Py_XDECREF(preexec_fn_args_tuple);
11237db96d56Sopenharmony_ci    PyMem_RawFree(groups);
11247db96d56Sopenharmony_ci    Py_XDECREF(cwd_obj2);
11257db96d56Sopenharmony_ci    if (envp)
11267db96d56Sopenharmony_ci        _Py_FreeCharPArray(envp);
11277db96d56Sopenharmony_ci    Py_XDECREF(converted_args);
11287db96d56Sopenharmony_ci    Py_XDECREF(fast_args);
11297db96d56Sopenharmony_ci    if (argv)
11307db96d56Sopenharmony_ci        _Py_FreeCharPArray(argv);
11317db96d56Sopenharmony_ci    if (exec_array)
11327db96d56Sopenharmony_ci        _Py_FreeCharPArray(exec_array);
11337db96d56Sopenharmony_ci
11347db96d56Sopenharmony_ci    if (need_to_reenable_gc) {
11357db96d56Sopenharmony_ci        PyGC_Enable();
11367db96d56Sopenharmony_ci    }
11377db96d56Sopenharmony_ci    Py_XDECREF(gc_module);
11387db96d56Sopenharmony_ci
11397db96d56Sopenharmony_ci    return pid == -1 ? NULL : PyLong_FromPid(pid);
11407db96d56Sopenharmony_ci}
11417db96d56Sopenharmony_ci
11427db96d56Sopenharmony_ci
11437db96d56Sopenharmony_ciPyDoc_STRVAR(subprocess_fork_exec_doc,
11447db96d56Sopenharmony_ci"fork_exec(args, executable_list, close_fds, pass_fds, cwd, env,\n\
11457db96d56Sopenharmony_ci          p2cread, p2cwrite, c2pread, c2pwrite,\n\
11467db96d56Sopenharmony_ci          errread, errwrite, errpipe_read, errpipe_write,\n\
11477db96d56Sopenharmony_ci          restore_signals, call_setsid, pgid_to_set,\n\
11487db96d56Sopenharmony_ci          gid, groups_list, uid,\n\
11497db96d56Sopenharmony_ci          preexec_fn)\n\
11507db96d56Sopenharmony_ci\n\
11517db96d56Sopenharmony_ciForks a child process, closes parent file descriptors as appropriate in the\n\
11527db96d56Sopenharmony_cichild and dups the few that are needed before calling exec() in the child\n\
11537db96d56Sopenharmony_ciprocess.\n\
11547db96d56Sopenharmony_ci\n\
11557db96d56Sopenharmony_ciIf close_fds is true, close file descriptors 3 and higher, except those listed\n\
11567db96d56Sopenharmony_ciin the sorted tuple pass_fds.\n\
11577db96d56Sopenharmony_ci\n\
11587db96d56Sopenharmony_ciThe preexec_fn, if supplied, will be called immediately before closing file\n\
11597db96d56Sopenharmony_cidescriptors and exec.\n\
11607db96d56Sopenharmony_ciWARNING: preexec_fn is NOT SAFE if your application uses threads.\n\
11617db96d56Sopenharmony_ci         It may trigger infrequent, difficult to debug deadlocks.\n\
11627db96d56Sopenharmony_ci\n\
11637db96d56Sopenharmony_ciIf an error occurs in the child process before the exec, it is\n\
11647db96d56Sopenharmony_ciserialized and written to the errpipe_write fd per subprocess.py.\n\
11657db96d56Sopenharmony_ci\n\
11667db96d56Sopenharmony_ciReturns: the child process's PID.\n\
11677db96d56Sopenharmony_ci\n\
11687db96d56Sopenharmony_ciRaises: Only on an error in the parent process.\n\
11697db96d56Sopenharmony_ci");
11707db96d56Sopenharmony_ci
11717db96d56Sopenharmony_ci/* module level code ********************************************************/
11727db96d56Sopenharmony_ci
11737db96d56Sopenharmony_ciPyDoc_STRVAR(module_doc,
11747db96d56Sopenharmony_ci"A POSIX helper for the subprocess module.");
11757db96d56Sopenharmony_ci
11767db96d56Sopenharmony_cistatic PyMethodDef module_methods[] = {
11777db96d56Sopenharmony_ci    {"fork_exec", subprocess_fork_exec, METH_VARARGS, subprocess_fork_exec_doc},
11787db96d56Sopenharmony_ci    {NULL, NULL}  /* sentinel */
11797db96d56Sopenharmony_ci};
11807db96d56Sopenharmony_ci
11817db96d56Sopenharmony_cistatic PyModuleDef_Slot _posixsubprocess_slots[] = {
11827db96d56Sopenharmony_ci    {0, NULL}
11837db96d56Sopenharmony_ci};
11847db96d56Sopenharmony_ci
11857db96d56Sopenharmony_cistatic struct PyModuleDef _posixsubprocessmodule = {
11867db96d56Sopenharmony_ci        PyModuleDef_HEAD_INIT,
11877db96d56Sopenharmony_ci        .m_name = "_posixsubprocess",
11887db96d56Sopenharmony_ci        .m_doc = module_doc,
11897db96d56Sopenharmony_ci        .m_size = 0,
11907db96d56Sopenharmony_ci        .m_methods = module_methods,
11917db96d56Sopenharmony_ci        .m_slots = _posixsubprocess_slots,
11927db96d56Sopenharmony_ci};
11937db96d56Sopenharmony_ci
11947db96d56Sopenharmony_ciPyMODINIT_FUNC
11957db96d56Sopenharmony_ciPyInit__posixsubprocess(void)
11967db96d56Sopenharmony_ci{
11977db96d56Sopenharmony_ci    return PyModuleDef_Init(&_posixsubprocessmodule);
11987db96d56Sopenharmony_ci}
1199