The branch main has been updated by brooks: URL: https://cgit.FreeBSD.org/src/commit/?id=47413f23e503e796989b35dfb04e453c5b6e2d01
commit 47413f23e503e796989b35dfb04e453c5b6e2d01 Author: Brooks Davis <[email protected]> AuthorDate: 2026-02-02 21:20:01 +0000 Commit: Brooks Davis <[email protected]> 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); } /*
