# DF-3226 VERDICT — REPRODUCED (unauthorized detach of a live tracee by a same-uid bystander)

## Bottom line

`procfs_control()` skips ALL authorization for `PROCFS_CTL_DETACH`
(sys/vfs/procfs/procfs_ctl.c:122). Any process that can open
`/proc/<victim>/ctl` (mode 0200 → any same-euid process, or anyone holding a
pre-opened fd across the victim's cred changes) — not just the tracer — can
detach a victim from its *active* tracer: P_TRACED cleared, pending SIGTRAP
deleted, victim reparented to `p_oppid` and unstopped. The tracer (possibly
root — a debugger or a ptrace-style monitoring/sandbox session on a uid-U
victim) silently loses the tracee; its subsequent ctl operations fail EBUSY.
Demonstrated twice as uid 1001 (run.log, run.2.log).

Additionally, `wakeup((caddr_t) curp)` at procfs_ctl.c:223 uses the
**detacher's** proc pointer as the wake address while a tracer blocked in
CTL_WAIT sleeps on `(caddr_t) p` (procfs_ctl.c:258) — a third-party detach
never wakes the blocked tracer.

## Observed (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
```

D was never the tracer, never the parent, never attached anything: the write
was accepted and destroyed T's session. Same output on the second run after
a clean-snapshot reset.

## Impact

Integrity/availability of debugging and ptrace/procfs-based supervision
sessions: a malicious same-uid process can unstick a victim from analysis or
containment at will (break root-run debuggers, evade procfs-style tracing
tools). No memory corruption; no uid0 route. Low severity (same-euid scope
via the open gate), certain confidence.

## Fix

`fix.diff` (v2, the validated version): DETACH of a `P_TRACED` process is
restricted to the current tracer (`p->p_pptr == curp` — the tracer may still
disengage after privilege loss, the original intent; untraced targets keep
the harmless no-op path), mirroring `PT_DETACH` (sys_process.c:250-262), plus
the wake-address fix (`wakeup((caddr_t) p)`).

Validation note: a first fix attempt (v1, simply applying
`CHECKIO`/`p_trespass` to non-tracer DETACH — kept as `run.fixed.log`) was
**insufficient**: `CHECKIO` legitimately passes for same-uid bystanders, so
the bystander detach was still accepted. v2 (tracer-only) is what was
re-validated on a second patched kernel: bystander → `EPERM`, tracer's
session intact (`run.fixed2.log`).

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