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

_mapping_find_enc_map_space clears the WRONG enclosure entry (et_entry instead of enc_entry), off-by-one overlap test, stale num_found (mps twin of DF-3917)

Summary

During enclosure-table defragmentation: (1) the eviction path clears et_entry - the NEW enclosure being added - instead of enc_entry, the evicted overlapping one; (2) the overlap skip test treats the first slot PAST the enclosure as inside, clearing a map entry owned by the next enclosure; (3) skip_search is reset on the wrong entry and num_found is not reset before the third search loop, so start_idx undershoots the free run and the caller's reservation loop steals still-owned slots. All writes remain within the tables; the corrupted num_slots/start_slot then feed the known DF-1375 slot arithmetic. Identical defects in mpr_mapping.c (DF-3917 twin). 4-hunk fix.

Discussion (0)

No comments yet.

PoC verification

Evidence pack

findings/poc/DF-4088 Β· 6 files
FileTypeDescriptionSize
README.md β€” 3.1 KB ↓ raw
VERDICT.md β€” 2.6 KB ↓ raw
env.txt β€” 1.4 KB view raw
fix.diff β€” 1.1 KB view raw
manifest.json β€” 620 B view raw
verdict.json β€” 2.4 KB view raw

DF-4088 β€” _mapping_find_enc_map_space clears the WRONG enclosure entry (et_entry vs enc_entry), off-by-one overlap test, stale num_found

File: sys/dev/raid/mps/mps_mapping.c:743-868 Class: CWE-697 wrong variable + off-by-one + stale accumulator (mps twin of mpr sibling finding DF-3917; the mpr file mpr_mapping.c:1075-1121 carries the identical three defects line-for-line) Severity: Low β€” pass 2 (GLM 5.3), bucket base:dev Confidence: certain

The bugs

  1. Wrong variable in the eviction clear (:845-847): c if (map_idx == (enc_entry->start_index + enc_entry->num_slots - 1)) _mapping_clear_enc_entry(et_entry); /* should be enc_entry */ Inside the loop that evicts the overlapping old enclosure (enc_entry), the code clears the new enclosure being added (et_entry): zeroes its num_slots, enclosure_id, phy_bits, dpm_entry_num (= BAD). The caller (_mapping_get_dev_info:972-998) then reserves num_slots (=0) entries and stores the found start_index into the half-wiped entry, so every later _mapping_add_new_device:1165 slot computation (start_index + slot - start_slot, with start_slot also zeroed) and the DPM commit path operate on corrupted enclosure state.

  2. Off-by-one overlap test (:829-831): an enclosure owns map-table slots [start_index, start_index + num_slots); the skip test map_idx > (enc_entry->start_index + enc_entry->num_slots) treats map_idx == start+num_slots (the first slot past the enclosure) as inside, so eviction clears one map entry belonging to the next enclosure (_mapping_clear_map_entry(mt_entry) at :843).

  3. Stale accumulator (:783-820): num_found is not reset before the third (post-eviction) search loop at :809; it retains the tail count of the second loop, so start_idx = (map_idx - num_found) + 1 (:815) can point before the actually-contiguous free run β€” entries still owned by other enclosures get marked MPS_DEV_RESERVED by the caller's reservation loop (:993-998), silently stealing slots.

Impact

Mapping-table state corruption on the enclosure-defragmentation path (reachable whenever table pressure forces eviction of a missing enclosure): devices mapped into wrong/stolen slots, enclosures with zeroed metadata, removal bookkeeping (removal_table) entries for the wrong handles, DPM entries committed with wrong DeviceIndex/slot data. All writes stay within the tables (indices bounded by end_of_table <= max_devices in this function), so the direct impact is correctness/persistence, not OOB β€” it feeds the already-filed DF-1375 slot arithmetic with corrupted start_slot/num_slots, which is what keeps it security-relevant. Hardware-gated for in-kernel reproduction (env.txt).

Fix

fix.diff β€” (a) > β†’ >= in the overlap skip test; (b) clear enc_entry (not et_entry) at the last-slot eviction point; (c) reset enc_entry's (not et_entry's) skip_search flag at :862; (d) num_found = 0 before the third search loop. Compile-validated with the batch (-Werror, mps.ko linked β€” fix_build.log in DF-4085's pack).

VERDICT.md
↓ download raw

DF-4088 VERDICT

Status: untested β€” hardware-gated (no mps HBA on the audit guest, env.txt); Low-severity mapping-state-corruption class, PoC skipped per batch precedent (mpr twin DF-3917 was likewise source-only). Confidence: certain (all three defects verified line-by-line against sys/dev/raid/mps/mps_mapping.c and cross-checked to be identical in sys/dev/raid/mpr/mpr_mapping.c:1075-1121).

  • Wrong-variable clear: mps_mapping.c:847 _mapping_clear_enc_entry(et_entry) inside the enc_entry eviction loop (loop head :826-828, eviction bookkeeping :833-844). _mapping_clear_enc_entry zeroes num_slots, start_slot, enclosure_id, phy_bits, dpm_entry_num (:83-97) of the enclosure being added, while the evicted enclosure's entry is left with live start_index but its map entries cleared β€” divergence on both sides. The caller assigns et_entry->start_index = map_idx afterwards (:974), masking one symptom.
  • Off-by-one: :829-831 ownership is [start, start+num_slots) but the skip test allows map_idx == start+num_slots β†’ one map entry past the enclosure gets _mapping_clear_map_entry()'d (:838-844) β€” that entry belongs to whatever enclosure follows.
  • Stale accumulator: num_found survives from the :783-794 loop into the :809-820 loop (found_space = 0 reset at :808 but not num_found), so start_idx = map_idx - num_found + 1 (:815) undershoots the free run and the caller's reservation loop (:993-998) marks still-owned entries MPS_DEV_RESERVED.
  • Blast radius: all indices generated here remain < end_of_table ≀ max_devices (:762-767), so no OOB inside this function; the corrupted num_slots/start_slot then flow into _mapping_add_new_device:1165 (whose missing bounds are the already-filed DF-1375) and into _mapping_commit_enc_entry β€” persistence and mapping-correctness impact, Low severity on its own.
  • Fix: fix.diff (4 hunks, all inside _mapping_find_enc_map_space). Compile-validated: applied to the guest /usr/src with the rest of the batch's mps fixes; make in sys/dev/raid/mps with -Werror linked mps.ko (BUILD_EXIT=0; fix_build.log in the DF-4085 pack). /usr/src restored 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_testable
baseline no→ patch + rebuild →patched clean

Applied 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-4088/fix.diff, findings/poc/DF-4085/fix_build.log
↓ fix.diffper-fix-DF-4088

Confirmed kernel references

Detail

Evidence (decisive lines)

VERDICT.md (line-by-line + mpr:1075-1121 cross-check), fix.diff (4 hunks), fix_build.log in DF-4085 pack

PoC changes

n/a (untested)

Verified recommended fix

Clear enc_entry (not et_entry) at the eviction point, use >= in the overlap skip test, reset enc_entry->skip_search, and zero num_found before the post-eviction search loop.

Verdict

Low - PoC skipped per contract (hardware-gated logic class, mpr twin DF-3917 precedent). Source-certain triple defect in _mapping_find_enc_map_space: (1) :847 clears the NEW enclosure (et_entry) instead of the evicted overlapping one (enc_entry) during table defragmentation; (2) :829-831 overlap test is off by one (map_idx > start+num_slots lets the first slot PAST the enclosure be evicted/cleared); (3) :862 resets et_entry->skip_search where enc_entry's flag was set at :802, and num_found is stale (not reset at :808) so the third search loop's start_idx undershoots the free run. Net: enclosure metadata zeroed, map slots stolen from neighbor enclosures, corrupted num_slots/start_slot feed the known DF-1375 slot arithmetic. All writes stay within the tables. Fix authored; module compile-validated with the batch.