From 83aeb85874abee17a312eab44d75484c097ed8a8 Mon Sep 17 00:00:00 2001 From: liqingqing_1229 Date: Mon, 8 Nov 2021 21:07:42 +0800 Subject: [PATCH] nptl: pthread_kill race condition issues fixed. uplink: https://sourceware.org/bugzilla/show_bug.cgi?id=19193 https://sourceware.org/bugzilla/show_bug.cgi?id=12889 https://sourceware.org/bugzilla/show_bug.cgi?id=28036 https://sourceware.org/bugzilla/show_bug.cgi?id=28363 https://sourceware.org/bugzilla/show_bug.cgi?id=28407 --- glibc.spec | 15 +- ...d-deadlock-with-blocked-signals-in-t.patch | 137 ++++++ ...tween-pthread_kill-and-thread-exit-b.patch | 424 ++++++++++++++++++ ...-pthread_mutexattr_getrobust_np-pthr.patch | 37 ++ ...l-must-send-signals-to-a-specific-th.patch | 162 +++++++ ...l-needs-to-return-ESRCH-for-old-prog.patch | 142 ++++++ 6 files changed, 916 insertions(+), 1 deletion(-) create mode 100644 nptl-Avoid-setxid-deadlock-with-blocked-signals-in-t.patch create mode 100644 nptl-Fix-race-between-pthread_kill-and-thread-exit-b.patch create mode 100644 nptl-Fix-type-of-pthread_mutexattr_getrobust_np-pthr.patch create mode 100644 nptl-pthread_kill-must-send-signals-to-a-specific-th.patch create mode 100644 nptl-pthread_kill-needs-to-return-ESRCH-for-old-prog.patch diff --git a/glibc.spec b/glibc.spec index 9361a89..9cc5fc3 100644 --- a/glibc.spec +++ b/glibc.spec @@ -65,7 +65,7 @@ ############################################################################## Name: glibc Version: 2.34 -Release: 20 +Release: 21 Summary: The GNU libc libraries License: %{all_license} URL: http://www.gnu.org/software/glibc/ @@ -121,6 +121,11 @@ Patch34: x86-64-Use-testl-to-check-__x86_string_control.patch Patch35: AArch64-Update-A64FX-memset-not-to-degrade-at-16KB.patch Patch36: support-Add-support_wait_for_thread_exit.patch Patch37: nptl-pthread_kill-pthread_cancel-should-not-fail-aft.patch +Patch38: nptl-Fix-race-between-pthread_kill-and-thread-exit-b.patch +Patch39: nptl-pthread_kill-needs-to-return-ESRCH-for-old-prog.patch +Patch40: nptl-Fix-type-of-pthread_mutexattr_getrobust_np-pthr.patch +Patch41: nptl-Avoid-setxid-deadlock-with-blocked-signals-in-t.patch +Patch42: nptl-pthread_kill-must-send-signals-to-a-specific-th.patch #Patch9000: turn-REP_STOSB_THRESHOLD-from-2k-to-1M.patch Patch9001: delete-no-hard-link-to-avoid-all_language-package-to.patch @@ -1310,6 +1315,14 @@ fi %endif %changelog +* Mon Nov 8 2021 Qingqing Li - 2.34-21 +- nptl: pthread_kill race condition issues fixed. + uplink: https://sourceware.org/bugzilla/show_bug.cgi?id=19193 + https://sourceware.org/bugzilla/show_bug.cgi?id=12889 + https://sourceware.org/bugzilla/show_bug.cgi?id=28036 + https://sourceware.org/bugzilla/show_bug.cgi?id=28363 + https://sourceware.org/bugzilla/show_bug.cgi?id=28407 + * Thu Nov 4 2021 Qingqing Li - 2.34-20 - nptl: pthread_kill and pthread_cancel return success for satisfy posix standard. diff --git a/nptl-Avoid-setxid-deadlock-with-blocked-signals-in-t.patch b/nptl-Avoid-setxid-deadlock-with-blocked-signals-in-t.patch new file mode 100644 index 0000000..e582b70 --- /dev/null +++ b/nptl-Avoid-setxid-deadlock-with-blocked-signals-in-t.patch @@ -0,0 +1,137 @@ +From 2849e2f53311b66853cb5159b64cba2bddbfb854 Mon Sep 17 00:00:00 2001 +From: Florian Weimer +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 +Tested-by: Carlos O'Donell +--- + nptl/pthread_create.c | 12 +++++- + sysdeps/pthread/Makefile | 1 + + sysdeps/pthread/tst-pthread-setuid-loop.c | 61 +++++++++++++++++++++++++++++++ + 3 files changed, 72 insertions(+), 2 deletions(-) + create mode 100644 sysdeps/pthread/tst-pthread-setuid-loop.c + +diff --git a/nptl/pthread_create.c b/nptl/pthread_create.c +index a559f86..d6ea43a 100644 +--- a/nptl/pthread_create.c ++++ b/nptl/pthread_create.c +@@ -487,8 +487,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 +diff --git a/sysdeps/pthread/Makefile b/sysdeps/pthread/Makefile +index 48dba71..d4bd2d4 100644 +--- a/sysdeps/pthread/Makefile ++++ b/sysdeps/pthread/Makefile +@@ -118,6 +118,7 @@ tests += tst-cnd-basic tst-mtx-trylock tst-cnd-broadcast \ + tst-unload \ + tst-unwind-thread \ + tst-pt-vfork1 tst-pt-vfork2 tst-vfork1x tst-vfork2x \ ++ tst-pthread-setuid-loop \ + tst-pthread_cancel-exited \ + tst-pthread_cancel-select-loop \ + tst-pthread_kill-exited \ +diff --git a/sysdeps/pthread/tst-pthread-setuid-loop.c b/sysdeps/pthread/tst-pthread-setuid-loop.c +new file mode 100644 +index 0000000..fda2a49 +--- /dev/null ++++ b/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 ++ . */ ++ ++#include ++#include ++#include ++ ++/* 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 +-- +1.8.3.1 + diff --git a/nptl-Fix-race-between-pthread_kill-and-thread-exit-b.patch b/nptl-Fix-race-between-pthread_kill-and-thread-exit-b.patch new file mode 100644 index 0000000..3acbe23 --- /dev/null +++ b/nptl-Fix-race-between-pthread_kill-and-thread-exit-b.patch @@ -0,0 +1,424 @@ +From 526c3cf11ee9367344b6b15d669e4c3cb461a2be Mon Sep 17 00:00:00 2001 +From: Florian Weimer +Date: Mon, 13 Sep 2021 11:06:08 +0200 +Subject: [PATCH] nptl: Fix race between pthread_kill and thread exit (bug + 12889) + +A new thread exit lock and flag are introduced. They are used to +detect that the thread is about to exit or has exited in +__pthread_kill_internal, and the signal is not sent in this case. + +The test sysdeps/pthread/tst-pthread_cancel-select-loop.c is derived +from a downstream test originally written by Marek Polacek. + +Reviewed-by: Adhemerval Zanella +--- + nptl/allocatestack.c | 3 + + nptl/descr.h | 6 ++ + nptl/pthread_create.c | 14 +++ + nptl/pthread_kill.c | 65 +++++++----- + sysdeps/pthread/Makefile | 2 + + sysdeps/pthread/tst-pthread_cancel-select-loop.c | 87 ++++++++++++++++ + sysdeps/pthread/tst-pthread_kill-exiting.c | 123 +++++++++++++++++++++++ + 7 files changed, 275 insertions(+), 25 deletions(-) + create mode 100644 sysdeps/pthread/tst-pthread_cancel-select-loop.c + create mode 100644 sysdeps/pthread/tst-pthread_kill-exiting.c + +diff --git a/nptl/allocatestack.c b/nptl/allocatestack.c +index 0356993..fa81007 100644 +--- a/nptl/allocatestack.c ++++ b/nptl/allocatestack.c +@@ -31,6 +31,7 @@ + #include + #include + #include ++#include + + /* Default alignment of stack. */ + #ifndef STACK_ALIGN +@@ -126,6 +127,8 @@ get_cached_stack (size_t *sizep, void **memp) + /* No pending event. */ + result->nextevent = NULL; + ++ result->exiting = false; ++ __libc_lock_init (result->exit_lock); + result->tls_state = (struct tls_internal_t) { 0 }; + + /* Clear the DTV. */ +diff --git a/nptl/descr.h b/nptl/descr.h +index e1c8831..41ee56f 100644 +--- a/nptl/descr.h ++++ b/nptl/descr.h +@@ -395,6 +395,12 @@ struct pthread + PTHREAD_CANCEL_ASYNCHRONOUS). */ + unsigned char canceltype; + ++ /* Used in __pthread_kill_internal to detected a thread that has ++ exited or is about to exit. exit_lock must only be acquired ++ after blocking signals. */ ++ bool exiting; ++ int exit_lock; /* A low-level lock (for use with __libc_lock_init etc). */ ++ + /* Used on strsignal. */ + struct tls_internal_t tls_state; + +diff --git a/nptl/pthread_create.c b/nptl/pthread_create.c +index 7607f36..a559f86 100644 +--- a/nptl/pthread_create.c ++++ b/nptl/pthread_create.c +@@ -36,6 +36,7 @@ + #include + #include + #include ++#include + + #include + +@@ -484,6 +485,19 @@ start_thread (void *arg) + /* This was the last thread. */ + exit (0); + ++ /* 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); ++ ++ /* Tell __pthread_kill_internal that this thread is about to exit. ++ If there is a __pthread_kill_internal in progress, this delays ++ the thread exit until the signal has been queued by the kernel ++ (so that the TID used to send it remains valid). */ ++ __libc_lock_lock (pd->exit_lock); ++ pd->exiting = true; ++ __libc_lock_unlock (pd->exit_lock); ++ + #ifndef __ASSUME_SET_ROBUST_LIST + /* If this thread has any robust mutexes locked, handle them now. */ + # if __PTHREAD_MUTEX_HAVE_PREV +diff --git a/nptl/pthread_kill.c b/nptl/pthread_kill.c +index 5d4c86f..fb7862e 100644 +--- a/nptl/pthread_kill.c ++++ b/nptl/pthread_kill.c +@@ -16,6 +16,7 @@ + License along with the GNU C Library; if not, see + . */ + ++#include + #include + #include + #include +@@ -23,37 +24,51 @@ + int + __pthread_kill_internal (pthread_t threadid, int signo) + { +- pid_t tid; + struct pthread *pd = (struct pthread *) threadid; +- + if (pd == THREAD_SELF) +- /* It is a special case to handle raise() implementation after a vfork +- call (which does not update the PD tid field). */ +- tid = INLINE_SYSCALL_CALL (gettid); +- else +- /* Force load of pd->tid into local variable or register. Otherwise +- if a thread exits between ESRCH test and tgkill, we might return +- EINVAL, because pd->tid would be cleared by the kernel. */ +- tid = atomic_forced_read (pd->tid); +- +- int val; +- if (__glibc_likely (tid > 0)) + { +- pid_t pid = __getpid (); +- +- val = INTERNAL_SYSCALL_CALL (tgkill, pid, tid, signo); +- val = (INTERNAL_SYSCALL_ERROR_P (val) +- ? INTERNAL_SYSCALL_ERRNO (val) : 0); ++ /* Use the actual TID from the kernel, so that it refers to the ++ current thread even if called after vfork. There is no ++ signal blocking in this case, so that the signal is delivered ++ immediately, before __pthread_kill_internal returns: a signal ++ sent to the thread itself needs to be delivered ++ synchronously. (It is unclear if Linux guarantees the ++ delivery of all pending signals after unblocking in the code ++ below. POSIX only guarantees delivery of a single signal, ++ which may not be the right one.) */ ++ pid_t tid = INTERNAL_SYSCALL_CALL (gettid); ++ int ret = INTERNAL_SYSCALL_CALL (kill, tid, signo); ++ return INTERNAL_SYSCALL_ERROR_P (ret) ? INTERNAL_SYSCALL_ERRNO (ret) : 0; + } ++ ++ /* Block all signals, as required by pd->exit_lock. */ ++ sigset_t old_mask; ++ __libc_signal_block_all (&old_mask); ++ __libc_lock_lock (pd->exit_lock); ++ ++ int ret; ++ if (pd->exiting) ++ /* The thread is about to exit (or has exited). Sending the ++ signal is either not observable (the target thread has already ++ blocked signals at this point), or it will fail, or it might be ++ delivered to a new, unrelated thread that has reused the TID. ++ So do not actually send the signal. Do not report an error ++ because the threadid argument is still valid (the thread ID ++ lifetime has not ended), and ESRCH (for example) would be ++ misleading. */ ++ ret = 0; + else +- /* The kernel reports that the thread has exited. POSIX specifies +- the ESRCH error only for the case when the lifetime of a thread +- ID has ended, but calling pthread_kill on such a thread ID is +- undefined in glibc. Therefore, do not treat kernel thread exit +- as an error. */ +- val = 0; ++ { ++ /* Using tgkill is a safety measure. pd->exit_lock ensures that ++ the target thread cannot exit. */ ++ ret = INTERNAL_SYSCALL_CALL (tgkill, __getpid (), pd->tid, signo); ++ ret = INTERNAL_SYSCALL_ERROR_P (ret) ? INTERNAL_SYSCALL_ERRNO (ret) : 0; ++ } ++ ++ __libc_lock_unlock (pd->exit_lock); ++ __libc_signal_restore_set (&old_mask); + +- return val; ++ return ret; + } + + int +diff --git a/sysdeps/pthread/Makefile b/sysdeps/pthread/Makefile +index dedfa0d..48dba71 100644 +--- a/sysdeps/pthread/Makefile ++++ b/sysdeps/pthread/Makefile +@@ -119,7 +119,9 @@ tests += tst-cnd-basic tst-mtx-trylock tst-cnd-broadcast \ + tst-unwind-thread \ + tst-pt-vfork1 tst-pt-vfork2 tst-vfork1x tst-vfork2x \ + tst-pthread_cancel-exited \ ++ tst-pthread_cancel-select-loop \ + tst-pthread_kill-exited \ ++ tst-pthread_kill-exiting \ + # tests + + tests-time64 := \ +diff --git a/sysdeps/pthread/tst-pthread_cancel-select-loop.c b/sysdeps/pthread/tst-pthread_cancel-select-loop.c +new file mode 100644 +index 0000000..a620875 +--- /dev/null ++++ b/sysdeps/pthread/tst-pthread_cancel-select-loop.c +@@ -0,0 +1,87 @@ ++/* Test that pthread_cancel succeeds during thread exit. ++ 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 ++ . */ ++ ++/* This test tries to trigger an internal race condition in ++ pthread_cancel, where the cancellation signal is sent after the ++ thread has begun the cancellation process. This can result in a ++ spurious ESRCH error. For the original bug 12889, the window is ++ quite small, so the bug was not reproduced in every run. */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++/* Set to true by timeout_thread_function when the test should ++ terminate. */ ++static bool timeout; ++ ++static void * ++timeout_thread_function (void *unused) ++{ ++ usleep (5 * 1000 * 1000); ++ __atomic_store_n (&timeout, true, __ATOMIC_RELAXED); ++ return NULL; ++} ++ ++/* Used for blocking the select function below. */ ++static int pipe_fds[2]; ++ ++static void * ++canceled_thread_function (void *unused) ++{ ++ while (true) ++ { ++ fd_set rfs; ++ fd_set wfs; ++ fd_set efs; ++ FD_ZERO (&rfs); ++ FD_ZERO (&wfs); ++ FD_ZERO (&efs); ++ FD_SET (pipe_fds[0], &rfs); ++ ++ /* If the cancellation request is recognized early, the thread ++ begins exiting while the cancellation signal arrives. */ ++ select (FD_SETSIZE, &rfs, &wfs, &efs, NULL); ++ } ++ return NULL; ++} ++ ++static int ++do_test (void) ++{ ++ xpipe (pipe_fds); ++ pthread_t thr_timeout = xpthread_create (NULL, timeout_thread_function, NULL); ++ ++ while (!__atomic_load_n (&timeout, __ATOMIC_RELAXED)) ++ { ++ pthread_t thr = xpthread_create (NULL, canceled_thread_function, NULL); ++ xpthread_cancel (thr); ++ TEST_VERIFY (xpthread_join (thr) == PTHREAD_CANCELED); ++ } ++ ++ xpthread_join (thr_timeout); ++ xclose (pipe_fds[0]); ++ xclose (pipe_fds[1]); ++ return 0; ++} ++ ++#include +diff --git a/sysdeps/pthread/tst-pthread_kill-exiting.c b/sysdeps/pthread/tst-pthread_kill-exiting.c +new file mode 100644 +index 0000000..f803e94 +--- /dev/null ++++ b/sysdeps/pthread/tst-pthread_kill-exiting.c +@@ -0,0 +1,123 @@ ++/* Test that pthread_kill succeeds during thread exit. ++ 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 ++ . */ ++ ++/* This test verifies that pthread_kill for a thread that is exiting ++ succeeds (with or without actually delivering the signal). */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++/* Set to true by timeout_thread_function when the test should ++ terminate. */ ++static bool timeout; ++ ++static void * ++timeout_thread_function (void *unused) ++{ ++ usleep (1000 * 1000); ++ __atomic_store_n (&timeout, true, __ATOMIC_RELAXED); ++ return NULL; ++} ++ ++/* Used to synchronize the sending threads with the target thread and ++ main thread. */ ++static pthread_barrier_t barrier_1; ++static pthread_barrier_t barrier_2; ++ ++/* The target thread to which signals are to be sent. */ ++static pthread_t target_thread; ++ ++/* Set by the main thread to true after timeout has been set to ++ true. */ ++static bool exiting; ++ ++static void * ++sender_thread_function (void *unused) ++{ ++ while (true) ++ { ++ /* Wait until target_thread has been initialized. The target ++ thread and main thread participate in this barrier. */ ++ xpthread_barrier_wait (&barrier_1); ++ ++ if (exiting) ++ break; ++ ++ xpthread_kill (target_thread, SIGUSR1); ++ ++ /* Communicate that the signal has been sent. The main thread ++ participates in this barrier. */ ++ xpthread_barrier_wait (&barrier_2); ++ } ++ return NULL; ++} ++ ++static void * ++target_thread_function (void *unused) ++{ ++ target_thread = pthread_self (); ++ xpthread_barrier_wait (&barrier_1); ++ return NULL; ++} ++ ++static int ++do_test (void) ++{ ++ xsignal (SIGUSR1, SIG_IGN); ++ ++ pthread_t thr_timeout = xpthread_create (NULL, timeout_thread_function, NULL); ++ ++ pthread_t threads[4]; ++ xpthread_barrier_init (&barrier_1, NULL, array_length (threads) + 2); ++ xpthread_barrier_init (&barrier_2, NULL, array_length (threads) + 1); ++ ++ for (int i = 0; i < array_length (threads); ++i) ++ threads[i] = xpthread_create (NULL, sender_thread_function, NULL); ++ ++ while (!__atomic_load_n (&timeout, __ATOMIC_RELAXED)) ++ { ++ xpthread_create (NULL, target_thread_function, NULL); ++ ++ /* Wait for the target thread to be set up and signal sending to ++ start. */ ++ xpthread_barrier_wait (&barrier_1); ++ ++ /* Wait for signal sending to complete. */ ++ xpthread_barrier_wait (&barrier_2); ++ ++ xpthread_join (target_thread); ++ } ++ ++ exiting = true; ++ ++ /* Signal the sending threads to exit. */ ++ xpthread_create (NULL, target_thread_function, NULL); ++ xpthread_barrier_wait (&barrier_1); ++ ++ for (int i = 0; i < array_length (threads); ++i) ++ xpthread_join (threads[i]); ++ xpthread_join (thr_timeout); ++ ++ return 0; ++} ++ ++#include +-- +1.8.3.1 + diff --git a/nptl-Fix-type-of-pthread_mutexattr_getrobust_np-pthr.patch b/nptl-Fix-type-of-pthread_mutexattr_getrobust_np-pthr.patch new file mode 100644 index 0000000..b92e3c5 --- /dev/null +++ b/nptl-Fix-type-of-pthread_mutexattr_getrobust_np-pthr.patch @@ -0,0 +1,37 @@ +From f3e664563361dc17530113b3205998d1f19dc4d9 Mon Sep 17 00:00:00 2001 +From: Florian Weimer +Date: Tue, 21 Sep 2021 07:12:56 +0200 +Subject: [PATCH] nptl: Fix type of pthread_mutexattr_getrobust_np, + pthread_mutexattr_setrobust_np (bug 28036) + +Reviewed-by: Carlos O'Donell +Tested-by: Carlos O'Donell +--- + sysdeps/nptl/pthread.h | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/sysdeps/nptl/pthread.h b/sysdeps/nptl/pthread.h +index f1b7f2b..43146e9 100644 +--- a/sysdeps/nptl/pthread.h ++++ b/sysdeps/nptl/pthread.h +@@ -933,7 +933,7 @@ extern int pthread_mutexattr_getrobust (const pthread_mutexattr_t *__attr, + # ifdef __USE_GNU + # ifdef __REDIRECT_NTH + extern int __REDIRECT_NTH (pthread_mutexattr_getrobust_np, +- (pthread_mutex_t *, int *), ++ (pthread_mutexattr_t *, int *), + pthread_mutexattr_getrobust) __nonnull ((1)) + __attribute_deprecated_msg__ ("\ + pthread_mutexattr_getrobust_np is deprecated, use pthread_mutexattr_getrobust"); +@@ -949,7 +949,7 @@ extern int pthread_mutexattr_setrobust (pthread_mutexattr_t *__attr, + # ifdef __USE_GNU + # ifdef __REDIRECT_NTH + extern int __REDIRECT_NTH (pthread_mutexattr_setrobust_np, +- (pthread_mutex_t *, int), ++ (pthread_mutexattr_t *, int), + pthread_mutexattr_setrobust) __nonnull ((1)) + __attribute_deprecated_msg__ ("\ + pthread_mutexattr_setrobust_np is deprecated, use pthread_mutexattr_setrobust"); +-- +1.8.3.1 + diff --git a/nptl-pthread_kill-must-send-signals-to-a-specific-th.patch b/nptl-pthread_kill-must-send-signals-to-a-specific-th.patch new file mode 100644 index 0000000..87683c3 --- /dev/null +++ b/nptl-pthread_kill-must-send-signals-to-a-specific-th.patch @@ -0,0 +1,162 @@ +From eae81d70574e923ce3c59078b8df857ae192efa6 Mon Sep 17 00:00:00 2001 +From: Florian Weimer +Date: Fri, 1 Oct 2021 18:16:41 +0200 +Subject: [PATCH] nptl: pthread_kill must send signals to a specific thread [BZ + #28407] + +The choice between the kill vs tgkill system calls is not just about +the TID reuse race, but also about whether the signal is sent to the +whole process (and any thread in it) or to a specific thread. + +This was caught by the openposix test suite: + + LTP: openposix test suite - FAIL: SIGUSR1 is member of new thread pendingset. + + +Fixes commit 526c3cf11ee9367344b6b15d669e4c3cb461a2be ("nptl: Fix race +between pthread_kill and thread exit (bug 12889)"). + +Reviewed-by: Carlos O'Donell +Tested-by: Carlos O'Donell +--- + nptl/pthread_kill.c | 4 +- + sysdeps/pthread/Makefile | 1 + + sysdeps/pthread/tst-pthread-raise-blocked-self.c | 92 ++++++++++++++++++++++++ + 3 files changed, 94 insertions(+), 3 deletions(-) + create mode 100644 sysdeps/pthread/tst-pthread-raise-blocked-self.c + +diff --git a/nptl/pthread_kill.c b/nptl/pthread_kill.c +index a44dc8f..35bf1f9 100644 +--- a/nptl/pthread_kill.c ++++ b/nptl/pthread_kill.c +@@ -40,7 +40,7 @@ __pthread_kill_implementation (pthread_t threadid, int signo, int no_tid) + below. POSIX only guarantees delivery of a single signal, + which may not be the right one.) */ + pid_t tid = INTERNAL_SYSCALL_CALL (gettid); +- int ret = INTERNAL_SYSCALL_CALL (kill, tid, signo); ++ int ret = INTERNAL_SYSCALL_CALL (tgkill, __getpid (), tid, signo); + return INTERNAL_SYSCALL_ERROR_P (ret) ? INTERNAL_SYSCALL_ERRNO (ret) : 0; + } + +@@ -59,8 +59,6 @@ __pthread_kill_implementation (pthread_t threadid, int signo, int no_tid) + ret = no_tid; + else + { +- /* Using tgkill is a safety measure. pd->exit_lock ensures that +- the target thread cannot exit. */ + ret = INTERNAL_SYSCALL_CALL (tgkill, __getpid (), pd->tid, signo); + ret = INTERNAL_SYSCALL_ERROR_P (ret) ? INTERNAL_SYSCALL_ERRNO (ret) : 0; + } +diff --git a/sysdeps/pthread/Makefile b/sysdeps/pthread/Makefile +index d4bd2d4..0af9c59 100644 +--- a/sysdeps/pthread/Makefile ++++ b/sysdeps/pthread/Makefile +@@ -121,6 +121,7 @@ tests += tst-cnd-basic tst-mtx-trylock tst-cnd-broadcast \ + tst-pthread-setuid-loop \ + tst-pthread_cancel-exited \ + tst-pthread_cancel-select-loop \ ++ tst-pthread-raise-blocked-self \ + tst-pthread_kill-exited \ + tst-pthread_kill-exiting \ + # tests +diff --git a/sysdeps/pthread/tst-pthread-raise-blocked-self.c b/sysdeps/pthread/tst-pthread-raise-blocked-self.c +new file mode 100644 +index 0000000..128e1a6 +--- /dev/null ++++ b/sysdeps/pthread/tst-pthread-raise-blocked-self.c +@@ -0,0 +1,92 @@ ++/* Test that raise sends signal to current thread even if blocked. ++ 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 ++ . */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++/* Used to create a dummy thread ID distinct from all other thread ++ IDs. */ ++static void * ++noop (void *ignored) ++{ ++ return NULL; ++} ++ ++static volatile pthread_t signal_thread; ++ ++static void ++signal_handler (int signo) ++{ ++ signal_thread = pthread_self (); ++} ++ ++/* Used to ensure that waiting_thread has launched and can accept ++ signals. */ ++static pthread_barrier_t barrier; ++ ++static void * ++waiting_thread (void *ignored) ++{ ++ xpthread_barrier_wait (&barrier); ++ pause (); ++ return NULL; ++} ++ ++static int ++do_test (void) ++{ ++ xsignal (SIGUSR1, signal_handler); ++ xpthread_barrier_init (&barrier, NULL, 2); ++ ++ /* Distinct thread ID value to */ ++ pthread_t dummy = xpthread_create (NULL, noop, NULL); ++ signal_thread = dummy; ++ ++ pthread_t helper = xpthread_create (NULL, waiting_thread, NULL); ++ ++ /* Make sure that the thread is running. */ ++ xpthread_barrier_wait (&barrier); ++ ++ /* Block signals on this thread. */ ++ sigset_t set; ++ sigfillset (&set); ++ xpthread_sigmask (SIG_BLOCK, &set, NULL); ++ ++ /* Send the signal to this thread. It must not be delivered. */ ++ raise (SIGUSR1); ++ TEST_VERIFY (signal_thread == dummy); ++ ++ /* Wait a bit to give a chance for signal delivery (increases ++ chances of failure with bug 28407). */ ++ usleep (50 * 1000); ++ ++ /* Unblocking should cause synchronous delivery of the signal. */ ++ xpthread_sigmask (SIG_UNBLOCK, &set, NULL); ++ TEST_VERIFY (signal_thread == pthread_self ()); ++ ++ xpthread_cancel (helper); ++ xpthread_join (helper); ++ xpthread_join (dummy); ++ return 0; ++} ++ ++#include +-- +1.8.3.1 + diff --git a/nptl-pthread_kill-needs-to-return-ESRCH-for-old-prog.patch b/nptl-pthread_kill-needs-to-return-ESRCH-for-old-prog.patch new file mode 100644 index 0000000..d52abb8 --- /dev/null +++ b/nptl-pthread_kill-needs-to-return-ESRCH-for-old-prog.patch @@ -0,0 +1,142 @@ +From 95dba35bf05e4a5d69dfae5e9c9d4df3646a7f93 Mon Sep 17 00:00:00 2001 +From: Florian Weimer +Date: Mon, 20 Sep 2021 14:56:08 +0200 +Subject: [PATCH] nptl: pthread_kill needs to return ESRCH for old programs + (bug 19193) + +The fix for bug 19193 breaks some old applications which appear +to use pthread_kill to probe if a thread is still running, something +that is not supported by POSIX. +--- + nptl/pthread_kill.c | 37 ++++++++++++++++++++++++------- + sysdeps/pthread/tst-pthread_kill-exited.c | 21 ++++++++++++++++-- + 2 files changed, 48 insertions(+), 10 deletions(-) + +diff --git a/nptl/pthread_kill.c b/nptl/pthread_kill.c +index fb7862e..a44dc8f 100644 +--- a/nptl/pthread_kill.c ++++ b/nptl/pthread_kill.c +@@ -21,8 +21,11 @@ + #include + #include + +-int +-__pthread_kill_internal (pthread_t threadid, int signo) ++/* Sends SIGNO to THREADID. If the thread is about to exit or has ++ already exited on the kernel side, return NO_TID. Otherwise return ++ 0 or an error code. */ ++static int ++__pthread_kill_implementation (pthread_t threadid, int signo, int no_tid) + { + struct pthread *pd = (struct pthread *) threadid; + if (pd == THREAD_SELF) +@@ -52,11 +55,8 @@ __pthread_kill_internal (pthread_t threadid, int signo) + signal is either not observable (the target thread has already + blocked signals at this point), or it will fail, or it might be + delivered to a new, unrelated thread that has reused the TID. +- So do not actually send the signal. Do not report an error +- because the threadid argument is still valid (the thread ID +- lifetime has not ended), and ESRCH (for example) would be +- misleading. */ +- ret = 0; ++ So do not actually send the signal. */ ++ ret = no_tid; + else + { + /* Using tgkill is a safety measure. pd->exit_lock ensures that +@@ -72,6 +72,15 @@ __pthread_kill_internal (pthread_t threadid, int signo) + } + + int ++__pthread_kill_internal (pthread_t threadid, int signo) ++{ ++ /* Do not report an error in the no-tid case because the threadid ++ argument is still valid (the thread ID lifetime has not ended), ++ and ESRCH (for example) would be misleading. */ ++ return __pthread_kill_implementation (threadid, signo, 0); ++} ++ ++int + __pthread_kill (pthread_t threadid, int signo) + { + /* Disallow sending the signal we use for cancellation, timers, +@@ -81,6 +90,7 @@ __pthread_kill (pthread_t threadid, int signo) + + return __pthread_kill_internal (threadid, signo); + } ++ + /* Some architectures (for instance arm) might pull raise through libgcc, so + avoid the symbol version if it ends up being used on ld.so. */ + #if !IS_IN(rtld) +@@ -88,6 +98,17 @@ libc_hidden_def (__pthread_kill) + versioned_symbol (libc, __pthread_kill, pthread_kill, GLIBC_2_34); + + # if OTHER_SHLIB_COMPAT (libpthread, GLIBC_2_0, GLIBC_2_34) +-compat_symbol (libc, __pthread_kill, pthread_kill, GLIBC_2_0); ++/* Variant which returns ESRCH in the no-TID case, for backwards ++ compatibility. */ ++int ++attribute_compat_text_section ++__pthread_kill_esrch (pthread_t threadid, int signo) ++{ ++ if (__is_internal_signal (signo)) ++ return EINVAL; ++ ++ return __pthread_kill_implementation (threadid, signo, ESRCH); ++} ++compat_symbol (libc, __pthread_kill_esrch, pthread_kill, GLIBC_2_0); + # endif + #endif +diff --git a/sysdeps/pthread/tst-pthread_kill-exited.c b/sysdeps/pthread/tst-pthread_kill-exited.c +index 7575fb6..a2fddad 100644 +--- a/sysdeps/pthread/tst-pthread_kill-exited.c ++++ b/sysdeps/pthread/tst-pthread_kill-exited.c +@@ -16,11 +16,15 @@ + License along with the GNU C Library; if not, see + . */ + +-/* This test verifies that pthread_kill returns 0 (and not ESRCH) for +- a thread that has exited on the kernel side. */ ++/* This test verifies that the default pthread_kill returns 0 (and not ++ ESRCH) for a thread that has exited on the kernel side. */ + ++#include ++#include ++#include + #include + #include ++#include + #include + #include + +@@ -30,6 +34,12 @@ noop_thread (void *closure) + return NULL; + } + ++#if TEST_COMPAT (libpthread, GLIBC_2_0, GLIBC_2_34) && PTHREAD_IN_LIBC ++extern __typeof (pthread_kill) compat_pthread_kill; ++compat_symbol_reference (libpthread, compat_pthread_kill, pthread_kill, ++ GLIBC_2_0); ++#endif ++ + static int + do_test (void) + { +@@ -37,7 +47,14 @@ do_test (void) + + support_wait_for_thread_exit (); + ++ /* NB: Always uses the default symbol due to separate compilation. */ + xpthread_kill (thr, SIGUSR1); ++ ++#if TEST_COMPAT (libpthread, GLIBC_2_0, GLIBC_2_34) && PTHREAD_IN_LIBC ++ /* Old binaries need the non-conforming ESRCH error code. */ ++ TEST_COMPARE (compat_pthread_kill (thr, SIGUSR1), ESRCH); ++#endif ++ + xpthread_join (thr); + + return 0; +-- +1.8.3.1 + -- Gitee