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);