# DF-5118 — dcons_crom detach half-clears the global dcons state: `dcons_conf->dma_map` left dangling, `dcons_paddr` stale forever, re-attach can never re-wire

## Verdict: UNTESTED (needs FireWire hardware) — Info/hardening. The state-machine defect is certain in code; memory safety today is only preserved by an unrelated NULL-guard.

## Where

- `sys/dev/misc/dcons/dcons_crom.c:190-207` (`dcons_crom_detach`)
- `sys/dev/misc/dcons/dcons_crom.c:139-146` (`dmamap_cb` — the early-return and the global wiring)
- Consumers: `sys/dev/misc/dcons/dcons_os.c:176-206` (`dcons_os_getc/checkc/putc` guard every `bus_dmamap_sync` with `dg.dma_tag != NULL`; `dg.dma_map` is used *unguarded inside* those blocks)

## The defect

```c
	/* XXX */
	if (dcons_conf->dma_tag == sc->dma_tag)
		dcons_conf->dma_tag = NULL;        /* tag cleared ...      */
	                                          /* ... but dma_map NOT */
	bus_dmamap_unload(sc->dma_tag, sc->dma_map);
	bus_dmamap_destroy(sc->dma_tag, sc->dma_map);   /* map freed  */
	bus_dma_tag_destroy(sc->dma_tag);
```

After detach:

1. `dcons_conf->dma_map` is a **dangling pointer to freed map memory**, while
   `dcons_conf->dma_tag` is NULL. Today the only thing preventing a UAF is
   the `if (dg.dma_tag != NULL)` guards in dcons_os.c:176-206 — one refactor
   that reorders those checks away from a NULL tag makes every console
   getc/putc call `bus_dmamap_sync(NULL-tag, freed-map)`.
2. The module-static `dcons_paddr` (dcons_crom.c:63) is **never reset**, and
   `dmamap_cb` early-returns when it is already set (dcons_crom.c:139-143):
   a re-attach of dcons_crom (device re-added under a live firewire bus
   without module unload) skips `dcons_conf->dma_tag/dma_map = ...`
   (:144-145) entirely — the dcons core stays with `dma_tag == NULL`
   forever → `bus_dmamap_sync` coherency silently disabled — while
   `post_busreset` keeps publishing the stale `dcons_paddr` into the ROM
   (:120-121). On x86 the stale physical address happens to still denote the
   same contigmalloc'd buffer (no IOMMU translation), so it is *latent*
   rather than actively corrupting; on any translated busdma backend it
   would advertise a dead mapping.

## Fix

Clear both globals and `dcons_paddr` together in detach — fix.diff. With
`dcons_paddr = 0`, the re-attach path re-wires `dcons_conf` correctly and the
early-return retains its intended second-controller semantics.

## Why no PoC run

Requires a FireWire controller for `dcons_crom` to instantiate
(guest has none — env.txt). Pure state-machine hardening.

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