Silent 64-bit->32-bit length truncation when invoking chacha_encrypt_bytes
Summary
_chacha20poly1305_update and _chacha20poly1305_final typed with size_t in_len but pass directly to chacha_encrypt_bytes(...uint32_t bytes). Implicit narrowing silently truncates lengths>=2^32 while poly1305_update (size_t bytes) does NOT truncate producing internal inconsistency where MAC covers more data than encrypted. For in_len>=2^32 keystream generated for only low 32 bits while MAC computed over full length breaking AEAD invariant. All current callers bounded well under 2^32 (WireGuard fixed sizes mbuf pkthdr.len int32). Latent API misuse risk for future >4GiB caller. [VERIFIED pass2: reproduced - in_len 2^32 passes 0 to chacha and 4294967296 to poly1305 splitting keystream and MAC with no error; KAT control bit-identical to real KPI; KKASSERT guard fix-validated]
Discussion (0)
PoC verification
Evidence pack
findings/poc/DF-2364 Β· 8 files| File | Type | Description | Size | |
|---|---|---|---|---|
| env.txt | β | 412 B | view raw | |
| fix.diff | β | 1.3 KB | view raw | |
| panic_fix.txt | β | 553 B | view raw | |
| rig | β | 4.0 KB | β download | |
| run_fixed_kernel.log | β | 2.8 KB | view raw | |
| run_kernel_baseline.log | β | 172 B | view raw | |
| verdict.json | β | 2.1 KB | view raw | |
| fix.diff | β | 1.3 KB | view raw |
Fix verification
not_testableConfirmed kernel references
Detail
Evidence (decisive lines)
run_fixed_kernel.log + session baseline (TRUNCATION: chacha saw 0, poly saw 4294967296; KAT MATCH), panic_fix.txt (post-fix assertion), fix.diff
PoC changes
the recorder forwards to the real primitives below a threshold and only records above it (no 4GiB poly pass); initial RFC vector reference was wrong for the 32-byte payload - replaced by twin comparison against the real kernel KPI
Verified recommended fix
KKASSERT in_len <= 0xffffffffU in _chacha20poly1305_update (recommend a runtime clamp upstream)
Verdict
_chacha20poly1305_update with in_len = 2^32 (a legal complete-block multiple for the size_t API) splits silently: the recording interposition on the verbatim TU shows chacha_encrypt_bytes receiving bytes=0 (uint32_t truncation) while poly1305_update receives 4294967296 (size_t, full) - keystream covers the low 32 bits, MAC covers everything, the AEAD invariant breaks with no error. The KAT control (small lengths, recorders forwarding to the real primitives) matches the real kernel KPI output bit-for-bit, proving the rig drives production code. With the KKASSERT guard the same call is rejected loudly on INVARIANTS kernels (assertion text captured). Latent: every in-tree caller is bounded far below 2^32 (mbuf pkthdr.len is int32).
No comments yet.