# DF-5149 — pps driver has no device_detach and never destroys its cdev (DF-5006/5074/5091 teardown-gap family)

**File:** `sys/dev/misc/pps/pps.c` (pass 2)
**Severity:** Low (structural; no reachable teardown path today) · **Confidence:** certain
**Status:** not_reproduced (runtime) — see `verdict.json` / `VERDICT.md`

## What

`ppsattach()` creates `/dev/ppsN` via `make_dev()` (sys/dev/misc/pps/pps.c:103-104)
and the driver's method table has only identify/probe/attach — **no
`device_detach`** (pps.c:190-197). The cdev returned by `make_dev()` is
discarded, so no `destroy_dev()` can ever happen, and the ppbus child is
permanent.

## Why it matters

- The `/dev/ppsN` node and the pps ppbus-child are pinned for the life of
  the kernel; `kldunload` of a module-built pps is structurally blocked
  (missing DETACH → ENXIO → unload aborts before any softc free) — the same
  chicken-and-egg as DF-5074/DF-5091: non-UAF *today*, guaranteed UAF the
  day someone adds a naive detach, because an open pps owns the ppbus and a
  registered `ppsintr` (pps.c:118-133).

## Build / Run / Expected

```sh
./build.sh          # nothing to build (structural finding; sh -n syntax check)
./run.sh            # runs trigger.sh as root on the QEMU guest
```

Expected (see `run.log`): pps driver registered nowhere; no `pps.ko` in
`/boot/kernel` (only `ppbus.ko`); not in `X86_64_GENERIC`; `kldload ppbus`
attaches nothing (QEMU has no ISA parallel port) and unloads cleanly;
no `/dev/pps*`; guest stays up.

## Fix

`fix.diff` — add `ppsdetach()` that refuses to detach while `pps_open`
(EBUSY) and otherwise `destroy_dev()`s the stored cdev; store the cdev in
the softc. `git apply --check` clean against `sys/` (not applied).

## Artifacts

`trigger.sh` `build.sh` `run.sh` `build.log` `run.log` `env.txt` `fix.diff`
`manifest.json` `verdict.json` `VERDICT.md`
