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

Reply via email to