From fe2c818f75d8f9b7b4bebb411f2970fda4f2fcb6 Mon Sep 17 00:00:00 2001 From: Adhemerval Zanella Date: Mon, 23 Aug 2021 14:30:51 -0300 Subject: [PATCH] nptl: Use exit_lock when accessing TID on pthread_getname_np Also return EINVAL if the thread is already terminated at the time of the call. Checked on x86_64-linux-gnu. --- nptl/pthread_getname.c | 65 +++++++++++++++++----------- sysdeps/pthread/tst-pthread-exited.c | 6 +++ 2 files changed, 45 insertions(+), 26 deletions(-) diff --git a/nptl/pthread_getname.c b/nptl/pthread_getname.c index 535932b815..ac9f4ad089 100644 --- a/nptl/pthread_getname.c +++ b/nptl/pthread_getname.c @@ -16,43 +16,27 @@ License along with the GNU C Library; see the file COPYING.LIB. If not, see . */ -#include -#include +#include +#include +#include #include +#include #include -#include -#include #include -#include -#include -int -__pthread_getname_np (pthread_t th, char *buf, size_t len) +static int +getname (pid_t tid, char *buf, size_t len) { - const struct pthread *pd = (const struct pthread *) th; - - /* Unfortunately the kernel headers do not export the TASK_COMM_LEN - macro. So we have to define it here. */ -#define TASK_COMM_LEN 16 - if (len < TASK_COMM_LEN) - return ERANGE; - - if (pd == THREAD_SELF) - return __prctl (PR_GET_NAME, buf) ? errno : 0; - -#define FMT "/proc/self/task/%u/comm" - char fname[sizeof (FMT) + 8]; - sprintf (fname, FMT, (unsigned int) pd->tid); + char fname[sizeof ("/proc/self/task//comm") + INT_BUFSIZE_BOUND (pid_t)]; + __snprintf (fname, sizeof (fname), "/proc/self/task/%d/comm", tid); int fd = __open64_nocancel (fname, O_RDONLY); if (fd == -1) - return errno; + return EINVAL; int res = 0; ssize_t n = TEMP_FAILURE_RETRY (__read_nocancel (fd, buf, len)); - if (n < 0) - res = errno; - else + if (n > 0) { if (buf[n - 1] == '\n') buf[n - 1] = '\0'; @@ -61,11 +45,40 @@ __pthread_getname_np (pthread_t th, char *buf, size_t len) else buf[n] = '\0'; } + else + res = errno == ENOENT ? EINVAL : errno;; __close_nocancel_nostatus (fd); return res; } + +int +__pthread_getname_np (pthread_t th, char *buf, size_t len) +{ + struct pthread *pd = (struct pthread *) th; + + /* Unfortunately the kernel headers do not export the TASK_COMM_LEN + macro. So we have to define it here. */ +#define TASK_COMM_LEN 16 + if (len < TASK_COMM_LEN) + return ERANGE; + + if (pd == THREAD_SELF) + return __prctl (PR_GET_NAME, buf) ? errno : 0; + + /* 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); + + int res = pd->tid > 0 ? getname (pd->tid, buf, len) : EINVAL; + + __libc_lock_unlock (pd->exit_lock); + internal_signal_restore_set (&old_mask); + + return res; +} versioned_symbol (libc, __pthread_getname_np, pthread_getname_np, GLIBC_2_34); diff --git a/sysdeps/pthread/tst-pthread-exited.c b/sysdeps/pthread/tst-pthread-exited.c index 91c6533235..8f33de44b6 100644 --- a/sysdeps/pthread/tst-pthread-exited.c +++ b/sysdeps/pthread/tst-pthread-exited.c @@ -63,6 +63,12 @@ do_test (void) TEST_COMPARE (r, EINVAL); } + { + char thread_name[16]; + int r = pthread_getname_np (thr, thread_name, sizeof (thread_name)); + TEST_COMPARE (r, EINVAL); + } + xpthread_join (thr); return 0; -- 2.47.2