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

samount parses uninitialized 8192-byte heap as block-limits geometry on short READ BLOCK LIMITS

Summary

rblim kmalloc(8192) without M_ZERO and no short-transfer check: a device completing RBL with <6 bytes leaves blk_gran/max_blk/min_blk derived from stale kernel heap - state-only (no copyout) but feeds the DF-5285 modulo and corrupts request validation. M_ZERO hunk included in the DF-5285 fix-validation build.

Discussion (0)

No comments yet.

PoC verification

Evidence pack

findings/poc/DF-5286 Β· 4 files
FileTypeDescriptionSize
Makefile β€” 52 B ↓ download
README.md β€” 1.4 KB ↓ raw
evilsa.c β€” 15.2 KB view raw
verdict.json β€” 2.0 KB view raw

DF-5286 β€” samount parses uninitialized heap on short READ BLOCK LIMITS

sys/bus/cam/scsi/scsi_sa.c:1961 β€” rblim = kmalloc(8192, M_SCSISA, M_INTWAIT); (no M_ZERO) is used both as the dummy-read scratch and as the READ BLOCK LIMITS response buffer. scsi_read_block_limits() requests only sizeof(struct scsi_read_block_limits_data) (6 bytes, scsi_sa.c:3459-3461) and nothing checks the transfer length, so a device that returns CAM_REQ_CMP with a short transfer leaves the buffer's stale heap contents to be parsed as geometry:

  • softc->blk_gran = RBL_GRAN(rblim) (scsi_sa.c:2008) β€” masked to 5 bits, so bounded;
  • softc->max_blk = scsi_3btoul(rblim->maximum) and softc->min_blk = scsi_2btoul(rblim->minimum) (scsi_sa.c:2018-2019) β€” fully stale-byte-derived, no sanity clamp.

Consequences are state-only (request-size validation in sastrategy, the granularity mask, and the DF-5285 modulo) β€” the bytes are never copied to userspace. Severity: Low (hardening), confidence certain (static); Phase V skipped per contract for Low findings.

The evilsa rig in the DF-5284/DF-5285 packs has a ready-made debug.evilsa.rbl_short=1 personality (zero-length RBL transfer) if triage ever wants a live demonstration.

Fix

M_ZERO on the allocation β€” included as hunk 2 of findings/poc/DF-5285/fix.diff (compiled in the fix-validation kernel build, ../DF-5285/fix_build.log).

Fix verification

not_testable
baseline no→ patch + rebuild →patched clean

M_ZERO hunk compiled as part of the DF-5285 fix kernel build (fix_build.log) but the short-RBL scenario itself was not executed

findings/poc/DF-5285/fix_build.log
per-fix-DF-5286

Confirmed kernel references

Detail

Evidence (decisive lines)

scsi_sa.c:1961,1988-1994,2007-2019 (cited in finding); fix.diff hunk 2; evilsa.c rbl_short choreography available if triage wants a live run

PoC changes

evilsa.c carries a ready rbl_short=1 mode (zero-length RBL transfer); not run

Verified recommended fix

kmalloc rblim with M_ZERO (included in DF-5285 fix.diff hunk 2).

Verdict

Not executed (Low-severity hardening finding; Phase V skipped per contract). Static proof: samount() kmallocs the 8192-byte READ BLOCK LIMITS scratch without M_ZERO (scsi_sa.c:1961) and parses gran/maximum/minimum from it (scsi_sa.c:2007-2019) with no short-transfer check - a device that completes RBL with a short transfer leaves blk_gran/max_blk/min_blk derived from stale kernel heap. Consequence is state-only (RBL_GRAN is masked to 5 bits; max/min only gate request sizes in sastrategy and feed the DF-5285 modulo), with no copyout of the bytes, hence Low. The M_ZERO hunk is included in the DF-5285 fix.diff and was compile-validated with that kernel build.