Dead debug printers carry latent unvalidated firmware-count walks (mpr_print_evt_sas NumEntries) and mpr_describe_table relies on a sentinel-plus-one convention
Summary
mpr_print_evt_sas walks data->PHY[i] for firmware-supplied NumEntries with no EventDataLength bound (zero callers tree-wide - the same class pass-1 filed against live consumers DF-1474/DF-3919/DF-4560); describe_table returns table[i+1] one past the {NULL,0} sentinel, in-bounds only by the extra-Unknown convention in all 13 tables. Bound-or-delete fix.
Discussion (0)
PoC verification
Evidence pack
findings/poc/DF-4790 Β· 6 files| File | Type | Description | Size | |
|---|---|---|---|---|
| README.md | β | 2.4 KB | β raw | |
| VERDICT.md | β | 2.0 KB | β raw | |
| env.txt | β | 920 B | view raw | |
| fix.diff | β | 832 B | view raw | |
| manifest.json | β | 499 B | view raw | |
| verdict.json | β | 1.9 KB | view raw |
DF-4790 β latent unvalidated event-count walks in dead debug printers; sentinel-plus-one convention in mpr_describe_table
What
sys/dev/raid/mpr/mpr_table.c contains two latent defects in code that is currently
dead (no callers anywhere in sys/ β verified with tree-wide grep; only
mpr_print_scsiio_cmd/mpr_print_sgl and mpr_describe_devinfo/mpr_describe_table
are live):
-
mpr_print_evt_sastopology walk (mpr_table.c:412-425).c for (i = 0; i < data->NumEntries; i++) { phy = &data->PHY[i];NumEntriesis a firmware-supplied byte inside the event reply and is never checked againstEventDataLength. The MPI2 event structure carriesPHY[]for the entries actually delivered; a short frame with a largeNumEntrieswalks past the event buffer (OOB heap read printed to console). This is the same defect class pass 1 filed against the live consumers (DF-1474 onmpr_sas_lsi.c, DF-3919 onmpr_mapping.c, mps twin DF-4560) β but inmpr_table.cthe function has no callers, so it is latent. If anyone ever wires this printer up (its mps counterpart was historically called from the event handler), the unbounded walk comes back. Recommended resolution: bound the loop byEventDataLength * 4(fix.diff) or delete the dead printer. -
mpr_describe_tablesentinel-plus-one (mpr_table.c:63-73).c for (i = 0; table[i].string != NULL; i++) { ... } return(table[i+1].string);The fallback intentionally indexes one entry past the{NULL, 0}sentinel. All 13 tables in this file happen to carry an extra{"Unknown β¦", 0}entry after the sentinel (mpr_table.c:107-108, 117-118, 131-132, 139-140, 152-153, 162-163, 169-170, 178-179, 194-195, 204-205, 226-227, 242-243, 255-256), so today it is in-bounds β but any future table that ends at the sentinel turns the "unknown code" lookup into an OOB pointer read +%sderef. Fragile-by-convention, worth a defensive bound or a literal fallback string.
Also noted, benign: mpr_table.c:457 β the MPI2_EVENT_SAS_DEVICE_STATUS_CHANGE case
falls through to default: (missing break;); default: break; makes it harmless.
Impact
None today (dead code / in-bounds-by-convention). Filed as Info hardening so the patterns don't get resurrected as-is.
Verdict
untested β latent code-path finding; nothing to execute.
DF-4790 VERDICT
- Status: untested (latent / dead code)
- Confidence: certain (dead-code status and loop bodies verified by direct read + tree-wide grep)
- Severity filed: Info
Evidence
Liveness check (tree-wide, rg over sys/): the only callers of any mpr_print_*
symbol outside mpr_table.c are
mpr_sas.c:2814βmpr_print_scsiio_cmd(live; covered by DF-4789)mpr_sas_lsi.c:967,1381βmpr_describe_devinfo(live; boundedksnprintfinto an 80-byte stack buffer β checked safe)
mpr_print_evt_sas, mpr_print_evt_generic, mpr_print_iocfacts,
mpr_print_portfacts, mpr_print_sasdev0, mpr_print_expander1, mpr_print_sasphy0
have zero callers. Their latent defects:
mpr_table.c:412-425βNumEntries(firmware byte) drivesdata->PHY[i]with noEventDataLengthbound. Compare the live twins already filed in pass 1: DF-1474 (mpr_sas_lsi.ctopo/IR/PCIe walks), DF-3919 (mpr_mapping.celement counts), DF-4560 (mpsmpssas_fw_workfixed-offset reads). Same class, currently unreachable.mpr_table.c:72βtable[i+1].stringrelies on every table shipping an extra entry after the{NULL,0}sentinel; all 13 do today (line refs in README), so this is convention-fragility, not a live OOB.
Why Info and not higher
Both arms require the dead code to be wired up first. No reachable path exists on any configuration, hardware or otherwise; nothing to execute on the guest.
Recommended fix summary
Bound the NumEntries walk by the event-frame length (fix.diff) β or better, delete the
dead printers; replace table[i+1].string with a literal "unknown" fallback or
bounds-check i+1.
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_testabledead code β nothing to validate on the guest; the diff is a defensive bound only
findings/poc/DF-4790/fix.diff
Confirmed kernel references
Detail
Evidence (decisive lines)
README.md (liveness + line cites), VERDICT.md (grep evidence of dead callers), fix.diff (NumEntries bound)
PoC changes
no PoC produced β dead code, no trigger path exists
Verified recommended fix
Delete the dead mpr_print_* debug printers or bound NumEntries by EventDataLength; use a literal fallback in mpr_describe_table
Verdict
Latent, currently-dead defects in mpr_table.c: (1) mpr_print_evt_sas walks data->PHY[i] for firmware-supplied NumEntries with no EventDataLength bound (mpr_table.c:412-425) β the same class as live pass-1 findings DF-1474/DF-3919/DF-4560, but this function has zero callers tree-wide; (2) mpr_describe_table returns table[i+1].string, one entry past the {NULL,0} sentinel (mpr_table.c:72) β in-bounds today only because all 13 tables ship an extra 'Unknown' entry. No reachable path, nothing to execute; filed as Info so the patterns are not resurrected as-is.
No comments yet.