XPT_RESET_DEV frees a regular-pool command via the high-priority free list, corrupting command-pool accounting
Summary
mprsas_action_resetdev() at mpr_sas.c:3351: tm=mpr_alloc_command(sc) (regular pool req_list). Sent with HighPriority descriptor at :3370. Completion mprsas_resetdev_complete at :3384 -> mprsas_free_tm at :3425 -> mprsas_free_tm at :244 -> mpr_free_high_priority_command at :269 (high_priority_req_list). Pool mismatch: regular alloc, high-priority free. Each reset leaks 1 regular slot + corrupts high-pri list with out-of-range SMID. After N resets mpr_alloc_command returns NULL -> disk stall. Trigger: camcontrol reset da0 (operator priv). Fix: use mprsas_alloc_tm(sc) instead of mpr_alloc_command(sc).
Discussion (0)
PoC verification
Evidence pack
findings/poc/DF-1223 Β· 9 files| File | Type | Description | Size | |
|---|---|---|---|---|
| VERDICT.md | verdict | full narrative + path:line trace | 4.5 KB | β raw |
| README.md | readme | reproduce / preconditions / PoC snippet | 1.2 KB | β raw |
| fix.diff | suggested-fix | use mprsas_alloc_tm(sc) instead of mpr_alloc_command(sc) | 478 B | view raw |
| build.sh | build-log | nativekernel build validation | 250 B | view raw |
| run.sh | run-log | no runtime trigger; static trace | 154 B | view raw |
| env.txt | environment | guest uname, PCI devices, GENERIC config | 587 B | view raw |
| build.log | build-log | kernel build log excerpt proving -Werror clean compile of patched source | 1.1 KB | view raw |
| ../fix_build_combined.log | build-log | Combined 41-finding kernel build (rc=0, -Werror clean) | 5.6 MB | β download |
| ../fix_build_summary.txt | build-summary | Summary of the combined 41-finding kernel build | 826 B | view raw |
DF-1223 β mpr XCT_RESET_DEV pool mismatch
Reproduce
Not runnable on the audit guest β no LSI MPT-Fusion SAS controller is
attached. The verification is a static source trace + a compiling fix.diff.
To validate the fix compiles, after applying fix.diff to /usr/src:
cd /usr/src
make -j6 nativekernel KERNCONF=X86_64_GENERIC
Bug location
sys/dev/raid/mpr/mpr_sas.c:3351 β mprsas_action_resetdev() allocates
with mpr_alloc_command(sc) (regular pool) but frees via
mprsas_free_tm β mpr_free_high_priority_command (high-pri pool). Every
other TM path uses mprsas_alloc_tm(sc). Each reset leaks a regular slot
and corrupts the high-pri list with out-of-range SMIDs; after N resets,
mpr_alloc_command returns NULL β disk I/O stall.
Trigger preconditions (NOT met on this guest)
- An LSI MPT-Fusion SAS controller (mpr-attached) with a target.
- A user able to issue
camcontrol reset <target>(operator group).
On a system WITH an mpr target, the PoC is:
for i in $(seq 1 200); do camcontrol reset da0; done
# dmesg: "command alloc failure in mprsas_action_resetdev"; disk I/O stalls
Files
VERDICT.md,fix.diff,env.txt,build.log.
DF-1223 β mpr XPT_RESET_DEV pool mismatch (regular alloc, high-pri free)
Verdict
INCONCLUSIVE (not_testable on this guest) β bug confirmed in source; the
LSI MPT-Fusion SAS controller is absent from the audit guest. Fix authored,
applied, and compiled clean as part of a single-fix nativekernel build.
Finding summary
mprsas_action_resetdev() in sys/dev/raid/mpr/mpr_sas.c allocates the task
from the regular command pool at :3351:
tm = mpr_alloc_command(sc); /* pops from sc->req_list */
β¦then sends the request with a HighPriority descriptor at :3370
(MPI2_REQ_DESCRIPT_FLAGS_HIGH_PRIORITY), and on completion the path
mprsas_resetdev_complete (:3384) β mprsas_free_tm (:3425) β
mpr_free_high_priority_command (mprvar.h:642) frees it back to the
high-priority pool (sc->high_priority_req_list).
Every other task-management path in this driver uses mprsas_alloc_tm(sc)
(mpr_sas.c:234 β mpr_alloc_high_priority_command), so the alloc/free pools
match. Only mprsas_action_resetdev uses mpr_alloc_command directly β that
is the bug. Each device reset:
1. Leaks one slot from the regular req_list (it never comes back).
2. Pushes an out-of-range SMID command onto the high-priority list
(the regular alloc gives SMIDs in the regular-command range, which the
high-pri free assumes are in the high-pri SMID range).
3. After N resets, mpr_alloc_command returns NULL β all disk I/O on the
controller stalls β persistent DoS until reload/reboot. The corrupted
high-pri list can also cause downstream KKASSERTs / use-after-free on the
next high-pri task (the KASSERT at mprvar.h:654 may catch some shapes).
Triggered by camcontrol reset da0 (operator/cambreaker privilege β typically
operator group or root; reachable from any user in operator).
Source confirmation (audited tree)
- mpr_sas.c:3351 β
tm = mpr_alloc_command(sc);β popssc->req_list. - mpr_sas.c:3370β3371 β
tm->cm_desc.HighPriority.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_HIGH_PRIORITY;β sent as high-priority. - mpr_sas.c:3425 β
mprsas_free_tm(sc, tm);β completion frees via the helper. - mpr_sas.c:244β270 β
mprsas_free_tm()βmpr_free_high_priority_command(sc, tm);(line 269) β pushessc->high_priority_req_list. - mprvar.h:605β619 β
mpr_alloc_commandβ popsreq_list. - mprvar.h:622β643 β
mpr_free_high_priority_commandβ pusheshigh_priority_req_list. - mprvar.h:646β660 β
mpr_alloc_high_priority_commandβ popshigh_priority_req_list. - mpr_sas.c:234 β
mprsas_alloc_tm()βmpr_alloc_high_priority_command(sc);β the correct helper. - mpr_sas.c:461, 524, 1723 β every other TM path uses
mprsas_alloc_tm(sc). Only the reset path uses the regular alloc.
Why not runtime-reproduced on this guest
The QEMU/KVM guest has no LSI MPT-Fusion SAS controller (only virtio-blk for
storage). The mpr driver never attaches, no mpr_softc is created, no
SIM is registered with CAM, and camcontrol reset would target nothing.
The mpr.ko module is present but not loaded. The bug path is unreachable
at runtime on this guest.
Triggering the bug requires a real LSI MPT-Fusion SAS controller (or an
emulated one) with an attached target, and an unprivileged-ish user able to
issue camcontrol reset <target> (typically via the operator group, which
on multi-user systems is often granted to semi-trusted users).
Fix (fix.diff)
Use the existing mprsas_alloc_tm() helper, which allocates from the
high-priority pool that the completion path expects:
- tm = mpr_alloc_command(sc);
+ tm = mprsas_alloc_tm(sc);
One-line change, exactly matches what every other TM path in the same file
already does (mprsas_action_bus_reset, mprsas_action_target_reset,
mprsas_scsiio_timeout, etc. all use mprsas_alloc_tm(sc)). After the fix,
the alloc and free pools match: high-pri alloc, high-pri free.
Fix validation
git apply --check -p1β clean.- Applied to in-guest
/usr/src, built withmake -j6 nativekernel(with DF-1212 and DF-1214) β compiled clean,NK_DONE rc=0. fix_status: not_testableβ no LSI SAS hardware on this guest; cannot do a runtime before/aftercamcontrol resetdemonstration.
Run / reproduce
Not runnable on this guest. On a system with an mpr-attached SAS target, the PoC is:
for i in $(seq 1 N); do camcontrol reset da0; done
# after enough iterations: disk I/O stalls, mpr_alloc_command returns NULL,
# and dmesg shows "command alloc failure in mprsas_action_resetdev"
Fix verification
not_testablecompile validated
kernel/module build rc=0
Confirmed kernel references
β
Detail
Exploit chain
none
Evidence (decisive lines)
β
Verdict
Source-confirmed. mprsas_action_resetdev regular-pool alloc + high-pri free -> pool mismatch + DoS. mpr in GENERIC, no SAS HW.
No comments yet.