# DF-4438 VERDICT

**Status:** inconclusive (kernel-path reproduction impossible on this guest: no
LSI/Avago MR controller present) · **Logic-flaw proof:** certain · **Impact if
triggered:** kernel heap double-free (M_CAMSIM) + UAF read + CAM bus/devq state
corruption at driver-attach failure.

## Root cause, traced line by line

1. `mrsas_attach()` calls `mrsas_cam_attach(sc)` — `sys/dev/raid/mrsas/mrsas.c:805`.
   On failure it goes to `attach_fail_cam:` (`mrsas.c:838-839`) which calls
   **`mrsas_cam_detach(sc)`** — the same teardown used for a *successful* attach.

2. Inside `mrsas_cam_attach()` (`sys/dev/raid/mrsas/mrsas_cam.c:116-201`), four
   internal failure paths free the SIM objects *themselves* and return failure:

   - `:150-156` — `xpt_bus_register(sc->sim_0, 0)` fails →
     `cam_simq_release(devq); cam_sim_free(sc->sim_0);` → return `ENXIO`.
   - `:157-165` — `xpt_create_path(&sc->path_0, ...)` fails →
     `xpt_bus_deregister(cam_sim_path(sc->sim_0)); cam_simq_release(devq);
     cam_sim_free(sc->sim_0);` → return `ENXIO`.
   - `:181-185` — `xpt_bus_register(sc->sim_1, 1)` fails →
     `cam_sim_free(sc->sim_1);` → return `ENXIO`.
   - `:186-193` — `xpt_create_path(&sc->path_1, ...)` fails →
     `xpt_bus_deregister(cam_sim_path(sc->sim_1)); cam_sim_free(sc->sim_1);`
     → return `ENXIO`.

   None of them clears `sc->sim_0` / `sc->sim_1`.

3. `cam_sim_free()` in DF is terminal: `sys/bus/cam/cam_sim.c:229-231` →
   `cam_sim_release(sim, CAM_SIM_SOFTC)` at `:234-251`; with `refcount == 1`
   (`:238`) it drops the sim's devq reference and **`kfree(sim, M_CAMSIM)`**
   (`:243-249`). The softc pointer now dangles.

4. The caller unwind then runs `mrsas_cam_detach()` (`mrsas_cam.c:209-227`):
   - `:217` `xpt_bus_deregister(cam_sim_path(sc->sim_0))` — `cam_sim_path()` is a
     plain `sim->path_id` dereference of **freed memory** (UAF read), and the bus
     is deregistered a second time (or, on path (1), was never registered —
     `xpt_bus_deregister` of an unknown path corrupts/double-unlinks CAM bus
     bookkeeping).
   - `:218` `cam_sim_free(sc->sim_0)` — **double free** into `M_CAMSIM`, plus a
     second `cam_simq_release(sim->devq)` → devq refcount underflow → premature
     `cam_devq` free while other sims/CAM still reference it.

   Same for `sc->sim_1` at `:222-224` for failure paths (3)/(4).

## Reachability / threat

Requires `mrsas(4)` attach to fail after `cam_sim_alloc` — i.e. an LSI Thunderbolt
MR controller present **plus** kernel memory pressure / CAM resource exhaustion at
boot or card hot-plug (`xpt_bus_register`/`xpt_create_path` ENOMEM-class failures).
Not directly attacker-triggerable without those preconditions, hence **Low**; the
consequence is kernel heap corruption in `M_CAMSIM` (double free) and CAM-layer
state corruption — panic at minimum, in principle a heap-manipulation primitive.

## Evidence

- `repro_logic.c` + `build.sh` + `run.sh` — userspace mirror of the exact kernel
  choreography, **compiled and executed on the DragonFly guest** (`run.log`):
  buggy (current-kernel) sequence flags `sim UAF: cam_sim_path() on freed cam_sim`
  and `sim DOUBLE FREE: cam_sim_release()/kfree() on already-freed cam_sim`;
  fixed sequence (`sc->sim_0 = NULL` after error-path free) is clean. `cc 8.3
  [DragonFly]` produced no warnings.
- `env.txt` — guest `uname`, `pciconf` shows **no vendor-1000 (LSI) devices**, no
  `/dev/mrsas*`, no `hw.mrsas` sysctl node ⇒ kernel-path reproduction is
  impossible on this guest; the finding rests on the (deterministic, single-threaded,
  attach-context) call-sequence proof above.

## Fix validation

Not kernel-testable on this guest (no mrsas hardware; fix validation requires
building a kernel with the mrsas driver and attaching a device that fails
registration). The mirror's `fixed` mode demonstrates the fix removes both
violations. `fix.diff` authored against the read-only tree; never applied to `sys/`.

## Fix summary

Clear `sc->sim_0`/`sc->sim_1` after error-path `cam_sim_free()` (and NULL them in
`mrsas_cam_detach()` after freeing) so `mrsas_attach`'s unwind via
`mrsas_cam_detach` cannot re-free; also drop the caller's devq reference on the
`sim_1`-alloc-failure path (currently a leak, in dead code since `cam_sim_alloc`
uses `M_INTWAIT`).

## 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.
