⬢ DragonFlyBSD Kernel Audit
DF-5679 / verdict.json
← back to finding ↓ download raw
{
  "finding_id": "DF-5679",
  "status": "reproduced",
  "reproduced": true,
  "impact": "none",
  "confidence": "certain",
  "verdict": "iscsi_crc32()/iscsi_crc32_ext() accept size_t size but calculate_crc32c() narrows it to unsigned int (sys/libkern/icrc32.c:763, called at :779/:785), so a 0x100000009-byte request is silently serviced as 9 bytes: demonstrated on the guest (T10 and fixdemo_baseline: identical CRCs 4520c30c, silent return). This is an under-read (unchecked tail), not an overflow. Bounds audit of every in-tree caller (kern_dmsg DMSG_AUX_MAX clamp at kern_dmsg.c:371-376, swap_pager MAXPHYS, hammer2 64KB radix cap, ext2fs block sizes, sizeof-based hashes) shows no caller can reach 2^32, so impact is a correctness-contract / defense-in-depth hazard only. The rest of the file is proven bit-exact and memory-safe by the same rig: 21/21 differential checks (all 9 tables element-wise vs generated references, KATs 0xCBF43926/0xE3069283, every length 0..600 x alignment 0..3 for both engines, chaining semantics incl. by-1/by-3 chunk churn, 1MiB random, PROT_NONE guard-page OOB probe with zero faults across 256 boundary lengths).",
  "exploit_chain": "",
  "evidence": "run.log: T10 truncation: iscsi_crc32(buf, 0x100000009)=4520c30c iscsi_crc32(buf, 9)=4520c30c TRUNCATED (equal) and RESULT: ALL-PASS (21 checks, 0 failures); fix_run.log: baseline FIX-BAD ... truncation still present (exit 1) vs patched FIX-OK: length honored -> child faulted on guard page (sig 11) (exit 0); VERDICT.md for the full class-by-class kill list with path:line.",
  "kernel_refs": [
    "sys/libkern/icrc32.c:760",
    "sys/libkern/icrc32.c:763",
    "sys/libkern/icrc32.c:765",
    "sys/libkern/icrc32.c:776",
    "sys/libkern/icrc32.c:779",
    "sys/libkern/icrc32.c:783",
    "sys/libkern/icrc32.c:785",
    "sys/sys/systm.h:205",
    "sys/kern/kern_dmsg.c:371",
    "sys/vfs/hammer2/hammer2.h:1457"
  ],
  "poc_changes": "No seed existed (orchestrator reserved IDs only); rig authored from scratch. Three iterations: (1) fix.diff was missing the #ifndef _KERNEL prototype hunk at icrc32.c:15-16 (patched-copy build failed with conflicting types) and one harness CHECK had a ^/== precedence bug caught by -Wparentheses; (2) first runs single T7 failure was my harness double-processing the final 3-byte chunk (228=76*3 leaves no remainder) - kernel exonerated; (3) clean ALL-PASS run + fix validation.",
  "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": 1,
  "guest_dirty": 0,
  "build_cmd": "sh build.sh  (guest, in pack dir: copies /usr/src/sys/libkern/{icrc32,crc32}.c, cc -O2 -Wall -o icrc32_diff icrc32_diff.c; cc -O2 -Wall -o fixdemo_baseline fixdemo.c icrc32.c; patch -d fixwork -p1 < fix.diff && cc -O2 -Wall -o fixdemo_patched fixdemo.c fixwork/sys/libkern/icrc32.c)",
  "run_cmd": "sh run.sh  (guest, in pack dir: ./icrc32_diff; ./fixdemo_baseline; ./fixdemo_patched)",
  "code_hash": "29acbcd0a567468761346edc7a6a3ebdb0ab1b59843a3a4adec315dc6bad8386",
  "notes": "Decisive harness run measured 0.06s real (rounded up to 1s). Guest /usr/src/sys/libkern/icrc32.c md5 29e2ead0a146caec695a6804944e3cde == audited tree; running kernel built from it Jul 2 2026. Guest left up, artifacts in /tmp/DF-5679 only, no panic, no reset needed. Negative result has weight: guard-page probe proves no OOB read in the init_bytes/running_length/end_bytes walk; all 9 CRC tables verified element-wise. Reserved IDs DF-5680..DF-5691 unused (no further findings).",
  "recommended_fix": "Propagate size_t end-to-end: calculate_crc32c/multitable_crc32c/crc32c_sb8_64_bit length params and the icrc32.c:15 + sys/sys/systm.h:207 prototypes take size_t (see fix.diff); keeps parity with crc32()/crc32_ext() which already honor size_t.",
  "fix_status": "fixed",
  "fix_baseline_reproduced": true,
  "fix_patched_reproduced": false,
  "fix_verdict": "fix.diff (size_t end-to-end, 4+1 hunks) applied to a copy of the pristine source and rebuilt on the guest: baseline fixdemo silently returns the 9-byte CRC (truncation present, exit 1); patched fixdemo honors the full 0x100000009 length and the child faults on the PROT_NONE guard page (SIGSEGV, FIX-OK, exit 0). The silently-truncated behavior is gone. Kernel-rebuild validation not performed: userland rig, non-memory-corruption Info finding (mandatory kernel rebuild rule applies to memory-corruption findings only).",
  "fix_evidence": "fix_run.log (baseline FIX-BAD/exit 1 vs patched FIX-OK sig 11/exit 0); fix_build.log (patch -p1 hunks 1-4 + systm.h hunk applied, both builds clean); fix.diff (sha256 fed7a77746635dc8bf11fd3a3301d51fee995ff6db31537dd7ad68796a029027)."
}