mly_cam_complete() INQUIRY rewrite writes vendor/product/revision at data_ptr[8..36) regardless of dxfer_len β heap OOB write via short pass(4) INQUIRY CCB on a logical device
Summary
On SCSI_STATUS_OK with CDB[0]==INQUIRY for a logical target, padstr() unconditionally rewrites inquiry fields at fixed offsets 8/16/32 of csio->data_ptr; pass(4) lets the caller pick any dxfer_len, so buffers shorter than 36 bytes are overrun by up to ~32 bytes (content static driver text, length/offset attacker-chosen - adjacent slab chunk-header corruption). Distinct from DF-1289 (the sense path). Gate-on-dxfer_len fix.
Discussion (0)
PoC verification
Evidence pack
findings/poc/DF-3930 Β· 5 files| File | Type | Description | Size | |
|---|---|---|---|---|
| README.md | β | 1.0 KB | β raw | |
| VERDICT.md | β | 2.8 KB | β raw | |
| fix.diff | β | 905 B | view raw | |
| env.txt | β | 543 B | view raw | |
| verdict.json | β | 2.4 KB | view raw |
DF-3930 β mly: mly_cam_complete() INQUIRY rewrite writes past a short CAM data buffer (heap OOB write)
Build / Run (on hardware)
Needs an mly controller with a logical device and access to its pass(4) device (root, or operator where devfs grants it):
camcontrol cmd 3:0:0 -c "12 00 00 00 04 00" -d 4 # 4-byte INQUIRY data-in
or equivalently a pass(4) XPT_SCSI_IO CCB with cdb_len=6,
cdb[0]=INQUIRY (0x12), dxfer_len=4, CAM_DIR_IN targeting the logical
volume. sc->mly_btl[bus][target].mb_flags & MLY_BTL_LOGICAL must be set
(it is, for mly virtual targets).
Expected result
mly_cam_complete() (status OK, cmd==INQUIRY) unconditionally rewrites
vendor/product/revision at data_ptr+8..+36 (padstr calls,
mly.c:2343-2345) regardless of dxfer_len. With a 4-byte buffer this writes
~32 bytes of device-descriptive text past a 4-byte kernel allocation β
adjacent heap corruption (mchunk metadata / neighbouring object headers).
No mly hardware in the audit guest β not runtime-reproduced; source-certain. See VERDICT.md.
DF-3930 verdict narrative
Reproduced?
No (hardware-gated: guest has no mly controller). Source-level certainty: certain.
Root cause chain (path:line)
mly.c:2331-2346 (mly_cam_complete, SCSI_STATUS_OK path):
c
if (sc->mly_btl[bus][target].mb_flags & MLY_BTL_LOGICAL) {
cmd = <cdb[0]>; /* 0x12 == INQUIRY */
if (cmd == INQUIRY) {
btl = &sc->mly_btl[bus][target];
inq = (struct scsi_inquiry_data *)csio->data_ptr; /* :2318 */
padstr(inq->vendor, ..., 8); /* writes data_ptr[8..16) */
padstr(inq->product, ..., 16); /* writes data_ptr[16..32) */
padstr(inq->revision, "MYLX", 4); /* writes data_ptr[32..36) */
}
}
csio->data_ptr / dxfer_len come straight from the CAM client. For a
normal probe INQUIRY dxfer_len is 36 so the rewrite fits. But pass(4)
forwards user-chosen CCBs: a 6-byte INQUIRY CDB with a short data-in buffer
(e.g. 4 bytes β the allocation pass makes for the transfer) reaches the
driver verbatim; the controller truncates its reply, status comes back OK,
and padstr then writes at offsets 8..36 of a 4-byte kmalloc buffer β an
out-of-bounds heap write of up to 32 bytes past the allocation.
Layout facts: struct scsi_inquiry_data has vendor at offset 8, product at
16, revision at 32 (scsi_all.h); padstr (mlyvar.h:362-372) writes exactly
len bytes.
The written content is static text (mly_tables.h strings, "MYLX") and space-fill β not attacker bytes, but the length/position are attacker-chosen (dxfer_len 0..35 selects how far past the end writes begin), and the clobbered neighbours are kernel heap metadata/objects. On this guest's slab allocator (a 4-byte request rounds to an 8-byte chunk) the write runs over the following chunk's header.
Threat model
Local privileged-ish user (pass device; typically root, operator where granted) on a machine with an mly logical volume. Requires the volume to report OK status for the short inquiry β it does, the card merely truncates.
Impact
Bounded (~32B) kernel heap OOB write with fixed content at a length-controlled offset β heap metadata corruption, panic most likely; exploitability limited by the static content but nonzero (chunk-header clobbering).
Distinct from knowns: DF-1289 is the sense_data overflow in the same function (mly.c:2356-2358); this is the INQUIRY-rewrite path (mly.c:2341-2346).
Fix
Gate the rewrite on csio->dxfer_len >= 36 β fix.diff.
Fix status (batch validation)
Applied with the 36 sibling fix.diffs of this batch in findings/poc/_batch41/all_fixes.patch; single in-guest make -j6 nativekernel KERNCONF=X86_64_GENERIC completed RC=0 with zero errors under -Werror (full log: findings/poc/_batch41/fix_build8.log). Behavior A/B intentionally skipped for this Info-tier item.
Fix verification
not_testableFix not validated on the guest: the trigger path requires mly/age hardware absent from the audit guest. fix.diff is mechanical (bounds/termination-only) and authored post-verification against the cited lines.
findings/poc/DF-3930/fix.diff + VERDICT.md
Confirmed kernel references
Detail
Exploit chain
privileged pass(4) user sends short INQUIRY data-in CCB to an mly logical volume -> padstr writes at data_ptr[8..36) past the short kernel buffer -> adjacent heap metadata corruption
Evidence (decisive lines)
findings/poc/DF-3930/VERDICT.md; README.md (exact camcontrol trigger); fix.diff (dxfer_len >= 36 gate)
PoC changes
No seed PoC; trigger documented as camcontrol/pass CCB one-liner in README.md.
Verified recommended fix
Only rewrite inquiry vendor/product/revision when csio->dxfer_len >= 36.
Verdict
Hardware-gated (no mly controller / logical volume in the guest); source-certain. mly_cam_complete (mly.c:2331-2346), on SCSI_STATUS_OK for a logical target with CDB[0]==INQUIRY, unconditionally rewrites the inquiry data at data_ptr+8..36 via padstr regardless of the CCB's dxfer_len. pass(4) forwards user-chosen buffers: a 6-byte INQUIRY CDB with a 4-byte data-in buffer (camcontrol cmd 3:0:0 -c '12 00 00 00 04 00' -d 4) makes the driver write ~32 bytes of static device-descriptive text past a 4-byte kmalloc - bounded heap OOB write with length/offset attacker-chosen (dxfer_len 0..35), clobbering adjacent slab chunk headers. Known DF-1289 covers the sense_data bcopy in the same function (:2356-2358); this is the distinct INQUIRY-rewrite path. Not runtime-reproduced (hardware absent); certain at source level.
No comments yet.