DF-4922 / leak_poc.sh
#!/bin/sh # DF-4922 — dm_target_flakey_init failure paths leak the dm_pdev reference # (and the open device vnode) taken by dm_pdev_insert() at # sys/dev/disk/dm/flakey/dm_target_flakey.c:86. # # All three post-insert failure paths exercised, one vn unit each: # A. interval sum == 0 : "flakey /dev/vn0 0 0 0" (:96-100) # B. unknown feature : "flakey /dev/vn1 0 1 1 1 nosuchfeat" (:195-196) # C. interval overflow : "flakey /dev/vn2 0 2147483647 2147483647" (:102-106) # Control: vn3 attached+detached with NO dm load -> must detach cleanly. # # Success criteria: # - every failed load returns EINVAL ("Invalid argument") # - M_DM malloc zone grows ~ +3*sizeof(dm_pdev_t) and STAYS grown # after the half-created dm devices are removed # - vn0/vn1/vn2 detach -> EBUSY ("Device busy") forever # - control vn3 detaches OK exec 2>&1 echo "=== DF-4922 PoC (clean run) ===" uname -a kldload dm_target_flakey && echo "flakey module loaded" for i in 0 1 2 3; do dd if=/dev/zero of=/tmp/back$i.img bs=1048576 count=1 2>/dev/null done echo "--- M_DM baseline ---" vmstat -m | grep -w dm echo "--- control: vn3 attach+detach, NO dm load ---" vnconfig -c -S 1m -T vn3 /tmp/back3.img && echo "CONTROL attach vn3: OK" if vnconfig -u vn3 2>/dev/null; then echo "CONTROL detach vn3: OK (expected)"; else echo "CONTROL detach vn3: FAILED (unexpected)"; fi echo "--- path A: up_int+down_int == 0 ---" vnconfig -c -S 1m -T vn0 /tmp/back0.img && echo "attach vn0 OK" out=$(dmsetup create leakA --table "0 8 flakey /dev/vn0 0 0 0" 2>&1); rc=$? echo "load rc=$rc out='$out' (expect Invalid argument)" echo "--- path B: unknown feature ---" vnconfig -c -S 1m -T vn1 /tmp/back1.img && echo "attach vn1 OK" out=$(dmsetup create leakB --table "0 8 flakey /dev/vn1 0 1 1 1 nosuchfeature" 2>&1); rc=$? echo "load rc=$rc out='$out' (expect Invalid argument)" echo "--- path C: interval overflow ---" vnconfig -c -S 1m -T vn2 /tmp/back2.img && echo "attach vn2 OK" out=$(dmsetup create leakC --table "0 8 flakey /dev/vn2 0 2147483647 2147483647" 2>&1); rc=$? echo "load rc=$rc out='$out' (expect Invalid argument)" echo "--- M_DM after A+B+C (3 leaked pdevs expected) ---" vmstat -m | grep -w dm echo "--- remove half-created dm devices ---" for d in $(dmsetup ls 2>/dev/null | awk '{print $1}'); do echo "removing dm device $d"; dmsetup remove "$d" >/dev/null 2>&1 done echo "--- M_DM after dm removal (must NOT shrink: pdev refs leaked) ---" vmstat -m | grep -w dm echo "--- detach leaked units vs control ---" for u in vn0 vn1 vn2; do if vnconfig -u $u 2>/tmp/err.$u; then echo "LEAK-UNIT $u detached OK (unexpected - no leak?)" else echo "LEAK-UNIT $u: $(cat /tmp/err.$u | tail -1) <-- pdev ref leaked, device pinned" fi done vnconfig -c -S 1m -T vn3 /tmp/back3.img >/dev/null 2>&1 vnconfig -u vn3 >/dev/null 2>&1 && echo "CONTROL vn3 re-attach+detach: OK (proves EBUSY above is the leak, not the tool)" echo "=== DF-4922 PoC end ===" |