β¬’ DragonFlyBSD Kernel Audit
← triage Β· dashboard
DF-2487

Modifying ioctls (MPTIO_WRITE_CFG_PAGE MPTIO_RAID_ACTION) allowed via read-only file descriptor

Summary

mpt character device created mode 0640 (operator group read-only) but mpt_ioctl performs no FWRITE check before dispatching state-changing ioctls MPTIO_WRITE_CFG_PAGE and MPTIO_RAID_ACTION. Operator-group user who can only open node O_RDONLY can rewrite controller config pages and issue RAID actions including volume deletion bypassing write-permission boundary implied by 0640 mode. DragonFly imposes no framework-level requirement fd opened FWRITE to issue ioctl so driver is sole enforcer. [VERIFIED pass2: HW-gated no MPT on guest - source-certain no FWRITE check on mutating MPTIO ioctls over 0640 GID_OPERATOR node; fflag fix compile-validated building full mpt.ko -Werror]

Discussion (0)

No comments yet.

PoC verification

Evidence pack

findings/poc/DF-2487 Β· 8 files
FileTypeDescriptionSize
README.md β€” 901 B ↓ raw
VERDICT.md β€” 2.1 KB ↓ raw
build.sh β€” 99 B view raw
run.log β€” 404 B view raw
env.txt β€” 963 B view raw
fix.diff β€” 909 B view raw
manifest.json β€” 681 B view raw
verdict.json β€” 2.5 KB view raw

DF-2487 -- mpt modifying ioctls allowed via read-only fd

Verification used the shared rig tree at /root/rigs on the audit guest (see manifest). The rig for this finding: dfv_mpt (rig.c = harness, gen.sh = verbatim extractor, dfv_*_extract.h = generated production text). The decisive outputs below were captured live on the guest during the 2026-10-24 verification session; full session logs are summarized per run.

Build

sh build.sh            # extracts verbatim driver text + builds the KLD

Run (guest, root)

kldload ./dfv_rig.ko

(compile validation only - no MPT hardware on the guest)

Expected

mpt.ko built clean with the fix (compile validation); source trace of both dispatch sites.

Fix validation

fix.diff adds FWRITE checks to MPTIO_WRITE_CFG_PAGE and MPTIO_RAID_ACTION; module builds clean.

Verdict: not_reproduced / impact=none (see verdict.json, VERDICT.md)

VERDICT.md
↓ download raw

DF-2487 verdict -- mpt modifying ioctls allowed via read-only fd

status: not_reproduced reproduced: 0 impact: none confidence: certain attempts: 2 runtime_sec: 300

HW-gated at runtime: the mpt character device is created only when an LSI MPT HBA attaches (mpt_user.c:116 inside the attach path); the guest has no MPT controller (pciconf -l shows PIIX3 IDE + virtio only, camcontrol shows the QEMU DVD only), so /dev/mptN does not exist and the ioctl path is dead here. The defect is source-certain: mpt_ioctl dispatches MPTIO_WRITE_CFG_PAGE (mpt_user.c:715) and MPTIO_RAID_ACTION (:729) - both state-mutating, including volume deletion - with no check that the fd was opened FWRITE, while the node is created 0640 GID_OPERATOR (operator can open O_RDONLY). The fix adds a_fflag & FWRITE gates to both cases; validated by building the complete mpt.ko module (all six objects, -Werror) against the patched tree - the first compile round correctly caught the wrong field name (a_oflags -> a_fflag) and a missing fcntl.h include, proving the validation path exercises the real driver.

Evidence (decisive lines)

$ cd /usr/src/sys/dev/disk/mpt && make -m /usr/src/share/mk all round 1 (initial fix draft): error: struct dev_ioctl_args has no member a_oflags; FWRITE undeclared -> corrected to a_fflag + #include round 2: cc ... -c mpt_user.c ; cc -Wl,--build-id=sha1 -nostdlib -r -o mpt.ko mpt.o mpt_cam.o mpt_debug.o mpt_pci.o mpt_raid.o mpt_user.o BUILD OK (-Werror): mpt.ko with both FWRITE gates

Exploit chain / privesc assessment

privileged-boundary bypass for the operator group on machines with MPT hardware; not reachable on this guest.

Fix + A/B

fix.diff adds FWRITE checks to MPTIO_WRITE_CFG_PAGE and MPTIO_RAID_ACTION; module builds clean.

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_testable
↓ fix.diffper-fix-DF-2487

Confirmed kernel references

Detail

Exploit chain

privileged-boundary bypass for the operator group on machines with MPT hardware; not reachable on this guest.

Evidence (decisive lines)

mpt.ko built clean with the fix (compile validation); source trace of both dispatch sites.

PoC changes

no rig - compile validation against the real module build.

Verified recommended fix

require FWRITE on the fd for MPTIO_WRITE_CFG_PAGE and MPTIO_RAID_ACTION

Verdict

HW-gated at runtime: the mpt character device is created only when an LSI MPT HBA attaches (mpt_user.c:116 inside the attach path); the guest has no MPT controller (pciconf -l shows PIIX3 IDE + virtio only, camcontrol shows the QEMU DVD only), so /dev/mptN does not exist and the ioctl path is dead here. The defect is source-certain: mpt_ioctl dispatches MPTIO_WRITE_CFG_PAGE (mpt_user.c:715) and MPTIO_RAID_ACTION (:729) - both state-mutating, including volume deletion - with no check that the fd was opened FWRITE, while the node is created 0640 GID_OPERATOR (operator can open O_RDONLY). The fix adds a_fflag & FWRITE gates to both cases; validated by building the complete mpt.ko module (all six objects, -Werror) against the patched tree - the first compile round correctly caught the wrong field name (a_oflags -> a_fflag) and a missing fcntl.h include, proving the validation path exercises the real driver.