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)
PoC verification
Evidence pack
findings/poc/DF-5286 Β· 4 files| File | Type | Description | Size | |
|---|---|---|---|---|
| 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)andsoftc->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_testableM_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
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.
No comments yet.