DF-4922 / verdict.json
{ "finding_id": "DF-4922", "status": "reproduced", "reproduced": 1, "impact": "leak", "confidence": "certain", "verdict": "dm_target_flakey_init() takes a dm_pdev reference (dm_pdev_insert, opens the device vnode, ref_cnt=1) at dm_target_flakey.c:86, but every post-insert failure path (interval sum==0 :96, interval overflow :102, _init_features error :108) jumps to fail: which only kfree()s tfc; the ref is never dropped. The downstream error path cannot recover it: dm_table_destroy() calls the target destroy handler, but target_config is still NULL so flakeys destroy returns early (:213), and pdev_maps is empty. Demonstrated on the guest: 3 failed loads grow the M_DM zone 336B->1.08K permanently (survives dm device removal) and leave vn0/vn1/vn2 permanently pinned (vnconfig -u -> VNIOCDETACH: Device busy), while the no-dm control unit detaches cleanly. Privileged (root/operator via /dev/mapper/control 0640) resource leak + device pinning; no memory-safety primitive.", "exploit_chain": "", "evidence": "run.log: M_DM 336 baseline -> 1.08K after A/B/C, unchanged after dm remove; LEAK-UNIT vn0/vn1/vn2: VNIOCDETACH: Device busy; CONTROL vn3 ... OK. dmesg line Unknown Flakey target feature nosuchfeature (env.txt) proves path B failed inside _init_features, i.e. after the insert.", "kernel_refs": [ "sys/dev/disk/dm/flakey/dm_target_flakey.c:86", "sys/dev/disk/dm/flakey/dm_target_flakey.c:96", "sys/dev/disk/dm/flakey/dm_target_flakey.c:102", "sys/dev/disk/dm/flakey/dm_target_flakey.c:108", "sys/dev/disk/dm/flakey/dm_target_flakey.c:117", "sys/dev/disk/dm/flakey/dm_target_flakey.c:213", "sys/dev/disk/dm/dm_pdev.c:151", "sys/dev/disk/dm/dm_pdev.c:242", "sys/dev/disk/dm/dm_table.c:150", "sys/dev/disk/dm/dm_ioctl.c:783" ], "poc_changes": "No seed PoC existed (new pass-2 finding). First attempt used 20 vn units; guest has only 4 vn units and same-inode backing files confuse attach, so the clean run uses one unit per failure path with distinct backing files plus a no-dm control unit.", "attempts": 2, "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": 90, "guest_dirty": 1, "build_cmd": "none (base-system dmsetup + kldload dm_target_flakey)", "run_cmd": "ssh -F dfbsd-qemu/config dfbsd cat > /tmp/leak_poc.sh < leak_poc.sh && dfbsd-qemu/vm.sh run_root sh /tmp/leak_poc.sh", "code_hash": "2c0e59658ab5f6d4136e0bac5a671ff9e673daa413c61bbf0b274649c1d06fd1", "notes": "Both guest resets after leak runs (dirty 20-unit run and clean 3-unit run) reported guest not answering during clean shutdown - reproducible shutdown wedge correlated with the pinned vn devices; serial log rotates on reset, so kept as a note, not a panic claim. Known-file findings DF-1981/DF-2452/DF-2453 deliberately not re-triggered or re-reported. Table-print ksnprintf accumulation pattern at :377-394 audited and found unreachable-overflow (udev_name is %d:%d, bounded).", "recommended_fix": "Add dm_pdev_decr(dmp) on the fail path of dm_target_flakey_init (see fix.diff).", "fix_status": "not_applicable", "fix_baseline_reproduced": 1, "fix_patched_reproduced": null, "fix_verdict": "Kernel rebuild not performed: Low-severity privileged resource leak, not memory corruption (fix validation mandated only for memory-corruption findings). The one-line fix.diff mirrors the normal teardown path (dm_pdev_decr at dm_target_flakey.c:217) and is correct by inspection against dm_pdev.c:242-259.", "fix_evidence": "fix.diff" } |