โฌข DragonFlyBSD Kernel Audit
DF-2664 / verdict.json
โ† back to finding โ†“ download raw
{
  "finding_id": "DF-2664",
  "status": "reproduced",
  "reproduced": 1,
  "impact": "none",
  "confidence": "certain",
  "verdict": "LZ4_decompress_safe() (sys/vfs/hammer2/hammer2_lz4.c:418, vendored upstream LZ4 r97) dereferences source[0] when inputSize==0 โ€” the pre-loop validation only rejects outputSize==0 (hammer2_lz4.c:407) โ€” a 1-byte OOB read past the declared input buffer that violates the documented 'never reads outside of input buffer' contract (hammer2_lz4.h:62-65). Unit-proven on the guest: SIGSEGV exactly at src with a guard page (run.log). In-kernel reachable from on-media compressed_size==0, which passes the strategy.c:199 KKASSERT even on INVARIANTS kernels (run_kernel.log: no panic, one 'READ PATH: Error during decompression', file reads as zeros). Impact fully contained by the caller: the speculative byte sits inside the dio allocation for every realistic layout, the decode always errors, and the output is zeroed โ€” no leak, no corruption. Negative proof: 2,000,000 guard-paged adversarial fuzz iterations with honest (inputSize,outputSize) โ€” 0 faults, 0 output-canary corruptions โ€” the r97 decoder is otherwise memory-safe on LP64; DF-0805's heap OOB is purely the caller's unchecked compressed_size. Guard (upstream r96 / v1.9.4 semantics) restored in fix.diff and validated at unit level: clean -1, no fault, fuzz still green.",
  "exploit_chain": "",
  "evidence": [
    "run.log / run.2.log โ€” Test A: SIGSEGV at src (delta=0) inside LZ4_decompress_safe with inputSize==0; Test A2 control (inputSize=1 token=0x00 โ†’ 0); Tests B+C: 2,000,000 iterations, 0 faults, 0 canary corruptions",
    "run_kernel.log โ€” on-media compressed_size=0 reaches LZ4_decompress_safe(inputSize=0) on stock INVARIANTS kernel: no panic, dmesg 'READ PATH: Error during decompression', unprivileged read returns zeros, guest healthy",
    "fix_run.log โ€” fixed build (r96/v1.9.4 guard): returns -1 cleanly, no fault, control + 2M fuzz green ('FIX VALIDATED')",
    "fix.diff โ€” one-line guard vs sys/vfs/hammer2/hammer2_lz4.c, git apply --check clean"
  ],
  "kernel_refs": [
    "sys/vfs/hammer2/hammer2_lz4.c:418",
    "sys/vfs/hammer2/hammer2_lz4.c:407",
    "sys/vfs/hammer2/hammer2_lz4.h:62-65",
    "sys/vfs/hammer2/hammer2_strategy.c:198-205",
    "sys/vfs/hammer2/hammer2_strategy.c:206-216"
  ],
  "poc_changes": "Harness written fresh (verbatim decoder excerpt pattern reused from DF-0805's pack): guard-page token-fetch proof for inputSize==0, canonical 1-byte null-stream control, 2M-iteration guard-paged fuzz (random + all-0xFF/0x00 + structured tokens with offsets 0/1/2/7/8/0xFFFF + valid-shaped streams with flip/truncate mutations) with output canaries, plus in-kernel trigger adapted from DF-0805's hammer2_trigger.sh with compressed_size=0x00000000 instead of 0x7FFFFFFF.",
  "attempts": 3,
  "guest_uname": "DragonFly dfbsd 6.5-DEVELOPMENT DragonFly 6.5-DEVELOPMENT #0: Thu Jul  2 06:02:54 UTC 2026     root@dfbsd:/usr/obj/usr/src/sys/X86_64_GENERIC  x86_64",
  "runtime_sec": 240,
  "guest_dirty": 0,
  "build_cmd": "cc -O2 -Wall -Wextra -o lz4_zero_input_harness lz4_zero_input_harness.c",
  "run_cmd": "./lz4_zero_input_harness 1000000   (as maxx; kernel stage: sh hammer2_trigger.sh as root, read as maxx)",
  "code_hash": "7b935bbf7b3c66f8ce9595df3a317fe6878aaf7747f4e3ca8026f452b5fb745d",
  "notes": "Upstream provenance pinned by diffing the in-tree function against historical upstream: verbatim LZ4 r97 (svn trunk@97, 2013-06-10). The inputSize==0 guard existed in r96, was dropped by the r97 de-genericization, and is present again in v1.9.4 (lib/lz4.c:1983) โ€” the vendored copy sits exactly in the unguarded window. CVE-2014-4610 (LZ4 < r118) is 32-bit-only and structurally unreachable here (sys/platform = pc64, vkernel64 only). Fix validation was performed at unit level deliberately: in-kernel baseline vs fixed behavior is observationally identical (silent 1-byte speculative read; both produce dmesg error + zeroed output), so a kernel rebuild cannot distinguish them โ€” the unit harness is the only level with an observable delta.",
  "recommended_fix": "Restore the upstream r96/v1.9.4 guard: reject inputSize==0 before the main loop ('if ((endOnInput) && unlikely(inputSize==0)) goto _output_error;' after the outputSize==0 check).",
  "fix_status": "fixed",
  "fix_kernel_uname": "",
  "fix_baseline_reproduced": 1,
  "fix_patched_reproduced": 0,
  "fix_verdict": "Unit-level validation (verbatim decoder copy): baseline faults at src with inputSize==0; patched build returns -1 with no fault and stays green across the full 2M-iteration fuzz and the null-stream control (fix_run.log). Kernel-level rebuild validation intentionally not performed: the in-kernel bad behavior has no observable runtime delta vs fixed (both yield the dmesg error and zeroed output), so only the unit level can demonstrate the fix; fix.diff is git-apply clean against sys/vfs/hammer2/hammer2_lz4.c.",
  "fix_evidence": [
    "fix_run.log โ€” 'FIX VALIDATED - inputSize==0 cleanly rejected, no OOB read', control + 2M fuzz green",
    "fix.diff โ€” git apply --check clean vs sys/vfs/hammer2/hammer2_lz4.c",
    "upstream corroboration: r96 lz4_decoder.h guard; v1.9.4 lib/lz4.c:1983 'if (unlikely(srcSize==0)) { return -1; }'"
  ]
}