git: 49e0c6270c73 - main - libthr: fix the race between pthread_getname_np() and thread exit

From: Konstantin Belousov <kib_at_FreeBSD.org>
Date: Fri, 30 Oct 2026 13:52:35 UTC
The branch main has been updated by kib:

URL: https://cgit.FreeBSD.org/src/commit/?id=49e0c6270c73f1570efc67028004db9da56da2d1

commit 49e0c6270c73f1570efc67028004db9da56da2d1
Author:     Konstantin Belousov <kib@FreeBSD.org>
AuthorDate: 2026-10-19 21:59:52 +0000
Commit:     Konstantin Belousov <kib@FreeBSD.org>
CommitDate: 2026-10-30 13:51:02 +0000

    libthr: fix the race between pthread_getname_np() and thread exit
    
    The exiting thread frees the thread name in exit_thread() without
    holding the thread lock.  This makes it possible for a thread doing
    pthread_getname_np() to observe the non-null thread->name and try to
    copy its content, accessing the memory after free.
    
    Set the thread->name to NULL under the thread lock.  Note that other
    thread might still set the exiting thread name, until the PS_DEAD state
    is assigned.  Since code should not call free() after
    _malloc_thread_cleanup(), re-check thread->name in _thr_free().
    
    Reviewed by:    aokblast, markj
    Sponsored by:   The FreeBSD Foundation
    MFC after:      1 week
    Differential revision:  https://reviews.freebsd.org/D60838
---
 lib/libthr/thread/thr_exit.c | 2 ++
 lib/libthr/thread/thr_list.c | 4 ++++
 2 files changed, 6 insertions(+)

diff --git a/lib/libthr/thread/thr_exit.c b/lib/libthr/thread/thr_exit.c
index 5a9dcf99fa21..4c9692ccf1a5 100644
--- a/lib/libthr/thread/thr_exit.c
+++ b/lib/libthr/thread/thr_exit.c
@@ -278,8 +278,10 @@ exit_thread(void)
 {
 	struct pthread *curthread = _get_curthread();
 
+	THR_LOCK(curthread);
 	free(curthread->name);
 	curthread->name = NULL;
+	THR_UNLOCK(curthread);
 
 	/* Check if there is thread specific data: */
 	if (curthread->specific != NULL) {
diff --git a/lib/libthr/thread/thr_list.c b/lib/libthr/thread/thr_list.c
index cbf16179f619..62fb6e3a3b45 100644
--- a/lib/libthr/thread/thr_list.c
+++ b/lib/libthr/thread/thr_list.c
@@ -203,6 +203,10 @@ _thr_free(struct pthread *curthread, struct pthread *thread)
 		_tcb_dtor(thread->tcb);
 	}
 	thread->tcb = NULL;
+	if (thread->name != NULL) {
+		free(thread->name);
+		thread->name = NULL;
+	}
 	if ((curthread == NULL) || (free_thread_count >= MAX_CACHED_THREADS)) {
 		thr_destroy(curthread, thread);
 		atomic_add_int(&total_threads, -1);