sync patches
This commit is contained in:
parent
7b6e5d6ec2
commit
9a0e0c1eb3
@ -0,0 +1,51 @@
|
||||
From be3c3a0e468237430ad7d19a33c60d306199a7f2 Mon Sep 17 00:00:00 2001
|
||||
From: "Gregory P. Smith" <greg@krypto.org>
|
||||
Date: Sat, 24 Oct 2020 12:07:35 -0700
|
||||
Subject: [PATCH] bpo-35823: Allow setsid() after vfork() on Linux. (GH-22945)
|
||||
|
||||
It should just be a syscall updating a couple of fields in the kernel side
|
||||
process info. Confirming, in glibc is appears to be a shim for the setsid
|
||||
syscall (based on not finding any code implementing anything special for it)
|
||||
and in uclibc (*much* easier to read) it is clearly just a setsid syscall shim.
|
||||
|
||||
A breadcrumb _suggesting_ that it is not allowed on Darwin/macOS comes from
|
||||
a commit in emacs: https://lists.gnu.org/archive/html/bug-gnu-emacs/2017-04/msg00297.html
|
||||
but I don't have a way to verify if that is true or not.
|
||||
As we are not supporting vfork on macOS today I just left a note in a comment.
|
||||
---
|
||||
Modules/_posixsubprocess.c | 5 +++--
|
||||
1 file changed, 3 insertions(+), 2 deletions(-)
|
||||
|
||||
diff --git a/Modules/_posixsubprocess.c b/Modules/_posixsubprocess.c
|
||||
index b7cba30..8baea31 100644
|
||||
--- a/Modules/_posixsubprocess.c
|
||||
+++ b/Modules/_posixsubprocess.c
|
||||
@@ -38,6 +38,8 @@
|
||||
|
||||
#if defined(__linux__) && defined(HAVE_VFORK) && defined(HAVE_SIGNAL_H) && \
|
||||
defined(HAVE_PTHREAD_SIGMASK) && !defined(HAVE_BROKEN_PTHREAD_SIGMASK)
|
||||
+/* If this is ever expanded to non-Linux platforms, verify what calls are
|
||||
+ * allowed after vfork(). Ex: setsid() may be disallowed on macOS? */
|
||||
# include <signal.h>
|
||||
# define VFORK_USABLE 1
|
||||
#endif
|
||||
@@ -712,7 +714,6 @@ struct linux_dirent64 {
|
||||
#ifdef VFORK_USABLE
|
||||
if (child_sigmask) {
|
||||
/* These are checked by our caller; verify them in debug builds. */
|
||||
- assert(!call_setsid);
|
||||
assert(!call_setuid);
|
||||
assert(!call_setgid);
|
||||
assert(!call_setgroups);
|
||||
@@ -997,7 +998,7 @@ struct linux_dirent64 {
|
||||
/* Use vfork() only if it's safe. See the comment above child_exec(). */
|
||||
sigset_t old_sigs;
|
||||
if (preexec_fn == Py_None &&
|
||||
- !call_setuid && !call_setgid && !call_setgroups && !call_setsid) {
|
||||
+ !call_setuid && !call_setgid && !call_setgroups) {
|
||||
/* Block all signals to ensure that no signal handlers are run in the
|
||||
* child process while it shares memory with us. Note that signals
|
||||
* used internally by C libraries won't be blocked by
|
||||
--
|
||||
1.8.3.1
|
||||
|
||||
@ -0,0 +1,63 @@
|
||||
From 473db47747bb8bc986d88ad81799bcbd88153ac5 Mon Sep 17 00:00:00 2001
|
||||
From: Alexey Izbyshev <izbyshev@ispras.ru>
|
||||
Date: Sat, 24 Oct 2020 20:47:38 +0300
|
||||
Subject: [PATCH] bpo-35823: subprocess: Fix handling of pthread_sigmask()
|
||||
errors (GH-22944)
|
||||
|
||||
Using POSIX_CALL() is incorrect since pthread_sigmask() returns
|
||||
the error number instead of setting errno.
|
||||
|
||||
Also handle failure of the first call to pthread_sigmask()
|
||||
in the parent process, and explain why we don't handle failure
|
||||
of the second call in a comment.
|
||||
---
|
||||
Modules/_posixsubprocess.c | 19 +++++++++++++++----
|
||||
1 file changed, 15 insertions(+), 4 deletions(-)
|
||||
|
||||
diff --git a/Modules/_posixsubprocess.c b/Modules/_posixsubprocess.c
|
||||
index ed49857..b7cba30 100644
|
||||
--- a/Modules/_posixsubprocess.c
|
||||
+++ b/Modules/_posixsubprocess.c
|
||||
@@ -581,7 +581,9 @@ struct linux_dirent64 {
|
||||
#ifdef VFORK_USABLE
|
||||
if (child_sigmask) {
|
||||
reset_signal_handlers(child_sigmask);
|
||||
- POSIX_CALL(pthread_sigmask(SIG_SETMASK, child_sigmask, NULL));
|
||||
+ if ((errno = pthread_sigmask(SIG_SETMASK, child_sigmask, NULL))) {
|
||||
+ goto error;
|
||||
+ }
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -1007,7 +1009,11 @@ struct linux_dirent64 {
|
||||
*/
|
||||
sigset_t all_sigs;
|
||||
sigfillset(&all_sigs);
|
||||
- pthread_sigmask(SIG_BLOCK, &all_sigs, &old_sigs);
|
||||
+ if ((saved_errno = pthread_sigmask(SIG_BLOCK, &all_sigs, &old_sigs))) {
|
||||
+ errno = saved_errno;
|
||||
+ PyErr_SetFromErrno(PyExc_OSError);
|
||||
+ goto cleanup;
|
||||
+ }
|
||||
old_sigmask = &old_sigs;
|
||||
}
|
||||
#endif
|
||||
@@ -1034,8 +1040,13 @@ struct linux_dirent64 {
|
||||
* Note that in environments where vfork() is implemented as fork(),
|
||||
* such as QEMU user-mode emulation, the parent won't be blocked,
|
||||
* but it won't share the address space with the child,
|
||||
- * so it's still safe to unblock the signals. */
|
||||
- pthread_sigmask(SIG_SETMASK, old_sigmask, NULL);
|
||||
+ * so it's still safe to unblock the signals.
|
||||
+ *
|
||||
+ * We don't handle errors here because this call can't fail
|
||||
+ * if valid arguments are given, and because there is no good
|
||||
+ * way for the caller to deal with a failure to restore
|
||||
+ * the thread signal mask. */
|
||||
+ (void) pthread_sigmask(SIG_SETMASK, old_sigmask, NULL);
|
||||
}
|
||||
#endif
|
||||
|
||||
--
|
||||
1.8.3.1
|
||||
|
||||
@ -0,0 +1,417 @@
|
||||
From 976da903a746a5455998e9ca45fbc4d3ad3479d8 Mon Sep 17 00:00:00 2001
|
||||
From: Alexey Izbyshev <izbyshev@ispras.ru>
|
||||
Date: Sat, 24 Oct 2020 03:47:01 +0300
|
||||
Subject: [PATCH] bpo-35823: subprocess: Use vfork() instead of fork() on Linux
|
||||
when safe (GH-11671)
|
||||
|
||||
* bpo-35823: subprocess: Use vfork() instead of fork() on Linux when safe
|
||||
|
||||
When used to run a new executable image, fork() is not a good choice
|
||||
for process creation, especially if the parent has a large working set:
|
||||
fork() needs to copy page tables, which is slow, and may fail on systems
|
||||
where overcommit is disabled, despite that the child is not going to
|
||||
touch most of its address space.
|
||||
|
||||
Currently, subprocess is capable of using posix_spawn() instead, which
|
||||
normally provides much better performance. However, posix_spawn() does not
|
||||
support many of child setup operations exposed by subprocess.Popen().
|
||||
Most notably, it's not possible to express `close_fds=True`, which
|
||||
happens to be the default, via posix_spawn(). As a result, most users
|
||||
can't benefit from faster process creation, at least not without
|
||||
changing their code.
|
||||
|
||||
However, Linux provides vfork() system call, which creates a new process
|
||||
without copying the address space of the parent, and which is actually
|
||||
used by C libraries to efficiently implement posix_spawn(). Due to sharing
|
||||
of the address space and even the stack with the parent, extreme care
|
||||
is required to use vfork(). At least the following restrictions must hold:
|
||||
|
||||
* No signal handlers must execute in the child process. Otherwise, they
|
||||
might clobber memory shared with the parent, potentially confusing it.
|
||||
|
||||
* Any library function called after vfork() in the child must be
|
||||
async-signal-safe (as for fork()), but it must also not interact with any
|
||||
library state in a way that might break due to address space sharing
|
||||
and/or lack of any preparations performed by libraries on normal fork().
|
||||
POSIX.1 permits to call only execve() and _exit(), and later revisions
|
||||
remove vfork() specification entirely. In practice, however, almost all
|
||||
operations needed by subprocess.Popen() can be safely implemented on
|
||||
Linux.
|
||||
|
||||
* Due to sharing of the stack with the parent, the child must be careful
|
||||
not to clobber local variables that are alive across vfork() call.
|
||||
Compilers are normally aware of this and take extra care with vfork()
|
||||
(and setjmp(), which has a similar problem).
|
||||
|
||||
* In case the parent is privileged, special attention must be paid to vfork()
|
||||
use, because sharing an address space across different privilege domains
|
||||
is insecure[1].
|
||||
|
||||
This patch adds support for using vfork() instead of fork() on Linux
|
||||
when it's possible to do safely given the above. In particular:
|
||||
|
||||
* vfork() is not used if credential switch is requested. The reverse case
|
||||
(simple subprocess.Popen() but another application thread switches
|
||||
credentials concurrently) is not possible for pure-Python apps because
|
||||
subprocess.Popen() and functions like os.setuid() are mutually excluded
|
||||
via GIL. We might also consider to add a way to opt-out of vfork() (and
|
||||
posix_spawn() on platforms where it might be implemented via vfork()) in
|
||||
a future PR.
|
||||
|
||||
* vfork() is not used if `preexec_fn != None`.
|
||||
|
||||
With this change, subprocess will still use posix_spawn() if possible, but
|
||||
will fallback to vfork() on Linux in most cases, and, failing that,
|
||||
to fork().
|
||||
|
||||
[1] https://ewontfix.com/7
|
||||
|
||||
Co-authored-by: Gregory P. Smith [Google LLC] <gps@google.com>
|
||||
---
|
||||
.../2020-10-16-07-45-35.bpo-35823.SNQo56.rst | 2 +
|
||||
Modules/_posixsubprocess.c | 224 ++++++++++++++++++---
|
||||
configure | 2 +-
|
||||
configure.ac | 2 +-
|
||||
pyconfig.h.in | 3 +
|
||||
5 files changed, 204 insertions(+), 29 deletions(-)
|
||||
create mode 100644 Misc/NEWS.d/next/Library/2020-10-16-07-45-35.bpo-35823.SNQo56.rst
|
||||
|
||||
diff --git a/Misc/NEWS.d/next/Library/2020-10-16-07-45-35.bpo-35823.SNQo56.rst b/Misc/NEWS.d/next/Library/2020-10-16-07-45-35.bpo-35823.SNQo56.rst
|
||||
new file mode 100644
|
||||
index 0000000..cd428d3
|
||||
--- /dev/null
|
||||
+++ b/Misc/NEWS.d/next/Library/2020-10-16-07-45-35.bpo-35823.SNQo56.rst
|
||||
@@ -0,0 +1,2 @@
|
||||
+Use ``vfork()`` instead of ``fork()`` for :func:`subprocess.Popen` on Linux
|
||||
+to improve performance in cases where it is deemed safe.
|
||||
diff --git a/Modules/_posixsubprocess.c b/Modules/_posixsubprocess.c
|
||||
index d08c479..ed49857 100644
|
||||
--- a/Modules/_posixsubprocess.c
|
||||
+++ b/Modules/_posixsubprocess.c
|
||||
@@ -36,6 +36,12 @@
|
||||
# define SYS_getdents64 __NR_getdents64
|
||||
#endif
|
||||
|
||||
+#if defined(__linux__) && defined(HAVE_VFORK) && defined(HAVE_SIGNAL_H) && \
|
||||
+ defined(HAVE_PTHREAD_SIGMASK) && !defined(HAVE_BROKEN_PTHREAD_SIGMASK)
|
||||
+# include <signal.h>
|
||||
+# define VFORK_USABLE 1
|
||||
+#endif
|
||||
+
|
||||
#if defined(__sun) && defined(__SVR4)
|
||||
/* readdir64 is used to work around Solaris 9 bug 6395699. */
|
||||
# define readdir readdir64
|
||||
@@ -407,9 +413,53 @@ struct linux_dirent64 {
|
||||
#endif /* else NOT (defined(__linux__) && defined(HAVE_SYS_SYSCALL_H)) */
|
||||
|
||||
|
||||
+#ifdef VFORK_USABLE
|
||||
+/* Reset dispositions for all signals to SIG_DFL except for ignored
|
||||
+ * signals. This way we ensure that no signal handlers can run
|
||||
+ * after we unblock signals in a child created by vfork().
|
||||
+ */
|
||||
+static void
|
||||
+reset_signal_handlers(const sigset_t *child_sigmask)
|
||||
+{
|
||||
+ struct sigaction sa_dfl = {.sa_handler = SIG_DFL};
|
||||
+ for (int sig = 1; sig < _NSIG; sig++) {
|
||||
+ /* Dispositions for SIGKILL and SIGSTOP can't be changed. */
|
||||
+ if (sig == SIGKILL || sig == SIGSTOP) {
|
||||
+ continue;
|
||||
+ }
|
||||
+
|
||||
+ /* There is no need to reset the disposition of signals that will
|
||||
+ * remain blocked across execve() since the kernel will do it. */
|
||||
+ if (sigismember(child_sigmask, sig) == 1) {
|
||||
+ continue;
|
||||
+ }
|
||||
+
|
||||
+ struct sigaction sa;
|
||||
+ /* C libraries usually return EINVAL for signals used
|
||||
+ * internally (e.g. for thread cancellation), so simply
|
||||
+ * skip errors here. */
|
||||
+ if (sigaction(sig, NULL, &sa) == -1) {
|
||||
+ continue;
|
||||
+ }
|
||||
+
|
||||
+ /* void *h works as these fields are both pointer types already. */
|
||||
+ void *h = (sa.sa_flags & SA_SIGINFO ? (void *)sa.sa_sigaction :
|
||||
+ (void *)sa.sa_handler);
|
||||
+ if (h == SIG_IGN || h == SIG_DFL) {
|
||||
+ continue;
|
||||
+ }
|
||||
+
|
||||
+ /* This call can't reasonably fail, but if it does, terminating
|
||||
+ * the child seems to be too harsh, so ignore errors. */
|
||||
+ (void) sigaction(sig, &sa_dfl, NULL);
|
||||
+ }
|
||||
+}
|
||||
+#endif /* VFORK_USABLE */
|
||||
+
|
||||
+
|
||||
/*
|
||||
- * This function is code executed in the child process immediately after fork
|
||||
- * to set things up and call exec().
|
||||
+ * This function is code executed in the child process immediately after
|
||||
+ * (v)fork to set things up and call exec().
|
||||
*
|
||||
* All of the code in this function must only use async-signal-safe functions,
|
||||
* listed at `man 7 signal` or
|
||||
@@ -417,8 +467,28 @@ struct linux_dirent64 {
|
||||
*
|
||||
* This restriction is documented at
|
||||
* http://www.opengroup.org/onlinepubs/009695399/functions/fork.html.
|
||||
+ *
|
||||
+ * If this function is called after vfork(), even more care must be taken.
|
||||
+ * The lack of preparations that C libraries normally take on fork(),
|
||||
+ * as well as sharing the address space with the parent, might make even
|
||||
+ * async-signal-safe functions vfork-unsafe. In particular, on Linux,
|
||||
+ * set*id() and setgroups() library functions must not be called, since
|
||||
+ * they have to interact with the library-level thread list and send
|
||||
+ * library-internal signals to implement per-process credentials semantics
|
||||
+ * required by POSIX but not supported natively on Linux. Another reason to
|
||||
+ * avoid this family of functions is that sharing an address space between
|
||||
+ * processes running with different privileges is inherently insecure.
|
||||
+ * See bpo-35823 for further discussion and references.
|
||||
+ *
|
||||
+ * In some C libraries, setrlimit() has the same thread list/signalling
|
||||
+ * behavior since resource limits were per-thread attributes before
|
||||
+ * Linux 2.6.10. Musl, as of 1.2.1, is known to have this issue
|
||||
+ * (https://www.openwall.com/lists/musl/2020/10/15/6).
|
||||
+ *
|
||||
+ * If vfork-unsafe functionality is desired after vfork(), consider using
|
||||
+ * syscall() to obtain it.
|
||||
*/
|
||||
-static void
|
||||
+_Py_NO_INLINE static void
|
||||
child_exec(char *const exec_array[],
|
||||
char *const argv[],
|
||||
char *const envp[],
|
||||
@@ -432,6 +502,7 @@ struct linux_dirent64 {
|
||||
int call_setgid, gid_t gid,
|
||||
int call_setgroups, size_t groups_size, const gid_t *groups,
|
||||
int call_setuid, uid_t uid, int child_umask,
|
||||
+ const void *child_sigmask,
|
||||
PyObject *py_fds_to_keep,
|
||||
PyObject *preexec_fn,
|
||||
PyObject *preexec_fn_args_tuple)
|
||||
@@ -507,6 +578,13 @@ struct linux_dirent64 {
|
||||
if (restore_signals)
|
||||
_Py_RestoreSignals();
|
||||
|
||||
+#ifdef VFORK_USABLE
|
||||
+ if (child_sigmask) {
|
||||
+ reset_signal_handlers(child_sigmask);
|
||||
+ POSIX_CALL(pthread_sigmask(SIG_SETMASK, child_sigmask, NULL));
|
||||
+ }
|
||||
+#endif
|
||||
+
|
||||
#ifdef HAVE_SETSID
|
||||
if (call_setsid)
|
||||
POSIX_CALL(setsid());
|
||||
@@ -599,6 +677,81 @@ struct linux_dirent64 {
|
||||
}
|
||||
|
||||
|
||||
+/* The main purpose of this wrapper function is to isolate vfork() from both
|
||||
+ * subprocess_fork_exec() and child_exec(). A child process created via
|
||||
+ * vfork() executes on the same stack as the parent process while the latter is
|
||||
+ * suspended, so this function should not be inlined to avoid compiler bugs
|
||||
+ * that might clobber data needed by the parent later. Additionally,
|
||||
+ * child_exec() should not be inlined to avoid spurious -Wclobber warnings from
|
||||
+ * GCC (see bpo-35823).
|
||||
+ */
|
||||
+_Py_NO_INLINE static pid_t
|
||||
+do_fork_exec(char *const exec_array[],
|
||||
+ char *const argv[],
|
||||
+ char *const envp[],
|
||||
+ const char *cwd,
|
||||
+ int p2cread, int p2cwrite,
|
||||
+ int c2pread, int c2pwrite,
|
||||
+ int errread, int errwrite,
|
||||
+ int errpipe_read, int errpipe_write,
|
||||
+ int close_fds, int restore_signals,
|
||||
+ int call_setsid,
|
||||
+ int call_setgid, gid_t gid,
|
||||
+ int call_setgroups, size_t groups_size, const gid_t *groups,
|
||||
+ int call_setuid, uid_t uid, int child_umask,
|
||||
+ const void *child_sigmask,
|
||||
+ PyObject *py_fds_to_keep,
|
||||
+ PyObject *preexec_fn,
|
||||
+ PyObject *preexec_fn_args_tuple)
|
||||
+{
|
||||
+
|
||||
+ pid_t pid;
|
||||
+
|
||||
+#ifdef VFORK_USABLE
|
||||
+ if (child_sigmask) {
|
||||
+ /* These are checked by our caller; verify them in debug builds. */
|
||||
+ assert(!call_setsid);
|
||||
+ assert(!call_setuid);
|
||||
+ assert(!call_setgid);
|
||||
+ assert(!call_setgroups);
|
||||
+ assert(preexec_fn == Py_None);
|
||||
+
|
||||
+ pid = vfork();
|
||||
+ } else
|
||||
+#endif
|
||||
+ {
|
||||
+ pid = fork();
|
||||
+ }
|
||||
+
|
||||
+ if (pid != 0) {
|
||||
+ return pid;
|
||||
+ }
|
||||
+
|
||||
+ /* Child process.
|
||||
+ * See the comment above child_exec() for restrictions imposed on
|
||||
+ * the code below.
|
||||
+ */
|
||||
+
|
||||
+ if (preexec_fn != Py_None) {
|
||||
+ /* We'll be calling back into Python later so we need to do this.
|
||||
+ * This call may not be async-signal-safe but neither is calling
|
||||
+ * back into Python. The user asked us to use hope as a strategy
|
||||
+ * to avoid deadlock... */
|
||||
+ PyOS_AfterFork_Child();
|
||||
+ }
|
||||
+
|
||||
+ child_exec(exec_array, argv, envp, cwd,
|
||||
+ p2cread, p2cwrite, c2pread, c2pwrite,
|
||||
+ errread, errwrite, errpipe_read, errpipe_write,
|
||||
+ close_fds, restore_signals, call_setsid,
|
||||
+ call_setgid, gid, call_setgroups, groups_size, groups,
|
||||
+ call_setuid, uid, child_umask, child_sigmask,
|
||||
+ py_fds_to_keep, preexec_fn, preexec_fn_args_tuple);
|
||||
+ _exit(255);
|
||||
+ return 0; /* Dead code to avoid a potential compiler warning. */
|
||||
+}
|
||||
+
|
||||
+
|
||||
static PyObject *
|
||||
subprocess_fork_exec(PyObject* self, PyObject *args)
|
||||
{
|
||||
@@ -836,39 +989,56 @@ struct linux_dirent64 {
|
||||
need_after_fork = 1;
|
||||
}
|
||||
|
||||
- pid = fork();
|
||||
- if (pid == 0) {
|
||||
- /* Child process */
|
||||
- /*
|
||||
- * Code from here to _exit() must only use async-signal-safe functions,
|
||||
- * listed at `man 7 signal` or
|
||||
- * http://www.opengroup.org/onlinepubs/009695399/functions/xsh_chap02_04.html.
|
||||
+ /* NOTE: When old_sigmask is non-NULL, do_fork_exec() may use vfork(). */
|
||||
+ const void *old_sigmask = NULL;
|
||||
+#ifdef VFORK_USABLE
|
||||
+ /* Use vfork() only if it's safe. See the comment above child_exec(). */
|
||||
+ sigset_t old_sigs;
|
||||
+ if (preexec_fn == Py_None &&
|
||||
+ !call_setuid && !call_setgid && !call_setgroups && !call_setsid) {
|
||||
+ /* Block all signals to ensure that no signal handlers are run in the
|
||||
+ * child process while it shares memory with us. Note that signals
|
||||
+ * used internally by C libraries won't be blocked by
|
||||
+ * pthread_sigmask(), but signal handlers installed by C libraries
|
||||
+ * normally service only signals originating from *within the process*,
|
||||
+ * so it should be sufficient to consider any library function that
|
||||
+ * might send such a signal to be vfork-unsafe and do not call it in
|
||||
+ * the child.
|
||||
*/
|
||||
+ sigset_t all_sigs;
|
||||
+ sigfillset(&all_sigs);
|
||||
+ pthread_sigmask(SIG_BLOCK, &all_sigs, &old_sigs);
|
||||
+ old_sigmask = &old_sigs;
|
||||
+ }
|
||||
+#endif
|
||||
|
||||
- if (preexec_fn != Py_None) {
|
||||
- /* We'll be calling back into Python later so we need to do this.
|
||||
- * This call may not be async-signal-safe but neither is calling
|
||||
- * back into Python. The user asked us to use hope as a strategy
|
||||
- * to avoid deadlock... */
|
||||
- PyOS_AfterFork_Child();
|
||||
- }
|
||||
+ pid = do_fork_exec(exec_array, argv, envp, cwd,
|
||||
+ p2cread, p2cwrite, c2pread, c2pwrite,
|
||||
+ errread, errwrite, errpipe_read, errpipe_write,
|
||||
+ close_fds, restore_signals, call_setsid,
|
||||
+ call_setgid, gid, call_setgroups, num_groups, groups,
|
||||
+ call_setuid, uid, child_umask, old_sigmask,
|
||||
+ py_fds_to_keep, preexec_fn, preexec_fn_args_tuple);
|
||||
|
||||
- child_exec(exec_array, argv, envp, cwd,
|
||||
- p2cread, p2cwrite, c2pread, c2pwrite,
|
||||
- errread, errwrite, errpipe_read, errpipe_write,
|
||||
- close_fds, restore_signals, call_setsid,
|
||||
- call_setgid, gid, call_setgroups, num_groups, groups,
|
||||
- call_setuid, uid, child_umask,
|
||||
- py_fds_to_keep, preexec_fn, preexec_fn_args_tuple);
|
||||
- _exit(255);
|
||||
- return NULL; /* Dead code to avoid a potential compiler warning. */
|
||||
- }
|
||||
/* Parent (original) process */
|
||||
if (pid == -1) {
|
||||
/* Capture errno for the exception. */
|
||||
saved_errno = errno;
|
||||
}
|
||||
|
||||
+#ifdef VFORK_USABLE
|
||||
+ if (old_sigmask) {
|
||||
+ /* vfork() semantics guarantees that the parent is blocked
|
||||
+ * until the child performs _exit() or execve(), so it is safe
|
||||
+ * to unblock signals once we're here.
|
||||
+ * Note that in environments where vfork() is implemented as fork(),
|
||||
+ * such as QEMU user-mode emulation, the parent won't be blocked,
|
||||
+ * but it won't share the address space with the child,
|
||||
+ * so it's still safe to unblock the signals. */
|
||||
+ pthread_sigmask(SIG_SETMASK, old_sigmask, NULL);
|
||||
+ }
|
||||
+#endif
|
||||
+
|
||||
Py_XDECREF(cwd_obj2);
|
||||
|
||||
if (need_after_fork)
|
||||
diff --git a/configure b/configure
|
||||
index 29f33b5..bc87485 100755
|
||||
--- a/configure
|
||||
+++ b/configure
|
||||
@@ -11732,7 +11732,7 @@ for ac_func in alarm accept4 setitimer getitimer bind_textdomain_codeset chown \
|
||||
sigaction sigaltstack sigfillset siginterrupt sigpending sigrelse \
|
||||
sigtimedwait sigwait sigwaitinfo snprintf strftime strlcpy strsignal symlinkat sync \
|
||||
sysconf tcgetpgrp tcsetpgrp tempnam timegm times tmpfile tmpnam tmpnam_r \
|
||||
- truncate uname unlinkat utimensat utimes waitid waitpid wait3 wait4 \
|
||||
+ truncate uname unlinkat utimensat utimes vfork waitid waitpid wait3 wait4 \
|
||||
wcscoll wcsftime wcsxfrm wmemcmp writev _getpty rtpSpawn
|
||||
do :
|
||||
as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh`
|
||||
diff --git a/configure.ac b/configure.ac
|
||||
index 9698c3c..49ed09a 100644
|
||||
--- a/configure.ac
|
||||
+++ b/configure.ac
|
||||
@@ -3690,7 +3690,7 @@ AC_CHECK_FUNCS(alarm accept4 setitimer getitimer bind_textdomain_codeset chown \
|
||||
sigaction sigaltstack sigfillset siginterrupt sigpending sigrelse \
|
||||
sigtimedwait sigwait sigwaitinfo snprintf strftime strlcpy strsignal symlinkat sync \
|
||||
sysconf tcgetpgrp tcsetpgrp tempnam timegm times tmpfile tmpnam tmpnam_r \
|
||||
- truncate uname unlinkat utimensat utimes waitid waitpid wait3 wait4 \
|
||||
+ truncate uname unlinkat utimensat utimes vfork waitid waitpid wait3 wait4 \
|
||||
wcscoll wcsftime wcsxfrm wmemcmp writev _getpty rtpSpawn)
|
||||
|
||||
# Force lchmod off for Linux. Linux disallows changing the mode of symbolic
|
||||
diff --git a/pyconfig.h.in b/pyconfig.h.in
|
||||
index 298cb4f..af8a3d6 100644
|
||||
--- a/pyconfig.h.in
|
||||
+++ b/pyconfig.h.in
|
||||
@@ -1301,6 +1301,9 @@
|
||||
/* Define to 1 if you have the <uuid/uuid.h> header file. */
|
||||
#undef HAVE_UUID_UUID_H
|
||||
|
||||
+/* Define to 1 if you have the `vfork' function. */
|
||||
+#undef HAVE_VFORK
|
||||
+
|
||||
/* Define to 1 if you have the `wait3' function. */
|
||||
#undef HAVE_WAIT3
|
||||
|
||||
--
|
||||
1.8.3.1
|
||||
|
||||
@ -0,0 +1,136 @@
|
||||
From d3b4e068077dd26927ae7485bd0303e09d962c02 Mon Sep 17 00:00:00 2001
|
||||
From: Alexey Izbyshev <izbyshev@ispras.ru>
|
||||
Date: Sun, 1 Nov 2020 08:33:08 +0300
|
||||
Subject: [PATCH] bpo-42146: Unify cleanup in subprocess_fork_exec() (GH-22970)
|
||||
|
||||
* bpo-42146: Unify cleanup in subprocess_fork_exec()
|
||||
|
||||
Also ignore errors from _enable_gc():
|
||||
* They are always suppressed by the current code due to a bug.
|
||||
* _enable_gc() is only used if `preexec_fn != None`, which is unsafe.
|
||||
* We don't have a good way to handle errors in case we successfully
|
||||
created a child process.
|
||||
|
||||
Co-authored-by: Gregory P. Smith <greg@krypto.org>
|
||||
---
|
||||
Modules/_posixsubprocess.c | 53 ++++++++++++++++------------------------------
|
||||
1 file changed, 18 insertions(+), 35 deletions(-)
|
||||
|
||||
diff --git a/Modules/_posixsubprocess.c b/Modules/_posixsubprocess.c
|
||||
index 5e5fbb2..a00e137 100644
|
||||
--- a/Modules/_posixsubprocess.c
|
||||
+++ b/Modules/_posixsubprocess.c
|
||||
@@ -87,8 +87,8 @@
|
||||
|
||||
#define _posixsubprocessstate_global get_posixsubprocess_state(PyState_FindModule(&_posixsubprocessmodule))
|
||||
|
||||
-/* If gc was disabled, call gc.enable(). Return 0 on success. */
|
||||
-static int
|
||||
+/* If gc was disabled, call gc.enable(). Ignore errors. */
|
||||
+static void
|
||||
_enable_gc(int need_to_reenable_gc, PyObject *gc_module)
|
||||
{
|
||||
PyObject *result;
|
||||
@@ -98,15 +98,17 @@
|
||||
PyErr_Fetch(&exctype, &val, &tb);
|
||||
result = PyObject_CallMethodNoArgs(
|
||||
gc_module, _posixsubprocessstate_global->enable);
|
||||
+ if (result == NULL) {
|
||||
+ /* We might have created a child process at this point, we
|
||||
+ * we have no good way to handle a failure to reenable GC
|
||||
+ * and return information about the child process. */
|
||||
+ PyErr_Print();
|
||||
+ }
|
||||
+ Py_XDECREF(result);
|
||||
if (exctype != NULL) {
|
||||
PyErr_Restore(exctype, val, tb);
|
||||
}
|
||||
- if (result == NULL) {
|
||||
- return 1;
|
||||
- }
|
||||
- Py_DECREF(result);
|
||||
}
|
||||
- return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -774,7 +776,7 @@ struct linux_dirent64 {
|
||||
int child_umask;
|
||||
PyObject *cwd_obj, *cwd_obj2 = NULL;
|
||||
const char *cwd;
|
||||
- pid_t pid;
|
||||
+ pid_t pid = -1;
|
||||
int need_to_reenable_gc = 0;
|
||||
char *const *exec_array, *const *argv = NULL, *const *envp = NULL;
|
||||
Py_ssize_t arg_num, num_groups = 0;
|
||||
@@ -1010,8 +1012,6 @@ struct linux_dirent64 {
|
||||
sigset_t all_sigs;
|
||||
sigfillset(&all_sigs);
|
||||
if ((saved_errno = pthread_sigmask(SIG_BLOCK, &all_sigs, &old_sigs))) {
|
||||
- errno = saved_errno;
|
||||
- PyErr_SetFromErrno(PyExc_OSError);
|
||||
goto cleanup;
|
||||
}
|
||||
old_sigmask = &old_sigs;
|
||||
@@ -1050,50 +1050,33 @@ struct linux_dirent64 {
|
||||
}
|
||||
#endif
|
||||
|
||||
- Py_XDECREF(cwd_obj2);
|
||||
-
|
||||
if (need_after_fork)
|
||||
PyOS_AfterFork_Parent();
|
||||
- if (envp)
|
||||
- _Py_FreeCharPArray(envp);
|
||||
- if (argv)
|
||||
- _Py_FreeCharPArray(argv);
|
||||
- _Py_FreeCharPArray(exec_array);
|
||||
-
|
||||
- /* Reenable gc in the parent process (or if fork failed). */
|
||||
- if (_enable_gc(need_to_reenable_gc, gc_module)) {
|
||||
- pid = -1;
|
||||
- }
|
||||
- PyMem_RawFree(groups);
|
||||
- Py_XDECREF(preexec_fn_args_tuple);
|
||||
- Py_XDECREF(gc_module);
|
||||
|
||||
- if (pid == -1) {
|
||||
+cleanup:
|
||||
+ if (saved_errno != 0) {
|
||||
errno = saved_errno;
|
||||
/* We can't call this above as PyOS_AfterFork_Parent() calls back
|
||||
* into Python code which would see the unreturned error. */
|
||||
PyErr_SetFromErrno(PyExc_OSError);
|
||||
- return NULL; /* fork() failed. */
|
||||
}
|
||||
|
||||
- return PyLong_FromPid(pid);
|
||||
-
|
||||
-cleanup:
|
||||
+ Py_XDECREF(preexec_fn_args_tuple);
|
||||
+ PyMem_RawFree(groups);
|
||||
Py_XDECREF(cwd_obj2);
|
||||
if (envp)
|
||||
_Py_FreeCharPArray(envp);
|
||||
+ Py_XDECREF(converted_args);
|
||||
+ Py_XDECREF(fast_args);
|
||||
if (argv)
|
||||
_Py_FreeCharPArray(argv);
|
||||
if (exec_array)
|
||||
_Py_FreeCharPArray(exec_array);
|
||||
|
||||
- PyMem_RawFree(groups);
|
||||
- Py_XDECREF(converted_args);
|
||||
- Py_XDECREF(fast_args);
|
||||
- Py_XDECREF(preexec_fn_args_tuple);
|
||||
_enable_gc(need_to_reenable_gc, gc_module);
|
||||
Py_XDECREF(gc_module);
|
||||
- return NULL;
|
||||
+
|
||||
+ return pid == -1 ? NULL : PyLong_FromPid(pid);
|
||||
}
|
||||
|
||||
|
||||
--
|
||||
1.8.3.1
|
||||
|
||||
16
python3.spec
16
python3.spec
@ -3,7 +3,7 @@ Summary: Interpreter of the Python3 programming language
|
||||
URL: https://www.python.org/
|
||||
|
||||
Version: 3.9.9
|
||||
Release: 14
|
||||
Release: 15
|
||||
License: Python-2.0
|
||||
|
||||
%global branchversion 3.9
|
||||
@ -94,6 +94,10 @@ Patch6002: backport-bpo-20369-concurrent.futures.wait-now-deduplicates-f.patch
|
||||
Patch6003: Make-mailcap-refuse-to-match-unsafe-filenam.patch
|
||||
Patch6004: backport-CVE-2021-28861.patch
|
||||
Patch6005: backport-CVE-2020-10735.patch
|
||||
Patch6006: backport-bpo-35823-subprocess-Use-vfork-instead-of-fork-on-Li.patch
|
||||
Patch6007: backport-bpo-35823-subprocess-Fix-handling-of-pthread_sigmask.patch
|
||||
Patch6008: backport-bpo-35823-Allow-setsid-after-vfork-on-Linux.-GH-2294.patch
|
||||
Patch6009: backport-bpo-42146-Unify-cleanup-in-subprocess_fork_exec-GH-2.patch
|
||||
|
||||
Patch9000: add-the-sm3-method-for-obtaining-the-salt-value.patch
|
||||
|
||||
@ -185,6 +189,10 @@ rm -r Modules/expat
|
||||
%patch6003 -p1
|
||||
%patch6004 -p1
|
||||
%patch6005 -p1
|
||||
%patch6006 -p1
|
||||
%patch6007 -p1
|
||||
%patch6008 -p1
|
||||
%patch6009 -p1
|
||||
|
||||
%patch9000 -p1
|
||||
|
||||
@ -801,6 +809,12 @@ export BEP_GTDLIST="$BEP_GTDLIST_TMP"
|
||||
%{_mandir}/*/*
|
||||
|
||||
%changelog
|
||||
* Thu Sep 22 zhuofeng <zhuofeng2@huawei.com> - 3.9.9-15
|
||||
- Type:bugfix
|
||||
- CVE:NA
|
||||
- SUG:NA
|
||||
- DESC:sync patches
|
||||
|
||||
* Thu Sep 08 shixuantong <shixuantong@h-partners.com> - 3.9.9-14
|
||||
- Type:CVE
|
||||
- CVE:CVE-2020-10735
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user