# DF-3226 — /proc/pid/ctl "detach" requires no authorization: bystanders can rip a tracee out of a live tracing session

**File:** `sys/vfs/procfs/procfs_ctl.c:122-128` (authz exemption), `:197-225` (DETACH body), `:223` (wrong wakeup address)
**Severity:** Low — same-euid interference with active debuggers/tracers (CWE-862)
**Status: REPRODUCED** on DragonFly 6.5-DEVELOPMENT #0, two runs.

## What the bug is

`procfs_control()` deliberately skips the credential gate for DETACH:

```c
if (op != PROCFS_CTL_DETACH) {     /* procfs_ctl.c:122 */
    ... CHECKIO / p_trespass / securelevel checks ...
}
```

The stated intent ("allow processes to disengage debugging on a process onto
which they have previously attached, but no longer have permission to debug")
only justifies the exemption for **the tracer itself** — but the code grants
it to *anyone* who can open the ctl file (any same-euid process; mode 0200,
owner = target euid). A bystander that never attached anything can write
`"detach"` to `/proc/<victim>/ctl` and the kernel will, with no
authorization:

* clear `P_TRACED` (procfs_ctl.c:203),
* delete the victim's pending SIGTRAP (:206-208),
* reparent the victim back to `p_oppid` (:211-219),
* clear `P_WAITED` and unstop the victim (:222, :280-281),

i.e. silently terminate an *active* debugging/tracing session run by another
(same-euid, or root) tracer — the tracer's subsequent ctl ops fail EBUSY and
a root debugger (or any ptrace-based monitoring/sandbox tool holding the
session via procfs semantics) loses the tracee mid-flight.

Secondary defect on the same path: `wakeup((caddr_t) curp)` at :223 wakes a
address derived from the **detacher**, while a tracer blocked in CTL_WAIT
tsleeps on `(caddr_t) p` (:258) — a detach issued by anyone other than the
WAITer's own process never wakes the blocked tracer (it hangs until a signal
breaks the PCATCH sleep).

## Reproduced evidence (run.log)

```
[T 1101] ctl attach V(1100)
[D 1102] bystander writes detach to /proc/1100/ctl
[D] DETACH ACCEPTED with no authorization
[T] ctl step V #1 after interference: failed: Device busy
[T] ctl run V: failed: Device busy
```

Bystander D (uid 1001, never attached anything, not the tracer, not the
parent) successfully detached the victim from tracer T's live session; T's
next ctl ops fail EBUSY. Reproduced twice (run.2.log after clean-snapshot
reset).

## Files

* `df3226.c` — PoC (all processes unprivileged uid 1001)
* `run.log`, `run.2.log` — full output, two runs
* `fix.diff` — verified fix (exempt DETACH only for the current tracer
  `p->p_pptr == curp`; wake `p` not `curp`)
* `verdict.json`, `manifest.json`

## Build & run

```
cc -O -o df3226 df3226.c
./df3226
```
