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

Kernel heap memory disclosure via mps_user_event_report copyout with attacker-controlled length

Summary

mps_user_event_report at mps_user.c:1856-1859: size=data->Size (uint32 user, no upper bound). if(size>=sizeof(recorded_events)) copyout(recorded_events,...,size). recorded_events is 10000 bytes. Size=1MB -> reads 1MB past array through softc (function pointers, DMA handles) -> KASLR bypass. Operator group. Twin of DF-1328 (mpr_user.c). Fix: clamp size to sizeof(recorded_events).

Discussion (0)

No comments yet.

PoC verification

Evidence pack

findings/poc/DF-1360 Β· 12 files
FileTypeDescriptionSize
poc.c trigger-source opens /dev/mps0, issues MPTIOCTL_EVENT_REPORT with Size=256KiB to leak softc tail 3.1 KB view raw
fix.diff suggested-fix copyout sizeof(recorded_events) instead of user-controlled size 453 B view raw
build.sh repro-script cc -O2 -o poc poc.c 109 B view raw
run.sh repro-script ./poc 56 B view raw
build.log build-log poc build, full output 91 B view raw
run.log run-log open /dev/mps0 ENOENT (no SAS HBA on guest) 194 B view raw
fix_build.log fix-build-log clean mps.ko module build with fix applied, rc=0 16.1 KB view raw
env.txt environment uname + cc version + dev-node check 520 B view raw
README.md readme summary + reproduce 917 B ↓ raw
VERDICT.md verdict full mechanism + reachability + fix 3.3 KB ↓ 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
README.md readme summary + reproduce
↓ download raw

DF-1360 β€” mps_user_event_report kernel-heap info leak (mps)

Summary

mps_user_event_report (sys/dev/raid/mps/mps_user.c:1859) copyouts size bytes (uint32 user-controlled) out of the 10000-byte recorded_events array. The guard at :1857 is a lower bound (size >= 10000), so any size above 10000 over-reads the softc tail and adjacent heap. Twin of DF-1328 (mpr). No SAS HBA on the audit guest β†’ /dev/mps0 absent.

Reproduce

./build.sh   # cc -O2 -o poc poc.c
./run.sh     # ./poc

Expected on this guest: poc: open /dev/mps0: No such file or directory (errno=2) and RUN_EXIT=1 β€” the mps driver does not attach (no SAS HBA), so the leak cannot be exercised here. On an mps-equipped host (root/operator) the same PoC would leak kernel heap.

Fix

fix.diff changes the copyout length to sizeof(sc->recorded_events). Validated to apply + compile (mps.ko, clean build rc=0).

VERDICT.md verdict full mechanism + reachability + fix
↓ download raw

DF-1360 β€” VERDICT

Verdict: INCONCLUSIVE (real bug, needs hardware absent from guest). Source trace confirms the vulnerability; it cannot be executed on this QEMU guest because /dev/mps0 does not exist (no LSI MPS SAS HBA), so the PoC fails at open() with ENOENT. Fix validated to apply + compile in a clean mps.ko module build.

This is the mps driver's twin of DF-1328 (the identical bug in the mpr driver's mpr_user.c).

Mechanism

sys/dev/raid/mps/mps_user.c:1856   size = data->Size;                       // uint32_t, user-controlled
sys/dev/raid/mps/mps_user.c:1857   if ((size >= sizeof(sc->recorded_events)) && (status == 0)) {
sys/dev/raid/mps/mps_user.c:1858       mps_unlock(sc);
sys/dev/raid/mps/mps_user.c:1859       if (copyout((void *)sc->recorded_events,
sys/dev/raid/mps/mps_user.c:1860           PTRIN(data->PtrEvents), size) != 0)    // *** LEAK: len = user size ***
sys/dev/raid/mps/mps_user.c:1861           status = EFAULT;

sizeof(sc->recorded_events) = MPS_EVENT_QUEUE_SIZE (50, mps_ioctl.h:207) Γ— sizeof(mps_event_entry_t) (= 4+4+4*MPS_MAX_EVENT_DATA_LENGTH(48) = 200, mps_ioctl.h:224-230) = 10000 bytes (mpsvar.h:414).

The gate at 1857 is a lower bound (size >= 10000), not an upper bound. The copyout length is the user-supplied size, which can be up to 0xFFFFFFFF. Setting size = 256 KiB reads 256 KiB out of recorded_events: 10000 bytes of the array plus ~240 KiB of whatever follows it inside struct mps_softc (DMA bus addresses, kernel pointers, locks, command rings) and into adjacent kernel heap. Deterministic kernel-heap information leak.

Reachability on this guest

mps is a device in X86_64_GENERIC but no SAS HBA is present β†’ driver never attaches β†’ no /dev/mps0 β†’ PoC fails at open():

poc: open /dev/mps0: No such file or directory  (errno=2)
poc: mps driver not attached on this guest (no SAS HBA) -> cannot reach mps_user_event_report.
RUN_EXIT=1

Privilege model (same as mpr, make_dev UID_ROOT/GID_OPERATOR 0640, mps_open returns 0, no priv_check in mps_ioctl): reachable by root or operator-group users on an mps-equipped host. Phase-4(d): real code path, unreachable on this guest due to absent hardware.

Exploit chain

None β€” read-only OOB info leak, no corruption primitive. Impact ceiling: deterministic disclosure of the mps_softc tail (DMA addresses, kernel pointers) and adjacent heap, repeated to taste β†’ KASLR bypass / heap-layout reconnaissance.

PoC changes

Folder was empty. Authored poc.c (opens /dev/mps0, issues MPTIOCTL_EVENT_REPORT with Size = 256 KiB, would dump bytes 10000..10064 of the softc tail), build.sh, run.sh.

Fix

fix.diff makes the copyout length sizeof(sc->recorded_events) (the fixed array size) instead of the user-controlled size. The size >= gate remains the "did the user give a big enough buffer?" check; the actual bytes copied are now exactly the array. Applies cleanly (patch --dry-run hunk @1857) and the clean mps.ko build succeeds (rc=0 β€” fix_build.log). Matches the finding's proposed fix (clamp size to sizeof(recorded_events)).

Fix validation

fix_status: not_testable β€” PoC cannot run (no /dev/mps0). Fix validated by apply + clean module compile + code-path inspection (copyout length is now the constant array size, independent of data->Size).

Fix verification

not_testable

compile+harness validated

module build rc=0

Confirmed kernel references

β€”

Detail

Exploit chain

none

Evidence (decisive lines)

β€”

Verdict

Source-confirmed. mps_user_event_report copyout user Size not sizeof(recorded_events) -> heap info leak. mps in GENERIC, no SAS HBA.