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

tws_cam_attach error symmetry: missing return after cam_sim_alloc failure -> xpt_bus_register(NULL) NULL-deref panic at attach; sc->sim left dangling/registered on later failure paths

Summary

cam_sim_alloc failure is logged but not returned; execution continues to xpt_bus_register(NULL) which immediately writes sim->bus_id - NULL panic under memory pressure. The bus_register failure NULLs sc->sim but the create_path failure frees the sim WITHOUT NULLing it (latent double-free for later detach), and the scan failure leaks the registered bus/SIM. Return+NULL+unwind fix.

Discussion (0)

No comments yet.

PoC verification

Evidence pack

findings/poc/DF-4402 Β· 6 files
FileTypeDescriptionSize
README.md β€” 1.9 KB ↓ raw
VERDICT.md β€” 2.0 KB ↓ raw
trigger.c β€” 547 B view raw
fix.diff β€” 1.0 KB view raw
verdict.json β€” 2.2 KB view raw
env.txt β€” 541 B view raw

DF-4402 β€” tws_cam_attach() error symmetry: missing return after cam_sim_alloc failure, dangling sc->sim

What

sys/dev/raid/tws/tws_cam.c:136-202 (tws_cam_attach):

  1. Missing error return (boot-time NULL deref): c sc->sim = cam_sim_alloc(...); cam_simq_release(devq); if (sc->sim == NULL) { tws_log(sc, CAM_SIM_ALLOC); /* logged... and falls through! */ } lockmgr(&sc->sim_lock, LK_EXCLUSIVE); if (xpt_bus_register(sc->sim, 0) != CAM_SUCCESS) { /* sc->sim == NULL */ On allocation failure the driver registers a NULL SIM. xpt_bus_register() dereferences sim immediately (sys/bus/cam/cam_xpt.c:4304 sim_lock_assert_owned(sim->lock) β†’ sim->lock on NULL; :4306 sim->bus_id = bus write through NULL) β†’ NULL-pointer kernel panic during attach. Reachable under memory pressure at boot/driver-load.

  2. Dangling sc->sim on the xpt_create_path failure path (latent double-free): the xpt_bus_register failure path NULLs sc->sim (:180) but the xpt_create_path failure path (:185-193) frees the sim (cam_sim_free(sc->sim)) without NULLing it β€” any later tws_cam_detach() (:211-214, xpt_bus_deregister + cam_sim_free again) would double-free / UAF. Today tws_attach's attach_fail_4 (tws.c:309-316) happens not to call tws_cam_detach, so this half is latent β€” but it is exactly the asymmetry that turns any future caller into a double free.

  3. tws_bus_scan failure leaks the registered bus/SIM (:194-198 returns error without deregistration).

Impact

(1) is a denial-of-service (kernel panic) gated on cam_sim_alloc failing β€” memory pressure during device attach. (2)/(3) are error-path hygiene with latent UAF potential. Low severity: attach-time, resource-pressure-gated.

Status

Cannot be exercised on the audit guest (no 3ware HBA); (1) proven by xpt_bus_register's immediate dereference β€” see VERDICT.md.

VERDICT.md
↓ download raw

VERDICT β€” DF-4402

Status: inconclusive (hardware-gated attach path).

Proof

  1. tws_cam_attach (tws_cam.c:167-175): c sc->sim = cam_sim_alloc(tws_action, tws_poll, "tws", sc, ..., devq); cam_simq_release(devq); if (sc->sim == NULL) { tws_log(sc, CAM_SIM_ALLOC); } /* no return! */
  2. Execution continues to xpt_bus_register(sc->sim, 0) (:178) with sc->sim == NULL. xpt_bus_register (sys/bus/cam/cam_xpt.c:4298-4306) first executes sim_lock_assert_owned(sim->lock) β€” a NULL deref read on INVARIANTS builds β€” and unconditionally sim->bus_id = bus (:4306) β€” a NULL-pointer write on production builds. Kernel panic at attach.
  3. Asymmetry evidence: the bus-register failure path knows the correct pattern β€” cam_sim_free(sc->sim); sc->sim = NULL; (:179-180) β€” while the create-path failure path (:188-190) and bus-scan failure path (:194-198) omit it, leaving sc->sim dangling/registered respectively.
  4. tws_cam_detach (:204-216) calls xpt_bus_deregister(cam_sim_path(sc->sim)) and cam_sim_free(sc->sim) guarded only by if (sc->sim) β€” a stale non-NULL pointer double-frees.

Trigger

Boot or kldload the driver when kernel memory is exhausted enough for cam_sim_alloc (kmalloc of struct cam_sim) to fail. Not reproducible on the audit guest (no 3ware PCI device β†’ probe never succeeds).

Impact ceiling

Panic at attach (DoS); latent double-free in detach if any future caller invokes tws_cam_detach after a partially-failed attach. Severity Low (requires allocation failure at attach; boot-time/privileged context).

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

fix.diff adds the missing return and symmetric cleanup; not validatable on the guest (no controller, no controllable kmalloc failure at attach).

fix.diff
↓ fix.diffper-fix-DF-4402

Confirmed kernel references

Detail

Evidence (decisive lines)

VERDICT.md; fix.diff (return ENOMEM; NULL sc->sim on both failure paths; unwind on scan failure); trigger.c (reproduction conditions)

PoC changes

no seed; conditions stub only

Verified recommended fix

Return ENOMEM immediately when cam_sim_alloc fails; NULL sc->sim after cam_sim_free on every failure path; unwind registration on bus-scan failure.

Verdict

Certain from source. tws_cam_attach logs but does not return on cam_sim_alloc failure (tws_cam.c:173-175), then calls xpt_bus_register(sc->sim==NULL) at :178 β€” xpt_bus_register immediately dereferences sim (sim->lock assert, then sim->bus_id = bus write at sys/bus/cam/cam_xpt.c:4304-4306) -> NULL-pointer write/panic during attach under memory pressure. Additionally the xpt_create_path failure path frees the sim without NULLing sc->sim (:185-193, contrast :180), leaving a latent double-free for any later tws_cam_detach (:211-214), and the tws_bus_scan failure path leaks the registered bus/SIM (:194-198). Hardware-gated: guest has no 3ware HBA.