_mapping_get_dpm_idx_from_id reads PhysicalIdentifier once from entry 0 and compares every DPM entry against it (mps twin of DF-3916)
Summary
The 64-bit PhysicalIdentifier is loaded from DPM entry 0 outside the loop and never re-read; the equality test compares every candidate against entry 0's ID. With >1 populated DPM entry, lookups return BAD_IDX -> duplicate entries, double-booked dpm_entry_used and divergent dpm_entry_num -> persistent-mapping corruption across reboots. All indices stay bounded (no OOB). Line-for-line identical to mpr sibling DF-3916. Re-read-per-iteration fix.
Discussion (0)
PoC verification
Evidence pack
findings/poc/DF-4087 Β· 6 files| File | Type | Description | Size | |
|---|---|---|---|---|
| README.md | β | 3.0 KB | β raw | |
| VERDICT.md | β | 2.0 KB | β raw | |
| env.txt | β | 1.4 KB | view raw | |
| fix.diff | β | 825 B | view raw | |
| manifest.json | β | 521 B | view raw | |
| verdict.json | β | 1.9 KB | view raw |
DF-4087 β _mapping_get_dpm_idx_from_id reads PhysicalIdentifier once (entry 0) and never refreshes it β DPM lookups only ever match entry 0
File: sys/dev/raid/mps/mps_mapping.c:505-525
Class: CWE-697 wrong-variable / stale-read logic defect (mps twin of the
mpr sibling finding DF-3916, line-for-line identical defect)
Severity: Low β pass 2 (GLM 5.3), bucket base:dev
Confidence: certain
The bug
dpm_entry = (Mpi2DriverMap0Entry_t *)((u8 *)sc->dpm_pg0 + hdr);
PhysicalIdentifier = dpm_entry->PhysicalIdentifier.High; /* entry 0 only */
PhysicalIdentifier = (PhysicalIdentifier << 32) |
dpm_entry->PhysicalIdentifier.Low;
for (entry_num = 0; entry_num < sc->max_dpm_entries; entry_num++,
dpm_entry++) /* ptr walks */
if ((id == PhysicalIdentifier) && /* value doesn't */
(!phy_bits || !dpm_entry->PhysicalBitsMapping ||
(phy_bits & dpm_entry->PhysicalBitsMapping))) /* these do */
return entry_num;
The 64-bit PhysicalIdentifier is loaded once, from entry 0, outside the
loop; the loop advances the pointer but never re-reads the identifier, so the
equality test compares every candidate entry against entry 0's ID. The
phy-bits term (which does dereference the walking pointer) is evaluated only
after the (bogus) equality already succeeded.
Impact
_mapping_get_dpm_idx_from_id() is the DPM lookup used by
_mapping_add_new_device:1179 (enclosure mapping) and
_mapping_update_ir_missing_cnt:591 (volumes). With a populated DPM page
(>1 non-zero entry), every lookup for an ID β entry-0's ID returns
MPS_DPM_BAD_IDX:
- the caller then takes the
_mapping_get_free_dpm_idx()path and allocates a duplicate DPM entry for an enclosure/volume that already has one, - enclosure/volume persistence entries get double-booked,
dpm_entry_used[]fills prematurely, andet_entry->dpm_entry_num/mt_entry->dpm_entry_numcan point at different entries for the same device β persistent-mapping divergence across reboots (NVRAM state corruption, functional, no direct memory unsafety: all indices stay withinmax_dpm_entries).
An ID that happens to equal entry 0's identifier is matched at every index whose phy-bits term passes, returning a wrong (but in-bounds) entry β again mapping divergence, not OOB.
Threat model / reachability
Requires DPM enabled (MaxPersistentEntries != 0) and more than one
persistent entry β ordinary legitimate configurations. Malicious firmware
amplifies it (deliberate aliasing). Hardware-gated for in-kernel
reproduction (no mps HBA on the audit guest, env.txt); the defect is
source-certain and identical to the mpr sibling already filed as DF-3916.
Fix
fix.diff β move the two PhysicalIdentifier loads inside the loop body
(braces added since the body is now two statements).
Compile-validated with the batch's other mps fixes (-Werror, mps.ko
linked β fix_build.log in DF-4085/DF-4086's packs; identical build).
DF-4087 VERDICT
Status: untested β hardware-gated (no mps HBA on the audit guest,
env.txt); Low-severity logic class, PoC skipped per batch precedent
(mpr twins DF-3916..3919). Confidence: certain (source).
- Defect:
sys/dev/raid/mps/mps_mapping.c:512-522βPhysicalIdentifierloaded from DPM entry 0 at:514-516, never re-read inside the loop at:517-522; every iteration compares the sought ID against entry 0's value whiledpm_entrywalks past it. Byte-for-byte the same defect as mpr sibling DF-3916 (mpr_mapping.c:539-566), which was filed and source-proven in the mpr pass. - Consequence: DPM lookups fail (or alias to entry 0) whenever the table has
more than one entry β duplicate DPM allocation via
_mapping_get_free_dpm_idx(mps_mapping.c:608,:1183), double-bookeddpm_entry_used[]slots, enclosure/volumedpm_entry_numdivergence (:1177-1226) β persistent mapping state corruption across reboots. All indices remain <max_dpm_entries; no OOB β impact is correctness/persistence, hence Low. - Consumers of the lookup:
_mapping_add_new_device:1179,_mapping_update_ir_missing_cnt:591β both only take the lookup result as an entry number or BAD_IDX; bounded arrays (dpm_entry_used,dpm_flush_entry,dpm_pg0walks) stay in bounds. - Fix:
fix.diffre-reads the identifier per iteration (loop body braced). Compile-validated: applied to the guest/usr/srcwith the rest of the batch's mps fixes;makeinsys/dev/raid/mpswith-Werrorlinkedmps.ko(BUILD_EXIT=0;fix_build.login the DF-4085 pack)./usr/srcrestored pristine; guest reset with clean-source snapshot.
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_testableApplied to the guest /usr/src together with this batch's other mps fixes (DF-4085..DF-4090); make in sys/dev/raid/mps compiled all sources with -Werror and linked mps.ko (BUILD_EXIT=0). Runtime fix validation not testable: the path requires an mps(4) HBA delivering firmware data, absent on this guest.
findings/poc/DF-4087/fix.diff, findings/poc/DF-4085/fix_build.log
Confirmed kernel references
Detail
Evidence (decisive lines)
VERDICT.md (line-by-line), fix.diff, fix_build.log in DF-4085 pack (same -Werror module build)
PoC changes
n/a (untested)
Verified recommended fix
Re-read PhysicalIdentifier from dpm_entry inside the per-entry loop.
Verdict
Low - PoC skipped per contract (hardware-gated logic class, mpr twin DF-3916 precedent). Source-certain: _mapping_get_dpm_idx_from_id (mps_mapping.c:512-522) loads the 64-bit PhysicalIdentifier once from DPM entry 0 and never re-reads it inside the loop, so every candidate entry is compared against entry 0's identifier; DPM lookups only ever match entry 0, all other IDs return BAD_IDX and get duplicate entries via _mapping_get_free_dpm_idx -> persistent-mapping double-booking/divergence. All indices stay < max_dpm_entries; correctness impact. Fix authored; module compile-validated with the batch.
No comments yet.