Andreas Schwab
4d4a3834ee
- ld-show-auxv-colon.patch: elf: Fix missing colon in LD_SHOW_AUXV output (BZ #282539 - x86-string-control-test.patch: x86-64: Use testl to check __x86_string_control - pthread-kill-fail-after-exit.patch: nptl: pthread_kill, pthread_cancel should not fail after exit (BZ #19193) - pthread-kill-race-thread-exit.patch: nptl: Fix race between pthread_kill and thread exit (BZ #12889) - getcwd-attribute-access.patch: posix: Fix attribute access mode on getcwd (BZ #27476) - pthread-kill-return-esrch.patch: nptl: pthread_kill needs to return ESRCH for old programs (BZ #19193) - pthread-mutexattr-getrobust-np-type.patch: nptl: Fix type of pthread_mutexattr_getrobust_np, pthread_mutexattr_setrobust_np (BZ #28036) - setxid-deadlock-blocked-signals.patch: nptl: Avoid setxid deadlock with blocked signals in thread exit (BZ #28361) - pthread-kill-send-specific-thread.patch: nptl: pthread_kill must send signals to a specific thread (BZ #28407) - sysconf-nprocessors-affinity.patch: linux: Revert the use of sched_getaffinity on get_nproc (BZ #28310) - iconv-charmap-close-output.patch: renamed from icon-charmap-close-output.patch OBS-URL: https://build.opensuse.org/request/show/923222 OBS-URL: https://build.opensuse.org/package/show/Base:System/glibc?expand=0&rev=604
136 lines
5.2 KiB
Diff
136 lines
5.2 KiB
Diff
From 33adeaa3e2b9143c38884bc5aa65ded222ed274e Mon Sep 17 00:00:00 2001
|
|
From: Florian Weimer <fweimer@redhat.com>
|
|
Date: Thu, 23 Sep 2021 09:55:54 +0200
|
|
Subject: [PATCH] nptl: Avoid setxid deadlock with blocked signals in thread
|
|
exit [BZ #28361]
|
|
|
|
As part of the fix for bug 12889, signals are blocked during
|
|
thread exit, so that application code cannot run on the thread that
|
|
is about to exit. This would cause problems if the application
|
|
expected signals to be delivered after the signal handler revealed
|
|
the thread to still exist, despite pthread_kill can no longer be used
|
|
to send signals to it. However, glibc internally uses the SIGSETXID
|
|
signal in a way that is incompatible with signal blocking, due to the
|
|
way the setxid handshake delays thread exit until the setxid operation
|
|
has completed. With a blocked SIGSETXID, the handshake can never
|
|
complete, causing a deadlock.
|
|
|
|
As a band-aid, restore the previous handshake protocol by not blocking
|
|
SIGSETXID during thread exit.
|
|
|
|
The new test sysdeps/pthread/tst-pthread-setuid-loop.c is based on
|
|
a downstream test by Martin Osvald.
|
|
|
|
Reviewed-by: Carlos O'Donell <carlos@redhat.com>
|
|
Tested-by: Carlos O'Donell <carlos@redhat.com>
|
|
(cherry picked from commit 2849e2f53311b66853cb5159b64cba2bddbfb854)
|
|
---
|
|
NEWS | 1 +
|
|
nptl/pthread_create.c | 12 ++++-
|
|
sysdeps/pthread/Makefile | 1 +
|
|
sysdeps/pthread/tst-pthread-setuid-loop.c | 61 +++++++++++++++++++++++
|
|
4 files changed, 73 insertions(+), 2 deletions(-)
|
|
create mode 100644 sysdeps/pthread/tst-pthread-setuid-loop.c
|
|
|
|
Index: glibc-2.34/nptl/pthread_create.c
|
|
===================================================================
|
|
--- glibc-2.34.orig/nptl/pthread_create.c
|
|
+++ glibc-2.34/nptl/pthread_create.c
|
|
@@ -488,8 +488,16 @@ start_thread (void *arg)
|
|
|
|
/* This prevents sending a signal from this thread to itself during
|
|
its final stages. This must come after the exit call above
|
|
- because atexit handlers must not run with signals blocked. */
|
|
- __libc_signal_block_all (NULL);
|
|
+ because atexit handlers must not run with signals blocked.
|
|
+
|
|
+ Do not block SIGSETXID. The setxid handshake below expects the
|
|
+ signal to be delivered. (SIGSETXID cannot run application code,
|
|
+ nor does it use pthread_kill.) Reuse the pd->sigmask space for
|
|
+ computing the signal mask, to save stack space. */
|
|
+ __sigfillset (&pd->sigmask);
|
|
+ __sigdelset (&pd->sigmask, SIGSETXID);
|
|
+ INTERNAL_SYSCALL_CALL (rt_sigprocmask, SIG_BLOCK, &pd->sigmask, NULL,
|
|
+ __NSIG_BYTES);
|
|
|
|
/* Tell __pthread_kill_internal that this thread is about to exit.
|
|
If there is a __pthread_kill_internal in progress, this delays
|
|
Index: glibc-2.34/sysdeps/pthread/Makefile
|
|
===================================================================
|
|
--- glibc-2.34.orig/sysdeps/pthread/Makefile
|
|
+++ glibc-2.34/sysdeps/pthread/Makefile
|
|
@@ -118,6 +118,7 @@ tests += tst-cnd-basic tst-mtx-trylock t
|
|
tst-unload \
|
|
tst-unwind-thread \
|
|
tst-pt-vfork1 tst-pt-vfork2 tst-vfork1x tst-vfork2x \
|
|
+ tst-pthread-setuid-loop \
|
|
tst-pthread_cancel-select-loop \
|
|
tst-pthread_kill-exiting \
|
|
|
|
Index: glibc-2.34/sysdeps/pthread/tst-pthread-setuid-loop.c
|
|
===================================================================
|
|
--- /dev/null
|
|
+++ glibc-2.34/sysdeps/pthread/tst-pthread-setuid-loop.c
|
|
@@ -0,0 +1,61 @@
|
|
+/* Test that setuid, pthread_create, thread exit do not deadlock (bug 28361).
|
|
+ Copyright (C) 2021 Free Software Foundation, Inc.
|
|
+ This file is part of the GNU C Library.
|
|
+
|
|
+ The GNU C Library is free software; you can redistribute it and/or
|
|
+ modify it under the terms of the GNU Lesser General Public
|
|
+ License as published by the Free Software Foundation; either
|
|
+ version 2.1 of the License, or (at your option) any later version.
|
|
+
|
|
+ The GNU C Library is distributed in the hope that it will be useful,
|
|
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
+ Lesser General Public License for more details.
|
|
+
|
|
+ You should have received a copy of the GNU Lesser General Public
|
|
+ License along with the GNU C Library; if not, see
|
|
+ <https://www.gnu.org/licenses/>. */
|
|
+
|
|
+#include <support/check.h>
|
|
+#include <support/xthread.h>
|
|
+#include <unistd.h>
|
|
+
|
|
+/* How many threads to launch during each iteration. */
|
|
+enum { threads = 4 };
|
|
+
|
|
+/* How many iterations to perform. This value seems to reproduce
|
|
+ bug 28361 in a bout one in three runs. */
|
|
+enum { iterations = 5000 };
|
|
+
|
|
+/* Cache of the real user ID used by setuid_thread. */
|
|
+static uid_t uid;
|
|
+
|
|
+/* Start routine for the threads. */
|
|
+static void *
|
|
+setuid_thread (void *closure)
|
|
+{
|
|
+ TEST_COMPARE (setuid (uid), 0);
|
|
+ return NULL;
|
|
+}
|
|
+
|
|
+static int
|
|
+do_test (void)
|
|
+{
|
|
+ /* The setxid machinery is still invoked even if the UID is
|
|
+ unchanged. (The kernel might reset other credentials as part of
|
|
+ the system call.) */
|
|
+ uid = getuid ();
|
|
+
|
|
+ for (int i = 0; i < iterations; ++i)
|
|
+ {
|
|
+ pthread_t thread_ids[threads];
|
|
+ for (int j = 0; j < threads; ++j)
|
|
+ thread_ids[j] = xpthread_create (NULL, setuid_thread, NULL);
|
|
+ for (int j = 0; j < threads; ++j)
|
|
+ xpthread_join (thread_ids[j]);
|
|
+ }
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+#include <support/test-driver.c>
|