From 17d91f08573a4cf392b302790e3524b92f6057f0 Mon Sep 17 00:00:00 2001 From: Adhemerval Zanella Date: Thu, 9 Sep 2021 17:13:05 -0300 Subject: [PATCH] nptl: Use exit_lock when accessing TID on pthread_sigqueue Also return EINVAL if the thread is already terminated at the time of the call. Checked on x86_64-linux-gnu. --- nptl/pthread_sigqueue.c | 56 ++++++++++++++-------------- sysdeps/pthread/tst-pthread-exited.c | 6 +++ 2 files changed, 34 insertions(+), 28 deletions(-) diff --git a/nptl/pthread_sigqueue.c b/nptl/pthread_sigqueue.c index cd7d8cc775..195bc6ca79 100644 --- a/nptl/pthread_sigqueue.c +++ b/nptl/pthread_sigqueue.c @@ -16,6 +16,7 @@ . */ #include +#include #include #include #include @@ -27,41 +28,40 @@ int __pthread_sigqueue (pthread_t threadid, int signo, const union sigval value) { -#ifdef __NR_rt_tgsigqueueinfo - struct pthread *pd = (struct pthread *) threadid; - - /* 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. */ - pid_t tid = atomic_forced_read (pd->tid); - if (__glibc_unlikely (tid <= 0)) - /* Not a valid thread handle. */ - return ESRCH; - /* Disallow sending the signal we use for cancellation, timers, for the setxid implementation. */ if (signo == SIGCANCEL || signo == SIGTIMER || signo == SIGSETXID) return EINVAL; - pid_t pid = getpid (); + struct pthread *pd = (struct pthread *) threadid; - /* Set up the siginfo_t structure. */ - siginfo_t info; - memset (&info, '\0', sizeof (siginfo_t)); - info.si_signo = signo; - info.si_code = SI_QUEUE; - info.si_pid = pid; - info.si_uid = __getuid (); - info.si_value = value; + /* Block all signals, as required by pd->exit_lock. */ + internal_sigset_t old_mask; + internal_signal_block_all (&old_mask); + __libc_lock_lock (pd->exit_lock); - /* We have a special syscall to do the work. */ - int val = INTERNAL_SYSCALL_CALL (rt_tgsigqueueinfo, pid, tid, signo, - &info); - return (INTERNAL_SYSCALL_ERROR_P (val) - ? INTERNAL_SYSCALL_ERRNO (val) : 0); -#else - return ENOSYS; -#endif + int res; + if (pd->tid != 0) + { + pid_t pid = getpid (); + + siginfo_t info = { 0 }; + info.si_signo = signo; + info.si_code = SI_QUEUE; + info.si_pid = pid; + info.si_uid = __getuid (); + info.si_value = value; + + res = -INTERNAL_SYSCALL_CALL (rt_tgsigqueueinfo, pid, pd->tid, signo, + &info); + } + else + res = EINVAL; + + __libc_lock_unlock (pd->exit_lock); + internal_signal_restore_set (&old_mask); + + return res; } versioned_symbol (libc, __pthread_sigqueue, pthread_sigqueue, GLIBC_2_34); diff --git a/sysdeps/pthread/tst-pthread-exited.c b/sysdeps/pthread/tst-pthread-exited.c index 6a602afe3f..ec8403eeb7 100644 --- a/sysdeps/pthread/tst-pthread-exited.c +++ b/sysdeps/pthread/tst-pthread-exited.c @@ -75,6 +75,12 @@ do_test (void) TEST_COMPARE (r, EINVAL); } + { + union sigval value = { 0 }; + int r = pthread_sigqueue (thr, SIGUSR1, value); + TEST_COMPARE (r, EINVAL); + } + xpthread_join (thr); return 0; -- 2.47.2