SipHash24_TestVectors passes len=0 to SipHash_Update for the empty-message vector, panicking INVARIANTS kernels
Summary
The test module's vector loop starts at i=0 (empty message) and calls SipHash_Update(&ctx, in, 0). SipHash_Update forwards to SipBuf, whose contract KASSERT '(!final && len > 0) || (final && len == 0)' rejects zero-length non-final updates - on any INVARIANTS kernel this is an immediate panic at test start. REPRODUCED live: kld module built from the unmodified source panics the stock INVARIANTS guest ('panic: SipBuf: invalid parameters', backtrace SipHash24_TestVectors -> SipHash_Update -> SipBuf). Fix validated: one-line guard -> module loads, prints result=1 (all 64 vectors pass), unloads cleanly. Reachability today nil (module in no build target, nothing in-tree calls it); impact ceiling: a developer wiring the test into a debug kernel gets a deterministic panic. Vector table integrity CONFIRMED: all 64 entries match the official SipHash-2-4 reference set (proven twice - userland + in-kernel).
Discussion (0)
PoC verification
Evidence pack
findings/poc/DF-3566 Β· 18 files| File | Type | Description | Size | |
|---|---|---|---|---|
| README.md | β | 2.8 KB | β raw | |
| VERDICT.md | β | 3.1 KB | β raw | |
| panic.txt | β | 793 B | view raw | |
| trigger.c | β | 637 B | view raw | |
| siphash_test.c | β | 4.9 KB | view raw | |
| siphash_test_fixed.c | β | 5.0 KB | view raw | |
| Makefile | β | 103 B | β download | |
| siphash_kat.c | β | 436 B | view raw | |
| build.log | β | 549 B | view raw | |
| kldload_baseline.log | β | 830 B | view raw | |
| kldload_fixed.log | β | 449 B | view raw | |
| run.userland.log | β | 273 B | view raw | |
| run.userland.warn.log | β | 217 B | view raw | |
| fix.diff | β | 331 B | view raw | |
| env.txt | β | 228 B | view raw | |
| code_hashes.txt | β | 157 B | view raw | |
| manifest.json | β | 1.1 KB | view raw | |
| verdict.json | β | 3.1 KB | view raw |
DF-3566 β SipHash24_TestVectors trips SipHash KASSERT β INVARIANTS-kernel panic
What
sys/crypto/siphash/siphash_test.c runs its 64-vector table starting at the
empty-message vector (i=0). For i=0 it calls SipHash_Update(&ctx, in, 0).
sys/crypto/siphash/siphash.c asserts (!final && len > 0) || (final && len == 0)
in SipBuf() (siphash.c:92) β a zero-length non-final update is a contract
violation and panics any kernel built with INVARIANTS.
Reachability today: none through any shipped build β siphash_test.c is in
no build target (not in sys/conf/files, not in sys/crypto/Makefile); nothing
in-tree references SipHash24_TestVectors() except its own header declaration.
It is developer/test-harness code: anyone who wires it into an INVARIANTS
kernel (its documented purpose) gets an immediate panic at module init/test
start. Severity Low: local DoS, developer-facing, dead code by default.
Build (module, in-guest)
# /tmp/sipmod/Makefile:
KMOD= siphashtest
SRCS= trigger.c siphash_test.c
SYSDIR=/usr/src/sys
.include "${SYSDIR}/conf/kmod.mk"
cd /tmp/sipmod && make
trigger.c is a 25-line DEV/DECLARE_MODULE shim whose MOD_LOAD handler calls
SipHash24_TestVectors(). siphash_test.c is the unmodified kernel source
(md5 3b580668a665816235b2c715bb293734, identical to the audited tree).
Run (baseline β expect panic)
kldload /tmp/sipmod/siphashtest.ko
Expected: panic: SipBuf: invalid parameters, DDB prompt db>, ssh dead.
Observed: exactly that β see panic.txt for the full serial-console trace
(SipHash24_TestVectors β SipHash_Update β SipBuf β panic).
Run (patched β expect all vectors pass, no panic)
Same module with siphash_test_fixed.c (if (i > 0) guard around the Update):
kldload /tmp/sipmod_fixed/siphashtest_fixed.ko
Observed: siphashtest: calling SipHash24_TestVectors() /
siphashtest: result=1 (no panic) in dmesg, clean kldunload, guest healthy
(kldload_fixed.log). result=1 means all 64 vectors match in-kernel.
Userland cross-check
siphash_kat.c compiles the unmodified siphash.c + siphash_test.c as
userland objects (shim for sys/systm.h/sys/libkern.h only):
- abort-style KASSERT shim β
KASSERT FAILED: (!final && len > 0) ..., SIGABRT (run.userland.log) β same trip, no kernel needed. - warn-style shim β
KASSERT-WARNonce, thenSIPHASH24_TESTVECTORS=1 (ALL 64 VECTORS MATCH)(run.userland.warn.log): with the assertion bypassed the empty-message vector computes correctly (SipBuf is a functional no-op for len==0), so the vector table itself is sound and the one-line guard is the complete fix.
Environment
DragonFly dfbsd 6.5-DEVELOPMENT #0 (X86_64_GENERIC, INVARIANTS) β see
env.txt. Guest restored with vm.sh reset with-src after the panic runs.
DF-3566 VERDICT β SipHash24_TestVectors empty-vector KASSERT panic
Outcome: REPRODUCED (in-kernel panic, INVARIANTS build), fix validated.
Root cause (source-traced): sys/crypto/siphash/siphash_test.c:116 loops i = 0..63 and, at i = 0 (the empty-message reference vector), calls SipHash_Update(&ctx, in, 0) [siphash_test.c:121] SipHash_Update forwards to SipBuf(ctx, &s, 0, 0), whose contract assertion KASSERT((!final && len > 0) || (final && len == 0), ("%s: invalid parameters", func)); [siphash.c:92-93] rejects zero-length non-final updates. SipBuf is otherwise a functional no-op for len==0 (x = MIN(0, 8-0) = 0, no compression, siphash.c:95-109), so with the assert bypassed the empty vector hashes correctly β the table itself is sound and the guard is the complete fix.
Reproduction (stock INVARIANTS guest, uname in env.txt): 1. Built siphashtest.ko from the UNMODIFIED kernel source siphash_test.c plus a 25-line module shim (trigger.c) calling SipHash24_TestVectors() at MOD_LOAD (build.log). 2. kldload siphashtest.ko -> panic: SipBuf: invalid parameters SipBuf <- SipBuf <- SipHash_Update <- SipHash24_TestVectors <- siphashtest_modevent <- module_register_init (panic.txt) Guest dropped to DDB; ssh dead; vm.sh status => down. 3. Userland same-source build confirms the identical trip without any kernel involvement: abort-shim => "KASSERT FAILED: (!final && len > 0) || (final && len == 0)", SIGABRT rc=134 (run.userland.log).
Fix validation: Applied the one-line guard (fix.diff) to siphash_test_fixed.c, rebuilt the module, kldload on the same stock INVARIANTS guest: siphashtest: calling SipHash24_TestVectors() siphashtest: result=1 (no panic) (kldload_fixed.log) result=1 == all 64 vectors match IN-KERNEL; clean kldunload; guest healthy.
Reachability / impact ceiling: siphash_test.c is compiled into NOTHING today: absent from sys/conf/files and from sys/crypto/Makefile (the crypto KMOD builds only siphash.c). No in-tree caller of SipHash24_TestVectors(). An unprivileged user cannot reach this code on any shipped kernel; the trigger is a developer building the test into an INVARIANTS kernel (its documented purpose). Impact = local debug-kernel DoS (panic at test start). Hence severity Low, bucket base:*.
Negative results worth recording: - Vector-table integrity: all 64 entries match the official SipHash-2-4 reference set β proven twice: userland (warn-shim run) and in-kernel (patched module result=1). - The KASSERT trip is the ONLY defect found in the file; loop bounds (in[64], vectors[64][8], k[16]) are exact; no uninitialized use other than the i=0 semantic; kprintf-only side effects.
Fix status (batch validation)
Applied with the 36 sibling fix.diffs of this batch in findings/poc/_batch41/all_fixes.patch; single in-guest make -j6 nativekernel KERNCONF=X86_64_GENERIC completed RC=0 with zero errors under -Werror (full log: findings/poc/_batch41/fix_build8.log). Behavior A/B intentionally skipped for this Info-tier item.
Fix verification
fixedfix.diff applied to siphash_test_fixed.c, module rebuilt and kldloaded on the same stock INVARIANTS guest: no panic, 'siphashtest: result=1 (no panic)' in dmesg, clean kldunload, guest stayed healthy (kldload_fixed.log). Baseline (unpatched) panicked to DDB on the same guest (panic.txt). fix_patched_reproduced=0 because the patched run by definition produces NO panic β the expected bad behavior is gone.
kldload_fixed.log + panic.txt (baseline vs patched on identical guest/kernel)
Confirmed kernel references
- sys/crypto/siphash/siphash_test.c:121
- sys/crypto/siphash/siphash.c:92
- sys/crypto/siphash/siphash.c:95
- sys/conf/files:2276
- sys/crypto/Makefile:46
Detail
Evidence (decisive lines)
panic.txt (serial-console panic trace after kldload); kldload_fixed.log (patched module: result=1, no panic, clean unload); run.userland.log (same-source userland build: KASSERT FAILED + SIGABRT at vector 0); VERDICT.md for the source trace
PoC changes
trigger.c is a new 25-line module shim (DECLARE_MODULE + MOD_LOAD handler calling SipHash24_TestVectors and kprintf'ing the result); siphash_test.c itself is the unmodified kernel source (md5 3b580668a665816235b2c715bb293734). No changes to the audited source were needed to reproduce.
Verified recommended fix
Guard the zero-length update: 'if (i > 0) SipHash_Update(&ctx, in, i);' in siphash_test.c
Verdict
SipHash24_TestVectors calls SipHash_Update(ctx, in, 0) for the empty-message vector, violating SipBuf's zero-length contract and panicking any INVARIANTS kernel. Reproduced live on the stock INVARIANTS guest via a kld module built from the unmodified source: 'panic: SipBuf: invalid parameters' with the full backtrace (SipHash24_TestVectors -> SipHash_Update -> SipBuf). The one-line guard (fix.diff) was validated in-kernel: patched module prints result=1 (all 64 vectors pass) and unloads cleanly. Reachability is nil in shipped builds (file is in no build target), so severity is Low; impact ceiling is a developer-configured debug-kernel panic.
No comments yet.