DragonFlyBSD Kernel Audit
DF-3083 / verdict.json
← back to finding ↓ download raw
{
  "finding_id": "DF-3083",
  "status": "reproduced",
  "reproduced": 1,
  "impact": "panic",
  "confidence": "certain",
  "verdict": "One corrupted dirent byte (rec_len 16->17, so rec_len % 4 != 0) in a crafted ext2 image, mounted read-write, panics the stock kernel on the first unprivileged path lookup that walks past it: ext2_check_direntry rejects the entry, ext2_search_dirblock calls ext2_dirbad (ext2_lookup.c:701), which panics on any non-MNT_RDONLY mount (ext2_lookup.c:777-780). The identical lookup on a read-only mount survives (control run), and the walker already skips to the next block, so the panic is pure fail-stop policy. Single-fix kernel (printf instead of panic): same lookup returns ENOENT, console shows the ext2_dirbad message, no panic.",
  "exploit_chain": "crafted image (1 flipped byte) + RW mount (root, or unpriv with vfs.usermount=1) -> stat/open/ls -l of any name at/after the corrupt entry -> ext2_search_dirblock:701 -> ext2_dirbad:778 panic -> reboot-loopable local DoS; also the automatic follow-on of DF-3082 on valid images (zero-filled freed htree leaves)",
  "evidence": [
    "panic.txt: panic ext2_dirbad /mnt/e2 ino 12 offset 56 via ext2_lookup<-ext2_search_dirblock<-vop_compat_nresolve",
    "run.log: RO control survived; RW trigger transcript",
    "fix_run.log: 'stat file4 rc=1 (ENOENT expected, NO panic)' + console ext2_dirbad printf + FIX-OK",
    "fix.diff (shared with DF-3082)"
  ],
  "kernel_refs": [
    "sys/vfs/ext2fs/ext2_lookup.c:698",
    "sys/vfs/ext2fs/ext2_lookup.c:701",
    "sys/vfs/ext2fs/ext2_lookup.c:771",
    "sys/vfs/ext2fs/ext2_lookup.c:777",
    "sys/vfs/ext2fs/ext2_lookup.c:801",
    "sys/vfs/ext2fs/ext2_lookup.c:803",
    "sys/vfs/ext2fs/ext2_lookup.c:805",
    "sys/vfs/ext2fs/ext2_lookup.c:532"
  ],
  "poc_changes": "Initial trigger used ls -l; readdir EIOs before emitting names on this image so no lstat reached the corrupt entry - replaced with a direct stat of a name positioned after the corrupt entry (deterministic). run.sh updated; craft.py in pack regenerates the image.",
  "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 (baseline); fix kernel #1: Sun Sep  6 03:12:08 UTC 2026",
  "runtime_sec": 20,
  "guest_dirty": 0,
  "build_cmd": "host: python3 craft.py; guest root: cc -O2 -o /root/vntool /root/vntool.c; fix kernel shared with DF-3082 (make nativekernel + installkernel)",
  "run_cmd": "guest root: sh run.sh",
  "code_hash": "890092f0c08c90be9e36e1075b22b0bc0ad8d7c5509056e27a5ba8125f757c8a",
  "notes": "vfs.usermount=0 on this guest (root performs the mount); with vfs.usermount=1 the whole chain is unprivileged. Panic trace double-prints ext2_dirbad (compiler tail-duplication artifact). Guest reset to with-src snapshot after the runs.",
  "recommended_fix": "replace the panic with printf+SDT in ext2_dirbad (fix.diff, validated in-guest)",
  "fix_status": "fixed",
  "fix_kernel_uname": "DragonFly dfbsd 6.5-DEVELOPMENT #1: Sun Sep  6 03:12:08 UTC 2026 root@dfbsd:/usr/obj/usr/src/sys/X86_64_GENERIC x86_64",
  "fix_baseline_reproduced": 1,
  "fix_patched_reproduced": 0,
  "fix_verdict": "Same mangled image, RW mount, same lookup on the single-fix kernel: ENOENT returned, console prints 'ext2_dirbad: : bad dir ino 12 at offset 56: mangled entry', entries before the corrupt byte still resolve (stat file1 ok), guest stays up (fix_run.log).",
  "fix_evidence": [
    "fix_run.log",
    "fix.diff",
    "build.log.gz (in DF-3082 pack, shared build)"
  ]
}