# DF-0911 — procfs ATTACH skips saving p_oppid for already-owned children; DETACH orphans

## What the bug is

`procfs_control()` in `sys/vfs/procfs/procfs_ctl.c` is the procfs equivalent
of `ptrace(2)` for the `/proc/<pid>/ctl` file (write `"attach"`, `"detach"`,
etc). The ATTACH path looks like this:

```c
p->p_flags |= P_TRACED;
p->p_xstat = 0;
if (p->p_pptr != curp) {        /* procfs_ctl.c:153 */
    p->p_oppid = p->p_pptr->p_pid;
    proc_reparent(p, curp);
}
proc_stop(p, SSTOP);
```

When the tracer is **already** the real parent of the target (`p->p_pptr ==
curp` — the normal case for a tracer that `fork()`s the child and then
attaches), the body of the `if` is skipped, so `p_oppid` is **never saved**
and stays at its default `0`.

On the matching DETACH:

```c
if (p->p_oppid != p->p_pptr->p_pid) {   /* procfs_ctl.c:211 */
    pp = pfs_pfind(p->p_oppid);         /* pfs_pfind(0) -> &proc0 */
    if (pp) {
        proc_reparent(p, pp);           /* child is handed to proc0 */
        pfs_pdone(pp);
    }
}
p->p_oppid = 0;
```

`pfs_pfind(0)` returns `&proc0` (the kernel swapper), so the child is
reparented to `proc0`. The original parent can no longer `wait(2)` on the
child (`ECHILD`), and the child's `getppid()` returns `0`.

Compare to the `ptrace(2)` syscall path in `sys/kern/sys_process.c` which
**always** saves `p_oppid` (lines 306 for `PT_TRACE_ME`, 314 for
`PT_ATTACH`). The procfs path is inconsistent with the syscall path.

## How to reproduce (unprivileged)

`maxx` (uid 1001) forks a child, ATTACHes and DETACHes via
`/proc/<child>/ctl`:

```
./build.sh
./run.sh
```

Expected output on the **buggy** kernel:

```
[parent] before attach: child ppid=<P>
[parent] wrote 'attach' (6 bytes) to /proc/<C>/ctl
[parent] wrote 'detach' (6 bytes) to /proc/<C>/ctl
[parent] after detach:  child ppid=0
RESULT: BUG REPRODUCED -- child orphaned to proc0 (ppid=0) after procfs attach/detach
waitpid(<C>)=-1 errno=10 (ECHILD)
```

On the **fixed** kernel:

```
[parent] after detach:  child ppid=<P>           # parent unchanged
RESULT: not reproduced -- child ppid after detach is non-zero
waitpid(<C>)=0 errno=0
```

## Files

- `df0911.c` — minimal trigger (fork, attach via procfs ctl, detach, observe ppid/waitpid)
- `ptrace_control.c` — control test using `ptrace(2)` PT_ATTACH/PT_DETACH (correct path)
- `build.sh` / `run.sh` — exact build & run
- `build.log` — trigger build output
- `run.log` — baseline (#0) run output (buggy)
- `fix_run.log` — patched (#1) kernel run output (fixed)
- `fix_build.log` — full `make nativekernel` log
- `fix.diff` — git-apply-able one-line-fix diff
- `env.txt` — guest environment
- `VERDICT.md` — full narrative analysis
- `manifest.json` — artifact catalog
