public inbox for git-commits@fedoraproject.org
help / color / mirror / Atom feed
From: Rostislav Krasny <rostiprodev@gmail.com>
To: git-commits@fedoraproject.org
Subject: [rpms/nss] f44: Reseed the freebl DRBG after fork()
Date: Wed, 29 Jul 2026 17:38:25 GMT	[thread overview]
Message-ID: <178534670590.1.6493704659492667690.rpms-nss-6cd71667a287@fedoraproject.org> (raw)

            A new commit has been pushed.

            Repo   : rpms/nss
            Branch : f44
            Commit : 6cd71667a2874a228c43f526378cbb82cc9831aa
            Author : Rostislav Krasny <rostiprodev@gmail.com>
            Date   : 2026-07-25T01:57:59+03:00
            Stats  : +96/-1 in 2 file(s)
            URL    : https://src.fedoraproject.org/rpms/nss/c/6cd71667a2874a228c43f526378cbb82cc9831aa?branch=f44

            Log:
            Reseed the freebl DRBG after fork()

fork() gives the child a verbatim copy of theGlobalRng together with the
PR_CallOnce flags that mark it instantiated, so RNG_RNGInit() in the child
is a no-op and the child replays the parent's output stream. Register a
pthread_atfork child handler that discards the inherited state, forcing a
clean reinstantiate from system entropy at the next RNG use.

Also add the NULL check RNG_RandomUpdate() was missing. Its sibling
prng_GenerateGlobalRandomBytes() already has one, and without it the
PR_Lock() below dereferences NULL.

Reported against Firefox's Linux fork server, where content processes
forked from a common ancestor generated identical UUIDs (mozbz#2056509),
but the defect affects any NSS consumer that forks without exec.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

---
diff --git a/nss-3.125-drbg-reseed-after-fork.patch b/nss-3.125-drbg-reseed-after-fork.patch
new file mode 100644
index 0000000..ef3d034
--- /dev/null
+++ b/nss-3.125-drbg-reseed-after-fork.patch
@@ -0,0 +1,87 @@
+--- a/lib/freebl/drbg.c	2026-07-25 00:09:40.452942615 +0300
++++ b/lib/freebl/drbg.c	2026-07-25 01:11:29.163041842 +0300
+@@ -20,6 +20,10 @@
+ #include "secrng.h" /* for RNG_SystemRNG() */
+ #include "secmpi.h"
+ 
++#ifdef XP_UNIX
++#include <pthread.h>
++#endif
++
+ /* PRNG_SEEDLEN defined in NIST SP 800-90 section 10.1
+  * for SHA-1, SHA-224, and SHA-256 it's 440 bits.
+  * for SHA-384 and SHA-512 it's 888 bits */
+@@ -471,6 +475,45 @@
+  */
+ static const PRCallOnceType pristineCallOnce;
+ static PRCallOnceType coRNGInit;
++
++#ifdef XP_UNIX
++static PRCallOnceType coRNGInitAtFork;
++
++/* fork() gives the child a verbatim copy of the DRBG state, including the
++ * PR_CallOnce flags marking it instantiated, so without this the child
++ * replays the parent's output stream.
++ *
++ * Keep async-signal-safe -- no allocation, locks or I/O -- for callers that
++ * fork from a multithreaded process; the reinstantiate is deferred to the
++ * next RNG use.  Only fork mechanisms that run atfork handlers are covered.
++ * Never run this after vfork(2): that child shares the parent's address
++ * space, so the zeroing below would destroy the live context. */
++static void
++rng_atfork_child(void)
++{
++    /* Zero the storage, not *globalrng: after RNG_RNGShutdown() the pointer
++     * is NULL while the context still holds C and V that prng_freeRNGContext
++     * deliberately preserved.  Discarding them forces a clean reinstantiate
++     * rather than a reseed over inherited state, and clears the stale lock
++     * pointer so rng_init() builds a fresh one.  The inherited PRLock is
++     * leaked on purpose: a thread that did not survive the fork may have held
++     * it, so destroying it would be undefined. */
++    PORT_SafeZero(&theGlobalRng, sizeof(theGlobalRng));
++    globalrng = NULL;
++    /* Reset both: the first otherwise suppresses rng_init() entirely, the
++     * second leaves previousEntropyHash zeroed while claiming it was primed. */
++    coRNGInit = pristineCallOnce;
++    coRNGInitEntropy = pristineCallOnce;
++}
++
++static PRStatus
++rng_registerAtFork(void)
++{
++    pthread_atfork(NULL, NULL, rng_atfork_child);
++    return PR_SUCCESS;
++}
++#endif
++
+ static PRStatus
+ rng_init(void)
+ {
+@@ -478,6 +521,12 @@
+     SECStatus rv = SECSuccess;
+ 
+     if (globalrng == NULL) {
++#ifdef XP_UNIX
++        /* Once per process: the registration survives fork() and
++         * coRNGInitAtFork is never reset, so repeated forks cannot stack
++         * duplicate handlers. */
++        PR_CallOnce(&coRNGInitAtFork, rng_registerAtFork);
++#endif
+         /* bytes needs to have enough space to hold
+          * a SHA256 hash value. Blow up at compile time if this isn't true */
+         PR_STATIC_ASSERT(sizeof(bytes) >= SHA256_LENGTH);
+@@ -617,6 +666,14 @@
+     PR_STATIC_ASSERT(sizeof(size_t) <= 4);
+ #endif
+ 
++    /* Absent before the first RNG_RNGInit(), and in a child until the
++     * inherited state is rebuilt.  prng_GenerateGlobalRandomBytes() makes the
++     * same check; without it the PR_Lock() below dereferences NULL. */
++    if (globalrng == NULL) {
++        PORT_SetError(SEC_ERROR_INVALID_ARGS);
++        return SECFailure;
++    }
++
+     PR_Lock(globalrng->lock);
+     /* if we're passed more than our additionalDataCache, simply
+      * call reseed with that data */

diff --git a/nss.spec b/nss.spec
index 2357903..c97804f 100644
--- a/nss.spec
+++ b/nss.spec
@@ -3,7 +3,7 @@
 # NOTE: To avoid NVR clashes of nspr* packages:
 # - reset %%{nspr_release} to 1, when updating %%{nspr_version}
 # - increment %%{nspr_version}, when updating the NSS part only
-%global baserelease 1
+%global baserelease 2
 %global nss_release %baserelease
 # use "%%global nspr_release %%[%%baserelease+n]" to handle offsets when
 # release number between nss and nspr are different.
@@ -145,6 +145,10 @@ Patch66:          nss-3.118-ml-dsa-tls-test.patch
 Patch67:          nss-3.118-ml-dsa-unittests.patch
 Patch68:          nss-3.123-fix-mldsa-import-regeneration.patch
 
+# Reseed the freebl DRBG in the child after fork(), so forked children do not
+# replay the parent's random stream (mozbz#2056509)
+Patch70:          nss-3.125-drbg-reseed-after-fork.patch
+
 Patch100:         nspr-config-pc.patch
 Patch101:         nspr-gcc-atomics.patch
 
@@ -1093,6 +1097,10 @@ fi
 
 
 %changelog
+* Sat Jul 25 2026 Rostislav Krasny <rostiprodev@gmail.com> - 3.125.0-2
+- Reseed the freebl DRBG after fork() so forked children do not replay the
+  parent's random stream (Firefox fork server duplicate UUIDs / crypto output)
+
 * Thu Jun 18 2026 Frantisek Krenzelok <fkrenzel@redhat.com> - 3.125.0-1
 - Update NSS to 3.125.0
 - Fix NSPR versioning scheme

                 reply	other threads:[~2026-07-29 17:38 UTC|newest]

Thread overview: [no followups] expand[flat|nested]  mbox.gz  Atom feed

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=178534670590.1.6493704659492667690.rpms-nss-6cd71667a287@fedoraproject.org \
    --to=rostiprodev@gmail.com \
    --cc=git-commits@fedoraproject.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox