Predictable RNG: /dev/urandom+getrandom+kern.random return deterministic ChaCha20 keystream (zero key) before first reseed
| Field | Value |
|---|---|
| ID | DF-0220 |
| Status | new |
| Severity | High |
| CVSS 3.1 | CVSS:3.1/AV:L/AC:H/PR:L/UI:N/S:C/C:H/I:H/A:N |
| CWE | CWE-338 Use of Cryptographically Weak PRNG |
| File | sys/kern/subr_csprng.c |
| Lines | 84-166 |
| Area | kern |
| Confidence | certain |
| Discovered | 2026-06-30 |
| Reported | pending |
Summary
csprng_init() zeroizes both the key and cipher context (:84-85) but never
calls chacha_keysetup(). The only readiness gate (:146) blocks non-unlimited
readers when reseed_cnt == 0, but /dev/urandom, getrandom(2), and
kern.random all pass CSPRNG_UNLIMITED, bypassing it. Before the first
successful Fortuna reseed, all three interfaces emit ChaCha20 keystream from
the all-zero (key, counter) pair β a byte-for-byte reproducible sequence
identical on every booted machine. This makes all boot-time cryptographic
material (SSH keys, TCP ISNs, IP IDs, UUIDs, MAC addresses) predictable.
Root cause
Initialization (csprng_init, :80-90):
bzero(state->key, sizeof(state->key)); // :84 β all zeros
bzero(&state->cipher_ctx, sizeof(state->cipher_ctx)); // :85 β never keyed
state->reseed_cnt = 0; // :89
Readiness gate (csprng_get_random, :146):
if ((flags & CSPRNG_UNLIMITED) == 0 && state->reseed_cnt == 0) {
ssleep(state, &state->spin, 0, "csprngrsd", 0);
goto again;
}
Only blocks when CSPRNG_UNLIMITED is NOT set.
Output (:152):
chacha_encrypt_bytes(&state->cipher_ctx, NULL, out, cnt);
Runs on the still-all-zero cipher context.
Callers passing CSPRNG_UNLIMITED:
- /dev/urandom: sys/kern/kern_memio.c:352
- getrandom(2): sys/kern/kern_nrandom.c:770
- kern.random sysctl: sys/kern/kern_nrandom.c:739
- arc4random(): keys from read_random unlimited (sys/libkern/arc4random.c:60)
Reseed trigger (csprng_reseed, :188-191):
if (state->pool[0].bytes < MIN_POOL_SIZE) {
state->failed_reseeds++;
return;
}
Pool[0] needs β₯ 96 bytes of entropy AND ratecheck() must fire. Entropy is
scattered round-robin across 32 pools (:272-274), so pool[0] commonly
receives < 96 bytes during early boot.
Threat model & preconditions
- Attacker position: Local or partially remote (via early-boot network services). Anyone who can predict the boot window.
- Impact: ALL cryptographic material derived from the kernel RNG during the pre-reseed window is 100% predictable:
- SSH/SSL session keys (via arc4random)
- TCP initial sequence numbers (
sys/netinet/tcp_subr.c:1702,1705,1741) - IP IDs (
sys/netinet/ip_id.c:122) - UUIDs (
sys/kern/kern_uuid.c:89,126) - Generated NIC MAC addresses (
sys/dev/netif/re/re.c:3521) - Required config: Default kernel. Entropy-poor systems (embedded, virtio without virtio-rng, headless) may have an indefinite window.
Proof of concept
# On a freshly booted DragonFlyBSD: dd if=/dev/urandom bs=64 count=1 | xxd # Compare against ChaCha20(key=0^32, counter=0^16, 64 bytes) # β they match exactly when captured before first reseed. # Repeating on a second identical boot yields the identical bytes.
Recommended fix
Gate unlimited output on readiness, or key the cipher at init:
--- a/sys/kern/subr_csprng.c
+++ b/sys/kern/subr_csprng.c
@@ -144,6 +144,11 @@
again:
/*
* If no reseed has occurred yet, we can't possibly give out
* any random data.
+ * Even unlimited readers should block until the first reseed,
+ * because the cipher context is all-zero until keyed.
*/
- if ((flags & CSPRNG_UNLIMITED) == 0 && state->reseed_cnt == 0) {
+ if (state->reseed_cnt == 0) {
+ if (flags & CSPRNG_UNLIMITED) {
+ /* Non-blocking: return 0 or fall back */
+ return 0;
+ }
ssleep(state, &state->spin, 0, "csprngrsd", 0);
goto again;
}
Additionally: csprng_init should key the cipher with at least hashed boot
timestamp data rather than leaving it all-zero, so any leak through the gate
is not trivially reproducible.
References
- Fortuna algorithm: Ferguson, Schneier, "Practical Cryptography"
- Linux
getrandom(2): blocks untilCRNG_READY - FreeBSD
random(4):/dev/urandomblocks until seeded
Timeline
- 2026-06-30 Discovered during automated audit.
Discussion (0)
PoC verification
Evidence pack
findings/poc/DF-0220 Β· 15 files| File | Type | Description | Size | |
|---|---|---|---|---|
| rand_probe.c | trigger-source | reads 64B from /dev/urandom, /dev/random, getrandom(2), kern.random + uptime; prints hex | 2.6 KB | view raw |
| ref_keystream.c | reference | computes the degenerate all-zero pre-reseed csprng keystream (kernel's exact chacha on zeroed ctx) | 3.2 KB | view raw |
| build.sh | build-script | cc -O2 both programs | 283 B | view raw |
| run.sh | run-script | prints reference keystream + live RNG probe | 459 B | view raw |
| boot1_probe.txt | run-log | full probe output, fresh boot #1 (uptime 82.9s) | 1.5 KB | view raw |
| boot2_probe.txt | run-log | full probe output, fresh boot #2 (uptime 28.4s) | 1.6 KB | view raw |
| boot3_probe.txt | run-log | full probe output, fresh boot #3 (uptime 22.3s) | 1.6 KB | view raw |
| final_verify.txt | run-log | end-to-end re-verification sequence + result | 3.4 KB | view raw |
| leak_sample.txt | leak-sample | 3-boot cross-boot byte comparison: all pairwise differ 64/64, none match all-zero ref; root-cause trace | 11.3 KB | view raw |
| env.txt | environment | uname, cc version, dmesg RNG lines (no rdrand), sysctl rand_mode, sizeof(globaldata)=14976 | 2.6 KB | view raw |
| VERDICT.md | verdict | full narrative: gate-bypass is real code pattern, but window closed by rgd feed during rand_initialize (SYSINIT before init) | 8.5 KB | β raw |
| fix.diff | suggested-fix | defense-in-depth: gate unlimited readers too when reseed_cnt==0 (return 0, don't emit degenerate keystream); applies cleanly + compiles; supersedes finding proposal | 1.2 KB | view raw |
| README.md | readme | build/run/expected + cross-boot reproduce procedure | 3.7 KB | β raw |
| ../fix_build_combined.log | build-log | Combined 41-finding kernel build (rc=0, -Werror clean) | 5.6 MB | β download |
| ../fix_build_summary.txt | build-summary | Summary of the combined 41-finding kernel build | 826 B | view raw |
DF-0220 β PoC: Predictable RNG pre-reseed claim (verification)
Finding: findings/DF-0220-csprng-predictable-rng-pre-reseed.md
Claim: /dev/urandom, getrandom(2), and kern.random return a deterministic
all-zero-key ChaCha20 keystream before the first Fortuna reseed β identical
across independent boots.
Verdict (re-verified 2026-07-03): NOT REPRODUCED. See VERDICT.md for the
full root-cause trace.
Files
| File | Purpose |
|---|---|
rand_probe.c |
Reads 64 B from /dev/urandom, /dev/random, getrandom(2), kern.random; prints hex + uptime |
ref_keystream.c |
Computes the degenerate pre-reseed csprng keystream (all-zero chacha input[16]) for comparison |
build.sh |
Builds both programs |
run.sh |
Runs the probe (single boot) |
boot1_probe.txt |
Full probe output, boot #1 (fresh vm.sh reset with-src, uptime 82.9 s) |
boot2_probe.txt |
Full probe output, boot #2 (fresh vm.sh reset with-src, uptime 28.4 s) |
boot3_probe.txt |
Full probe output, boot #3 (fresh vm.sh reset with-src, uptime 22.3 s) |
leak_sample.txt |
Side-by-side cross-boot byte comparison + root-cause analysis |
final_verify.txt |
End-to-end re-verification sequence + result |
env.txt |
Guest uname, dmesg RNG lines, sysctl state, sizeof(globaldata) |
VERDICT.md |
Full narrative verdict |
fix.diff |
Defense-in-depth fix (gate-bypass is real, window is closed) |
manifest.json |
Machine-readable artifact catalog |
Build
./build.sh
(equivalent to cc -O2 -o rand_probe rand_probe.c && cc -O2 -o ref_keystream ref_keystream.c)
Run
./run.sh # single-boot probe; prints hex of 4 RNG sources + uptime ./ref_keystream 64 # prints the degenerate all-zero pre-reseed keystream
Expected (claim TRUE / bug present)
On two (or more) independent fresh boots, the 64-byte /dev/urandom (and
getrandom, kern.random) outputs would be byte-for-byte identical to each
other AND identical to ref_keystream's output (the degenerate pre-reseed
stream). With sysctl kern.rand_mode=csprng, /dev/urandom would return all
zero bytes.
Actual (on DragonFly master DEV 6.5-DEVELOPMENT #0)
On three independent fresh vm.sh reset with-src boots the outputs are
completely different (3 boots pairwise differ in 64/64 bytes for every
source) and never match the all-zero reference. With rand_mode=csprng,
/dev/urandom returns non-zero, varying bytes β proving the csprng cipher
context is already keyed (reseeded) before any userspace read. The claim
does not reproduce. See VERDICT.md and leak_sample.txt for the root
cause (the per-CPU globaldata entropy feed reseeds pool[0] during
rand_initialize, a kernel SYSINIT that runs before init(8)).
Reproduce across boots (the decisive test)
dfbsd-qemu/vm.sh reset with-src
# redeploy + build (disk is reverted by reset)
scp -F dfbsd-qemu/config rand_probe.c ref_keystream.c dfbsd-maxx:poc/DF-0220/
dfbsd-qemu/vm.sh run_user 'cd poc/DF-0220 && cc -O2 -o rand_probe rand_probe.c && ./rand_probe' > boot1.txt
dfbsd-qemu/vm.sh reset with-src
scp -F dfbsd-qemu/config rand_probe.c ref_keystream.c dfbsd-maxx:poc/DF-0220/
dfbsd-qemu/vm.sh run_user 'cd poc/DF-0220 && cc -O2 -o rand_probe rand_probe.c && ./rand_probe' > boot2.txt
# repeat for boot3, then diff /dev/urandom sections:
diff <(sed -n '/\/dev\/urandom/,/^$/p' boot1.txt) \
<(sed -n '/\/dev\/urandom/,/^$/p' boot2.txt) # differs => not reproducible
DF-0220 β VERDICT
Finding: Predictable RNG: /dev/urandom, getrandom(2), and kern.random
return a deterministic ChaCha20 keystream (zero key) before the first reseed,
identical across independent boots. (Severity High, Confidence "certain".)
Verdict: NOT REPRODUCED (the exploitable condition does not manifest on
DragonFly master DEV 6.5-DEVELOPMENT #0; the finding's premise about pool[0]
entropy is wrong β it omits the per-CPU globaldata feed that lands in pool[0]
during rand_initialize, before userspace).
Re-verified 2026-07-03 on the audit-source kernel 6.5-DEVELOPMENT #0:
Thu Jul 2 06:02:54 UTC 2026 (unpatched).
What is genuinely true in the claim (confirmed by source read)
-
The readiness gate is bypassed for unlimited readers.
sys/kern/subr_csprng.c:146:c if ((flags & CSPRNG_UNLIMITED) == 0 && state->reseed_cnt == 0) { ssleep(state, &state->spin, 0, "csprngrsd", 0); goto again; }Only NON-unlimited readers block whenreseed_cnt == 0./dev/urandom,getrandom(2),kern.random, and in-kernelarc4randomall reachcsprng_get_randomwithCSPRNG_UNLIMITED(sys/kern/kern_nrandom.c:702-703and:710-711, reached fromread_random(...,1)atkern_nrandom.c:739and:770, andsys/libkern/arc4random.c:60). So the gate genuinely does not protect them. -
The cipher context is never keyed at init.
csprng_init(subr_csprng.c:84-85) doesbzero(state->key, ...)andbzero(&state->cipher_ctx, ...)and never callschacha_keysetup. So IFchacha_encrypt_bytes(subr_csprng.c:155) ran whilereseed_cnt == 0, it would run on an all-zerochacha_ctx(all 16 input words zero, including the 4 sigma-constant words thatkeysetupnormally writes). -
The all-zero chacha state is a fixed point β the degenerate "keystream" is all zeros. The chacha quarterround uses only
PLUS,XOR,ROTATE. With every input word 0, every operation yields 0, so after 20 rounds and the final add all 16 output words are still 0.ref_keystream.creproduces the kernel's exact transform on the all-zero state and emits 64 bytes of 0x00. (The finding's description "ChaCha20(key=0^32, counter=0^16)" is therefore inaccurate: that variant still has the non-zero sigma constants atinput[0..3]and would be non-zero; the real degenerate output is all-zeros.)
So the code pattern the finding describes is real: an unlimited reader that
reached csprng_get_random while reseed_cnt == 0 would receive all-zero bytes
from the csprng (XORed with IBAA in default mixed mode).
Why it does NOT reproduce on this kernel
The finding's entire exploitability hinges on a window in which reseed_cnt == 0
and a reader obtains output. That window does not exist on master DEV,
because the cipher is keyed during rand_initialize() β a kernel SYSINIT that
runs before init(8), i.e. before any userspace read is possible.
SYSINIT ordering (sys/sys/kernel.h):
- rand_initialize is registered at SI_BOOT2_POST_SMP = 0x1cc0000,
SI_ORDER_SECOND (sys/kern/kern_nrandom.c:562).
- init(8) is launched at SI_SUB_KTHREAD_INIT = 0xe000000 (kernel.h:216),
~0xc340000 subsystem-ticks later. Userspace cannot read /dev/urandom until
then.
Trace of rand_initialize (sys/kern/kern_nrandom.c:485-560), per CPU:
1. csprng_init(state) (:507) β key=0, ctx=0, reseed_cnt=0.
2. Timing loop: 128 csprng feeds of 8 B each via RAND_SRC_TIMING (:517-531).
csprng_add_entropy routes by pool_id = src_pool_idx[src_id & 0xff]++ & 0x1f
(subr_csprng.c:272-273); src_pool_idx[0x02] cycles 0..31, so each pool
gets ~4 feeds. pool[0] receives ~32 B from timing. This is the only
entropy the finding considered, and on that basis alone its
"pool[0] < 96 bytes" claim would hold.
3. The feed the finding omits (kern_nrandom.c:539-543):
c
state->inject_counter[RAND_SRC_THREAD2] = 0;
add_buffer_randomness_state(state, (void *)rgd, sizeof(*rgd),
RAND_SRC_THREAD2);
RAND_SRC_THREAD2 = 0x0c (sys/sys/random.h:89). inject_counter[0x0c]
starts at 0, so ++ makes it 1 β ic & 1 branch in
add_buffer_randomness_state (kern_nrandom.c:614) calls
csprng_add_entropy(state, 0x0c & RAND_SRC_MASK, ...).
src_pool_idx[0x0c] starts at 0 β pool_id = 0. So sizeof(struct
globaldata) lands entirely in pool[0]. Verified via DWARF + gdb on
/boot/kernel/kernel.debug: sizeof(struct globaldata) = 14976 bytes
(gd_reserved02B[200] alone is 1600 B; plus gd_idlethread,
gd_slab/gd_kmslab, gd_systimerq, three gd_*clock systimers, etc.).
pool[0] therefore receives 32 (timing) + 14976 (rgd) β 15008 bytes β far
beyond MIN_POOL_SIZE = 96.
4. read_random(buf, sizeof(buf), 1) (kern_nrandom.c:558) β csprng_get_random
β ratecheck() fires on the first call (subr_csprng.c:134-135) β
csprng_reseed (subr_csprng.c:176). The guard
state->pool[0].bytes < MIN_POOL_SIZE (:188) passes β reseed_cnt
becomes 1 (:201), a fresh key is derived from the pools via SHA-256
(:228), and chacha_keysetup + chacha_ivsetup finally key the cipher
(:231,235).
From this point β still inside the kernel SYSINIT, before init(8) β every
subsequent read sees a properly-keyed csprng. There is no userspace-reachable
pre-reseed window. Even in-kernel arc4random's first stir happens after
this, so it keys from good data.
Empirical proof (3 independent fresh boots; full data in leak_sample.txt,
boot1_probe.txt, boot2_probe.txt, boot3_probe.txt)
Three independent vm.sh reset with-src boots, probe run as soon as ssh comes
up. (Disk is reverted on each reset, so each boot is independent.)
| Source | Boot #1 vs #2 | #1 vs #3 | #2 vs #3 | vs reference (all-zero) |
|---|---|---|---|---|
| /dev/urandom | 64/64 differ | 64/64 | 64/64 | 64/64 differ |
| getrandom(2) | 64/64 differ | 64/64 | 64/64 | 64/64 differ |
| kern.random | 64/64 differ | 64/64 | 64/64 | 64/64 differ |
Output is non-deterministic across boots and never matches the degenerate keystream.
Decisive secondary test β isolate the csprng with sysctl kern.rand_mode=csprng
(raw csprng, no IBAA mixing): three consecutive reads return non-zero, distinct
bytes. If reseed_cnt were still 0, csprng-only mode would emit the all-zero
fixed-point keystream. It does not β the cipher is keyed before userspace.
Classification
Case (a) false-premise / (d) not reachable on this kernel. The finding's
threat model assumes a userspace-observable pre-reseed window, but the per-CPU
globaldata entropy feed (kern_nrandom.c:539-543) closes that window during
rand_initialize (kernel SYSINIT SI_BOOT2_POST_SMP), before init. The
cross-boot determinism the finding predicts is empirically absent across 3
independent fresh boots.
The underlying gate-bypass + never-keyed-cipher pattern is a real
defense-in-depth gap (if pool[0] routing or the rgd feed ever changed, the
all-zero leak would resurface for unlimited readers), so fix.diff provides a
targeted hardening β gate unlimited readers too when reseed_cnt == 0 (return 0
bytes, do not emit the degenerate keystream) β but it is hardening, not a
fix for a reproduced vuln. Phase 8 single-fix-kernel build/boot is therefore
not applicable (the patched kernel would behave identically to the unpatched
one, since reseed_cnt is already > 0 before any userspace read; there is no
"before/after" bad-behavior contrast to demonstrate).
PoC changes
rand_probe.c (multi-source RNG reader + uptime) and ref_keystream.c
(degenerate-keystream reference that reproduces the kernel's exact chacha
transform on the all-zero state) were authored by the prior runner. This
re-verification made no source changes β both programs build and run unchanged.
The only file refreshed in this pass was fix.diff: the prior version had a
bogus index 0000000..1111111 git-header line that broke patch -p1 from
/usr/src; it has been regenerated with proper diff --git / --- / +++
headers (hunk content unchanged) and verified to apply cleanly
(patch -p1 --dry-run β rc=0, hunk #1 succeeded at line 138) and compile
(cc -fsyntax-only of the patched TU β rc=0). Evidence files refreshed:
boot1_probe.txt, boot2_probe.txt, boot3_probe.txt, leak_sample.txt,
env.txt, manifest.json, this VERDICT.md.
Confirmed kernel references
- sys/kern/subr_csprng.c:54
- sys/kern/subr_csprng.c:84
- sys/kern/subr_csprng.c:85
- sys/kern/subr_csprng.c:134
- sys/kern/subr_csprng.c:135
- sys/kern/subr_csprng.c:146
- sys/kern/subr_csprng.c:155
- sys/kern/subr_csprng.c:176
- sys/kern/subr_csprng.c:188
- sys/kern/subr_csprng.c:201
- sys/kern/subr_csprng.c:228
- sys/kern/subr_csprng.c:231
- sys/kern/subr_csprng.c:235
- sys/kern/subr_csprng.c:272
- sys/kern/subr_csprng.c:273
- sys/kern/kern_nrandom.c:485
- sys/kern/kern_nrandom.c:507
- sys/kern/kern_nrandom.c:517
- sys/kern/kern_nrandom.c:539
- sys/kern/kern_nrandom.c:543
- sys/kern/kern_nrandom.c:558
- sys/kern/kern_nrandom.c:562
- sys/kern/kern_nrandom.c:614
- sys/kern/kern_nrandom.c:702
- sys/kern/kern_nrandom.c:710
- sys/kern/kern_nrandom.c:739
- sys/kern/kern_nrandom.c:770
- sys/sys/random.h:79
- sys/sys/random.h:89
- sys/sys/random.h:93
- sys/sys/kernel.h:168
- sys/sys/kernel.h:216
- sys/sys/globaldata.h:129
- sys/libkern/arc4random.c:60
Detail
Exploit chain
none (non-corruption, non-reproduced class). No memory-corruption primitive; the threat-model impact (predictable boot-time crypto material) is empirically absent: 3 independent fresh boots produce non-deterministic RNG output, never matching the all-zero degenerate keystream, because the cipher is keyed during a kernel SYSINIT before init(8).
Evidence (decisive lines)
REFERENCE degenerate pre-reseed keystream (what a bug would emit): 64 bytes all 0x00. BOOT #1 /dev/urandom (uptime 82.9s): 51 6a e3 97 93 d1 1d 12 a2 54 86 b1 80 c5 96 de 4c 73 e3 25 e4 7d d9 98 67 bc 16 05 0f 93 3f e8 ... BOOT #2 /dev/urandom (uptime 28.4s): cc 5d 92 1b d8 d3 4f 06 8b e9 39 81 3d 10 7f 9b 6b b6 ce d8 6e e7 75 b8 63 ad 14 23 ce 16 43 cb ... BOOT #3 /dev/urandom (uptime 22.3s): ee b5 51 40 fb 2e ea 83 84 57 dd 9e 73 80 7c 48 be bc 5e c6 01 e4 fe 61 af 44 1d ab 49 3d dd 85 ... Cross-boot: 3 boots pairwise differ in 64/64 bytes; none match all-zero reference. rand_mode=csprng (raw csprng, no IBAA) 3 consecutive reads: 8c a6 62 2b... / 92 ff 5c d9... / 7e 77 de 53... (all non-zero, all distinct).
PoC changes
No source changes to rand_probe.c / ref_keystream.c / build.sh / run.sh. Refreshed evidence: boot1/boot2/boot3_probe.txt, leak_sample.txt (3-boot cross-comparison + root cause), env.txt (sizeof(globaldata)=14976 + SYSINIT ordering), VERDICT.md. Regenerated fix.diff with proper git headers (hunk content unchanged) -- verified patch -p1 --dry-run rc=0 and cc -fsyntax-only rc=0.
Verified recommended fix
Defense-in-depth hardening (NOT a fix for a reproduced vuln): in sys/kern/subr_csprng.c change the readiness gate at :146 from 'if ((flags & CSPRNG_UNLIMITED) == 0 && state->reseed_cnt == 0)' to 'if (state->reseed_cnt == 0)' and, for the CSPRNG_UNLIMITED case, return 0 instead of emitting the degenerate all-zero keystream from the un-keyed cipher context. Closes the latent gap if pool[0] routing or the per-CPU globaldata feed ever changes. Supersedes the finding markdown proposal (same intent, adds explicit return-0 path for non-blocking readers). Full git-apply-able diff in findings/poc/DF-0220/fix.diff.
Verdict
NOT REPRODUCED (false-premise / not-reachable-on-this-kernel). The code pattern the finding describes is real and confirmed by source read: csprng_init() bzero()s key AND cipher_ctx and never calls chacha_keysetup() (subr_csprng.c:84-85); the readiness gate at subr_csprng.c:146 only blocks NON-unlimited readers, so /dev/urandom, getrandom(2), kern.random, and in-kernel arc4random bypass it; and the all-zero chacha state is a fixed point so the degenerate pre-reseed keystream is all-zero bytes. HOWEVER the userspace-observable pre-reseed window does NOT exist on master DEV. rand_initialize() (kern_nrandom.c:485-560) is a SYSINIT at SI_BOOT2_POST_SMP that runs before init(8). At kern_nrandom.c:539-543 it feeds sizeof(struct globaldata)=14976 bytes into csprng pool[0] via RAND_SRC_THREAD2 (verified via DWARF/gdb) -- far beyond MIN_POOL_SIZE=96. The first read_random at kern_nrandom.c:558 triggers csprng_reseed, chacha_keysetup+chacha_ivsetup finally key the cipher. Empirically, 3 independent fresh boots give pairwise-distinct RNG output (64/64 bytes differ for /dev/urandom, getrandom(2), kern.random) and NEVER match the all-zero degenerate keystream; with kern.rand_mode=csprng three consecutive reads return non-zero distinct bytes, proving the cipher is keyed before userspace. The finding's premise that pool[0] commonly receives < 96 bytes during early boot omits the per-CPU globaldata feed entirely.
No comments yet.