Module Name: src Committed By: riastradh Date: Sun Mar 2 22:46:24 UTC 2025
Modified Files: src/lib/libc/gen: arc4random.c pthread_atfork.c Log Message: libc: New __libc_atfork. This uses caller-provided storage for the callback queues. Use it in arc4random(3) in order to avoid possible failure modes. This is a private symbol, not designed for use outside NetBSD, and the API is not intended to be stable (yet) -- I just took the existing purely internal structure (struct atfork_callback) and reused it for this API without changing any of the calling-side logic. We could change it, e.g. to use a single structure per call, to make the API a little less unwieldy, at the cost of microscopically more storage and runtime for the users that don't use all three callbacks; to be considered in a future change. We might reasonably use __libc_atfork in libpthread for use in the pthread_tsd_init constructor, in order to be confident it never attempts malloc(3), but let's do that in a separate commit just in case anything goes awry with that plan. PR lib/59112: libpthread constructors use malloc PR lib/59117: arc4random has some failure modes it shouldn't To generate a diff of this commit: cvs rdiff -u -r1.39 -r1.40 src/lib/libc/gen/arc4random.c cvs rdiff -u -r1.23 -r1.24 src/lib/libc/gen/pthread_atfork.c Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Modified files: Index: src/lib/libc/gen/arc4random.c diff -u src/lib/libc/gen/arc4random.c:1.39 src/lib/libc/gen/arc4random.c:1.40 --- src/lib/libc/gen/arc4random.c:1.39 Sun Mar 2 21:35:59 2025 +++ src/lib/libc/gen/arc4random.c Sun Mar 2 22:46:23 2025 @@ -1,4 +1,4 @@ -/* $NetBSD: arc4random.c,v 1.39 2025/03/02 21:35:59 riastradh Exp $ */ +/* $NetBSD: arc4random.c,v 1.40 2025/03/02 22:46:23 riastradh Exp $ */ /*- * Copyright (c) 2014 The NetBSD Foundation, Inc. @@ -52,7 +52,7 @@ */ #include <sys/cdefs.h> -__RCSID("$NetBSD: arc4random.c,v 1.39 2025/03/02 21:35:59 riastradh Exp $"); +__RCSID("$NetBSD: arc4random.c,v 1.40 2025/03/02 22:46:23 riastradh Exp $"); #include "namespace.h" #include "reentrant.h" @@ -73,6 +73,7 @@ __RCSID("$NetBSD: arc4random.c,v 1.39 20 #include <unistd.h> #include "arc4random.h" +#include "atfork.h" #include "reentrant.h" #ifdef __weak_alias @@ -534,6 +535,7 @@ struct arc4random_global_state arc4rando .initialized = false, }; +static struct atfork_callback arc4random_atfork_prepare_cb; static void arc4random_atfork_prepare(void) { @@ -543,6 +545,7 @@ arc4random_atfork_prepare(void) sizeof arc4random_global.prng); } +static struct atfork_callback arc4random_atfork_parent_cb; static void arc4random_atfork_parent(void) { @@ -550,6 +553,7 @@ arc4random_atfork_parent(void) mutex_unlock(&arc4random_global.lock); } +static struct atfork_callback arc4random_atfork_child_cb; static void arc4random_atfork_child(void) { @@ -575,10 +579,10 @@ arc4random_initialize(void) if (!arc4random_global.initialized) { if (crypto_core_selftest() != 0) abort(); - if (pthread_atfork(&arc4random_atfork_prepare, - &arc4random_atfork_parent, &arc4random_atfork_child) - != 0) - abort(); + __libc_atfork( + &arc4random_atfork_prepare_cb, &arc4random_atfork_prepare, + &arc4random_atfork_parent_cb, &arc4random_atfork_parent, + &arc4random_atfork_child_cb, &arc4random_atfork_child); #ifdef _REENTRANT if (thr_keycreate(&arc4random_global.thread_key, &arc4random_tsd_destructor) == 0) Index: src/lib/libc/gen/pthread_atfork.c diff -u src/lib/libc/gen/pthread_atfork.c:1.23 src/lib/libc/gen/pthread_atfork.c:1.24 --- src/lib/libc/gen/pthread_atfork.c:1.23 Sat Mar 1 20:31:58 2025 +++ src/lib/libc/gen/pthread_atfork.c Sun Mar 2 22:46:23 2025 @@ -1,4 +1,4 @@ -/* $NetBSD: pthread_atfork.c,v 1.23 2025/03/01 20:31:58 christos Exp $ */ +/* $NetBSD: pthread_atfork.c,v 1.24 2025/03/02 22:46:23 riastradh Exp $ */ /*- * Copyright (c) 2002 The NetBSD Foundation, Inc. @@ -31,15 +31,18 @@ #include <sys/cdefs.h> #if defined(LIBC_SCCS) && !defined(lint) -__RCSID("$NetBSD: pthread_atfork.c,v 1.23 2025/03/01 20:31:58 christos Exp $"); +__RCSID("$NetBSD: pthread_atfork.c,v 1.24 2025/03/02 22:46:23 riastradh Exp $"); #endif /* LIBC_SCCS and not lint */ #include "namespace.h" +#include <sys/queue.h> + #include <errno.h> #include <stdlib.h> #include <unistd.h> -#include <sys/queue.h> + +#include "atfork.h" #include "extern.h" #include "reentrant.h" @@ -54,12 +57,6 @@ __locked_fork(int *my_errno) return __fork(); } -struct atfork_callback { - SIMPLEQ_ENTRY(atfork_callback) next; - void (*fn)(void); -}; - - /* * Keep a cache for of 3, one for prepare, one for parent, one for child. * This is so that we don't have to allocate memory for the call from the @@ -105,6 +102,53 @@ af_free(struct atfork_callback *af) free(af); } +static void +__libc_atfork_locked( + struct atfork_callback *restrict newprepare, void (*prepare)(void), + struct atfork_callback *restrict newparent, void (*parent)(void), + struct atfork_callback *restrict newchild, void (*child)(void)) +{ + + /* + * The order in which the functions are called is specified as + * LIFO for the prepare handler and FIFO for the others; insert + * at the head and tail as appropriate so that SIMPLEQ_FOREACH() + * produces the right order. + */ + if (prepare) { + newprepare->fn = prepare; + SIMPLEQ_INSERT_HEAD(&prepareq, newprepare, next); + } + if (parent) { + newparent->fn = parent; + SIMPLEQ_INSERT_TAIL(&parentq, newparent, next); + } + if (child) { + newchild->fn = child; + SIMPLEQ_INSERT_TAIL(&childq, newchild, next); + } +} + +void +__libc_atfork( + struct atfork_callback *restrict newprepare, void (*prepare)(void), + struct atfork_callback *restrict newparent, void (*parent)(void), + struct atfork_callback *restrict newchild, void (*child)(void)) +{ + sigset_t mask, omask; + + sigfillset(&mask); + thr_sigsetmask(SIG_SETMASK, &mask, &omask); + + mutex_lock(&atfork_lock); + __libc_atfork_locked(newprepare, prepare, + newparent, parent, + newchild, child); + mutex_unlock(&atfork_lock); + + thr_sigsetmask(SIG_SETMASK, &omask, NULL); +} + int pthread_atfork(void (*prepare)(void), void (*parent)(void), void (*child)(void)) @@ -125,7 +169,6 @@ pthread_atfork(void (*prepare)(void), vo error = ENOMEM; goto out; } - newprepare->fn = prepare; } if (parent != NULL) { @@ -136,7 +179,6 @@ pthread_atfork(void (*prepare)(void), vo error = ENOMEM; goto out; } - newparent->fn = parent; } if (child != NULL) { @@ -149,21 +191,11 @@ pthread_atfork(void (*prepare)(void), vo error = ENOMEM; goto out; } - newchild->fn = child; } - /* - * The order in which the functions are called is specified as - * LIFO for the prepare handler and FIFO for the others; insert - * at the head and tail as appropriate so that SIMPLEQ_FOREACH() - * produces the right order. - */ - if (prepare) - SIMPLEQ_INSERT_HEAD(&prepareq, newprepare, next); - if (parent) - SIMPLEQ_INSERT_TAIL(&parentq, newparent, next); - if (child) - SIMPLEQ_INSERT_TAIL(&childq, newchild, next); + __libc_atfork_locked(newprepare, prepare, + newparent, parent, + newchild, child); error = 0; out: mutex_unlock(&atfork_lock);