β¬’ DragonFlyBSD Kernel Audit
← triage Β· dashboard
DF-2821

rand_thread_loop feeds generator output back into the entropy pools, so the MIN_POOL_SIZE reseed gate can be satisfied with zero external entropy

Field Value
ID DF-2821
Status new
Severity Low
CVSS 3.1 CVSS:3.1/AV:L/AC:H/PR:L/UI:N/S:U/C:N/I:N/A:L
CWE CWE-338 Use of Cryptographically Weak PRNG
File sys/kern/kern_nrandom.c
Lines 886-898 (gate subr_csprng.c:188)
Area kern
Confidence likely
Discovered 2026-08-31
Pass 2 (GLM 5.3 second pass)
Bucket base:kern
Reported pending
Known CVE none
CVE match novel

Summary

Every ~100-200ms the random helper thread adds the PREVIOUS iteration's read_random() output (32 bytes) into the same state's pools as RAND_SRC_THREAD1, plus per-cpu globaldata counters. csprng_reseed's only freshness gate is pool[0].bytes >= MIN_POOL_SIZE β€” a raw byte counter with no entropy estimate. Under total external-entropy starvation (quiet appliance/vkernel, no RDRAND/virtio-rng/keyboard) the self-feedback and predictable per-cpu counters keep the byte count above threshold forever, so reseeds keep deriving new keys purely from old generator state and boot-time timing; /dev/random's limited reads never stall and the CSPRNG presents a continuously-reseeded facade while its key evolution is a deterministic function of the initial weak seed. The entropy-starvation-masking complement to DF-0220 (pre-first-reseed window) and DF-0068 (IBAA gate) β€” a distinct post-reseed self-feed mechanism. On entropy-starved machines long-term keys (TCP ISN secrets, kern_uuid, sppp seeds) continue to be derived with no fresh unpredictability while operators believe the blocking gate guarantees entropy; the failure is silent and unbounded in time.

Never credit self-generated or low-assurance data toward the reseed gate: track an estimated-entropy counter per pool incremented only by external sources, gate reseeds on that counter, and feed generator chaining through a separate non-credited channel (add_buffer_randomness_state_nocredit) β€” sketch diff in the row above.

Timeline

  • 2026-08-31 Discovered during pass-2 audit of kern_nrandom.c (GLM 5.3).

Discussion (0)

No comments yet.

PoC verification

Evidence pack

findings/poc/DF-2821 Β· 1 files
FileTypeDescriptionSize
fix.diff β€” 795 B view raw

Fix verification

not_testable
baseline no→ patch + rebuild →patched clean

Self-feedback removal compile-validated; starvation precondition not producible for A/B.

compile-validated in the fix-all kernel build (make nativekernel, 0 errors)
↓ fix.diffper-fix-DF-2821

Confirmed kernel references

Detail

Evidence (decisive lines)

kern_nrandom.c:886-898: add_buffer_randomness_state(buf=read_random output) + :898 read_random refresh

PoC changes

n/a

Verified recommended fix

--- sys/kern/kern_nrandom.c 2026-06-29 12:51:19.000000000 +0000

Verdict

Code-verified entropy-accounting flaw; not observable on a live guest. rand_thread_loop (sys/kern/kern_nrandom.c:886-898) feeds the PREVIOUS iterations read_random() output (buf) into the same pools as RAND_SRC_THREAD1, plus per-cpu counters, while csprng_reseeds only freshness gate is pool[0].bytes >= MIN_POOL_SIZE - a raw byte counter with no entropy estimate. Under total external-entropy starvation the self-feedback keeps the counter above threshold forever, so reseeds derive keys purely from old state and boot timing while /dev/random never stalls. On this guest interrupts, the systimer, RDRAND and the storage layer all inject entropy, so the starvation precondition cannot be produced (and the internal pool counters are not exported via sysctl to measure the split between credited external entropy and self-feedback). The fix (stop crediting generator output as pool input) is compile-validated; a complete fix needs per-pool estimated-entropy accounting.