git: 47413f23e503 - main - clnt_broadcast(3): don't free function pointers

From: Brooks Davis <brooks_at_FreeBSD.org>
Date: Mon, 02 Feb 2026 21:20:33 UTC
The branch main has been updated by brooks:

URL: https://cgit.FreeBSD.org/src/commit/?id=47413f23e503e796989b35dfb04e453c5b6e2d01

commit 47413f23e503e796989b35dfb04e453c5b6e2d01
Author:     Brooks Davis <brooks@FreeBSD.org>
AuthorDate: 2026-02-02 21:20:01 +0000
Commit:     Brooks Davis <brooks@FreeBSD.org>
CommitDate: 2026-02-02 21:20:01 +0000

    clnt_broadcast(3): don't free function pointers
    
    Replace use of thr_getspecific/thr_setspecific to stash the function
    pointer we're smuggling between clnt_broadcast and rpc_wrap_bcast with a
    simple thread local variable.  Clear it after use so the reference
    doesn't linger.
    
    In the relatively unlikely event clnt_broadcast was called from threads
    that exited prior to program termination, the previous code called free
    on a function pointer, which is undefined and might corrupted allocator
    state.
    
    Effort:         CHERI upstreaming
    Reviewed by:    glebius, jhb
    Sponsored by:   DARPA, AFRL
    Differential Revision:  https://reviews.freebsd.org/D54939
---
 lib/libc/rpc/rpc_soc.c | 35 ++++++++++-------------------------
 1 file changed, 10 insertions(+), 25 deletions(-)

diff --git a/lib/libc/rpc/rpc_soc.c b/lib/libc/rpc/rpc_soc.c
index c63b89594ce6..21a36cedf69f 100644
--- a/lib/libc/rpc/rpc_soc.c
+++ b/lib/libc/rpc/rpc_soc.c
@@ -307,19 +307,10 @@ registerrpc(int prognum, int versnum, int procnum,
 }
 
 /*
- * All the following clnt_broadcast stuff is convulated; it supports
- * the earlier calling style of the callback function
+ * Support the earlier calling style of the callback function with a
+ * per-thread temporary copy of the real callback.
  */
-static thread_key_t	clnt_broadcast_key;
-static resultproc_t	clnt_broadcast_result_main;
-static once_t		clnt_broadcast_once = ONCE_INITIALIZER;
-
-static void
-clnt_broadcast_key_init(void)
-{
-
-	thr_keycreate(&clnt_broadcast_key, free);
-}
+static _Thread_local resultproc_t	clnt_broadcast_result;
 
 /*
  * Need to translate the netbuf address into sockaddr_in address.
@@ -334,14 +325,8 @@ rpc_wrap_bcast(char *resultp, struct netbuf *addr, struct netconfig *nconf)
  *	struct netconfig *nconf; // Netconf of the transport
  */
 {
-	resultproc_t clnt_broadcast_result;
-
 	if (strcmp(nconf->nc_netid, "udp"))
 		return (FALSE);
-	if (thr_main())
-		clnt_broadcast_result = clnt_broadcast_result_main;
-	else
-		clnt_broadcast_result = (resultproc_t)thr_getspecific(clnt_broadcast_key);
 	return (*clnt_broadcast_result)(resultp,
 				(struct sockaddr_in *)addr->buf);
 }
@@ -363,16 +348,16 @@ clnt_broadcast(u_long prog, u_long vers, u_long proc, xdrproc_t xargs,
  *	resultproc_t	eachresult;	// call with each result obtained
  */
 {
+	enum clnt_stat ret;
 
-	if (thr_main())
-		clnt_broadcast_result_main = eachresult;
-	else {
-		thr_once(&clnt_broadcast_once, clnt_broadcast_key_init);
-		thr_setspecific(clnt_broadcast_key, (void *) eachresult);
-	}
-	return rpc_broadcast((rpcprog_t)prog, (rpcvers_t)vers,
+	clnt_broadcast_result = eachresult;
+
+	ret = rpc_broadcast((rpcprog_t)prog, (rpcvers_t)vers,
 	    (rpcproc_t)proc, xargs, argsp, xresults, resultsp,
 	    (resultproc_t) rpc_wrap_bcast, "udp");
+
+	clnt_broadcast_result = NULL;
+	return (ret);
 }
 
 /*