{
  "finding_id": "DF-4852",
  "status": "reproduced",
  "reproduced": 1,
  "impact": "none",
  "confidence": "certain",
  "verdict": "Reproduced on the guest as root: dm_target_stripe_inits chunk-size guard (dm_target_striped.c:98-99) does int*int arithmetic, so chunk sizes >= 2^22 pass by signed overflow -- the kernel ACCEPTED 4194304 (2^22, product 2^31 wraps to INT_MIN) and 2147483647 (INT_MAX, product wraps to -256), stored them in tsc->stripe_chunksize, and correctly REJECTED the non-overflow control 1048576 with EINVAL (dmesg: dm: Error unsupported chunk size 524288KB); the table ioctl readback confirmed the kernel stored 2 4194304 .... Impact is integrity/validation only (no kernel memory unsafety: with chunksize < 2^31 every strategy/dump intermediate stays in range -- verified in the finding text), hence impact=none and severity Low; /dev/mapper/control is 0640 root:operator so the attacker is already privileged. Fix behaviorally validated: with (uintmax_t)chunksize*DEV_BSIZE > MAXPHYS patched module, cases A and C return EINVAL while the legitimate 128-block chunk still loads (fix_run.log).",
  "exploit_chain": "",
  "evidence": "run.log (all four cases + params readback 2 4194304 ... + PASS), dmesg_run.log (dm: Stripe 2 devices chunk size 4194304KB accepted-BUG, 524288KB rejected-control, 2147483647KB accepted-BUG), fix_run.log (patched module: A and C -> EINVAL, D still accepted), VERDICT.md full math + no-memory-corruption analysis",
  "kernel_refs": [
    "sys/dev/disk/dm/striped/dm_target_striped.c:98-103",
    "sys/dev/disk/dm/striped/dm_target_striped.c:111-117",
    "sys/dev/disk/dm/striped/dm_target_striped.c:306-343",
    "sys/dev/disk/dm/device-mapper.c:584-596",
    "sys/dev/disk/dm/device-mapper.c:181",
    "sys/cpu/x86_64/include/param.h:122"
  ],
  "poc_changes": "no seed; wrote proplib dm-ioctl PoC. Two iterations were required: DragonFly prop_dictionary_send_ioctl() is one-way (unlike NetBSD), so the table readback needs prop_dictionary_sendrecv_ioctl(); and a remove_all() preamble is needed after an earlier run leaves the device (EEXIST).",
  "attempts": 4,
  "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": 1200,
  "guest_dirty": 0,
  "build_cmd": "guest: cd /tmp/df4852 && cc -O -Wall -o dm_chunk dm_chunk.c -lprop   (modules: kldload dm; kldload dm_target_striped)",
  "run_cmd": "guest: /tmp/df4852/dm_chunk   (fix check: kldload /usr/src/sys/dev/disk/dm/striped/dm_target_striped.ko && /tmp/df4852_p/dm_chunk)",
  "code_hash": "9bf8b857eccf6c5d9f9e5be635437fc31f7ef7da47a5f59e4d5007971cda1ee1",
  "notes": "kprintf at :100 labels the block count as KB (cosmetic). DF-1933 and DF-2454 (known, not re-reported) are the SAME ksnprintf-length-tracking root in stripe_table/stripe_info -- DF-2454 is effectively the info() variant of DF-1933. Refcount audit: dm_pdev_insert/decr are 1:1 per stripe_dev; dm_table_add_deps holds NO pdev reference (dm_table_free_deps only frees maps), and its -1 dup return being ignored by the ctor is therefore harmless.",
  "recommended_fix": "Cast to 64-bit before the multiply: if (chunksize < 1 || (uintmax_t)chunksize * DEV_BSIZE > MAXPHYS) -- see fix.diff",
  "fix_status": "fixed",
  "fix_baseline_reproduced": 1,
  "fix_patched_reproduced": 0,
  "fix_verdict": "fix.diff applies clean (hunk at :96) and dm_target_striped.ko rebuilds -Werror (fix_build.log, RC=0). BEHAVIORALLY validated on the guest: with the patched module loaded, the previously-accepted overflow values 4194304 and 2147483647 now return EINVAL with the correct dm: Error unsupported chunk size dmesg lines while the legitimate 128-block chunk still loads (fix_run.log: cases A/C UNEXPECTED=now-rejected, D accepted).",
  "fix_evidence": "fix.diff; fix_build.log (patched module, -Werror, RC=0); fix_run.log (patched behavior: A/C EINVAL, D accepted)"
}