⬢ DragonFlyBSD Kernel Audit
DF-4829 / verdict.json
← back to finding ↓ download raw
{
  "finding_id": "DF-4829",
  "status": "not_reproduced",
  "reproduced": 0,
  "impact": "none",
  "confidence": "certain",
  "verdict": "The 32-bit wrap in mdstrategy_mallocs secp growth is a certain code defect (md.c:253 truncates the 64-bit bio offset; md.c:303 computes the kmalloc size in 32-bit arithmetic, so a write at 0x1FFFFFFE00 gives secno=0xFFFFFFFF and a wrapped size of 0 -> kmalloc(0) returns ZERO_LENGTH_PTR=(void*)-8 per kern_slaballoc.c:884, then md.c:306 bcopys nsecp*8 bytes to VA -8; a 1024-byte transfer instead wraps to a real 16-byte chunk = heap overflow, and md.c:310/315/323 always follows with a wild write at secp+32GB). However it is NOT reachable on this tree: /dev/mdN is the disk1_ops covering device whose diskstrategy->dscheck (subr_disk.c:1222, subr_diskslice.c:91-236) bounds all bios to d_media_blocks=20000 (10MiB) and returns EINVAL beyond (verified live: pwrite@0x1FFFFFFE00 -> EINVAL, no panic; in-bounds pwrite@4MiB grows the array normally), the raw md_ops cdev is never devfs-published (make_only_dev, kern_conf.c:271), and the only unbounded dscheck branch (part>=128 kernel-raw, subr_diskslice.c:166-176) has no userland-openable cdev. Reported as Info/latent defense-in-depth; it becomes kernel memory corruption if any future path feeds mdstrategy an unclamped bio_offset.",
  "exploit_chain": "",
  "evidence": "run.log (trigger survived, errno=22), env.txt (boundary matrix: in-bounds OK / >=media-end EINVAL), VERDICT.md (full gate trace), fix.diff (64-bit secno + MD_MAX_NSECT cap)",
  "kernel_refs": [
    "sys/dev/disk/md/md.c:253",
    "sys/dev/disk/md/md.c:303",
    "sys/dev/disk/md/md.c:306",
    "sys/dev/disk/md/md.c:310",
    "sys/kern/kern_slaballoc.c:884",
    "sys/kern/subr_disk.c:691",
    "sys/kern/subr_disk.c:1222",
    "sys/kern/subr_diskslice.c:91",
    "sys/kern/subr_diskslice.c:166"
  ],
  "poc_changes": "n/a (first authored version; seed sketch corrected for printf errno-eval order in the boundary probe)",
  "attempts": 3,
  "guest_uname": "DragonFly dfbsd 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": 420,
  "guest_dirty": 0,
  "build_cmd": "cc -O2 -o mdwrap mdwrap.c",
  "run_cmd": "./mdwrap A",
  "code_hash": "351fbd802947fd4259684b1c31a12e091a5275ec462ed2f08e10511fd8ccf7e2",
  "notes": "Latent: defect certain, reachability dead (dscheck gate + no raw-md devfs node + no part>=128 cdev creator). Even if reached, the mandatory wild write at secp[secno>=2^31] in the same request forecloses a controlled post-corruption window (panic-with-heap-smash, not clean privesc). Side observation: opening /dev/md0 auto-created md1 on the guest (live confirmation of known DF-2478).",
  "recommended_fix": "Compute secno in 64-bit ((uint64_t)bio->bio_offset >> DEV_BSHIFT) and reject transfers with secno+nsec above a hard cap before the growth kmalloc (see fix.diff).",
  "fix_status": "not_testable",
  "fix_baseline_reproduced": 0,
  "fix_patched_reproduced": 0,
  "fix_verdict": "fix.diff authored (64-bit sector number + MD_MAX_NSECT growth cap + EIO on out-of-range requests). Not kernel-build-validated: the latent path cannot be triggered on the current tree, so there is no reproducible baseline behavior to compare against.",
  "fix_evidence": "fix.diff in this pack; gate trace in VERDICT.md"
}