⬢ DragonFlyBSD Kernel Audit
DF-2480 / verdict.json
← back to finding ↓ download raw
{
  "finding_id": "DF-2480",
  "status": "reproduced",
  "reproduced": 1,
  "impact": "corruption",
  "confidence": "certain",
  "verdict": "The verbatim mmcsd_rw/mmcsd_delete (extracted whole) assign bio->bio_offset/sz into daddr_t (= __int32_t, sys/types.h:80) block/end. Control (1000 sectors): cmd.arg correct. At exactly 1 TiB the arg still bit-matches (0x80000000). At 2 TiB the u64 block 0x100000000 arrives at the card as cmd.arg=0x00000000, and at 4 TiB+12345 sectors as 0x00003039 - the READ/WRITE/ERASE command is issued against the WRONG SECTOR (silent data corruption on >1TiB SDXC/eMMC media, or spurious EIO depending on card). mmcsd_delete shares the math (cited :534). Fix (64-bit locals + reject blocks beyond the 32-bit MMC argument with EIO) A/B: no MMC command is issued for the hostile offsets (opcode/arg unchanged, transfer skipped).",
  "exploit_chain": "no attacker needed - media-size correctness bug; corruption affects data at wrong sectors on large cards.",
  "evidence": "run.log: 2TiB -> cmd.arg=0x00000000 (expected 0x100000000) TRUNCATED/WRONG; 4TiB -> 0x00003039; control 0x3e8 CORRECT.",
  "kernel_refs": [
    "sys/dev/disk/mmcsd/mmcsd.c:327",
    "sys/dev/disk/mmcsd/mmcsd.c:328",
    "sys/dev/disk/mmcsd/mmcsd.c:345",
    "sys/dev/disk/mmcsd/mmcsd.c:415",
    "sys/sys/types.h:80"
  ],
  "poc_changes": "MMCBUS_WAIT_FOR_REQUEST interposed to capture cmd.arg; device reports success.",
  "attempts": 1,
  "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": 600,
  "guest_dirty": 0,
  "build_cmd": "sh /root/rigs/dfv_mmcsd/gen.sh && make -m /usr/src/share/mk (in dfv_mmcsd)",
  "run_cmd": "kldload dfv_mmcsd.ko; for i in 0 1 2 3 4; do sysctl kern.dfv_mmcsd_run=$i >/dev/null; sysctl -n kern.dfv_mmcsd_status; done",
  "code_hash": "e9326f24fb77555d8173b358b7b35b0e7be0969b443005a93e25a8420844f88d",
  "notes": "daddr_t is __int32_t (sys/types.h:80). At 2TiB the u32 arg still matches (0x80000000), at 2TiB+ it wraps to 0 and at 4TiB+ arbitrary low bits - wrong-sector commands against large SDXC/eMMC. Fixed code rejects beyond-32-bit blocks with EIO (rig: no MMC command issued).",
  "recommended_fix": "64-bit block math and reject blocks beyond the 32-bit MMC argument",
  "fix_status": "fixed"
}