# DF-0015 — PoC

`leak_pathname.c` — unprivileged disclosure of every process's executable
path via `kern.proc.pathname.<pid>`.

## The bug

`sysctl_kern_proc_pathname()` (`sys/kern/kern_proc.c:2080-2117`) resolves and
returns the executable path of an arbitrary pid **without** the
`p_trespass`/`ps_argsopen` visibility gate that its siblings
`sysctl_kern_proc_args` (`:1897`) and `sysctl_kern_proc_cwd` (`:2052`) apply.
The `KERN_PROC_PATHNAME` node (`:2212-2214`) is `CTLFLAG_RD` (world-readable),
so any unprivileged user can read the resolved exe path of any process,
including other users' and root's.

`ps_argsopen` defaults to 1 (`kern_exec.c:103`) which *disables* the args/cwd
gate; an admin restricts inter-process visibility with `sysctl
kern.ps_argsopen=0`. That hides args/cwd but **not** pathname — proving pathname
is the lone un-gated sibling.

## Build

```
cc -o leak_pathname leak_pathname.c     # or: ./build.sh
```

## Run

As an **unprivileged** user (e.g. `maxx`):

```
./leak_pathname 1        # or: ./run.sh   (default target pid = 1 = init)
```

For the **decisive contrast** (args/cwd gated, pathname not), as root first do
`sysctl kern.ps_argsopen=0`, then run the PoC as the unprivileged user:
`kern.proc.pathname.1` returns `/sbin/init` while `kern.proc.args.1` and
`.cwd.1` return nothing.

## Expected output (bug present)

With `kern.ps_argsopen=0`:
```
kern.ps_argsopen = 0
  kern.proc.pathname  .1   : rc=0 len= 11  '/sbin/init'    <-- LEAKED (no gate)
  kern.proc.args      .1   : rc=0 len=0   (blocked/empty)  <-- gate works
  kern.proc.cwd       .1   : rc=0 len=0   (blocked/empty)  <-- gate works
  kern.proc.pathname  .699 : '/usr/sbin/sshd'              (root daemon, leaked)
  ...
```

With the default `kern.ps_argsopen=1`, all three return data (gate disabled).
On a fixed kernel, `pathname.1` is also blocked when `ps_argsopen=0`.

## Access-pattern note
These are "node-with-pid-child" sysctls; the pid is passed as a trailing MIB
element via `sysctlnametomib("kern.proc.pathname", mib, &len)` then
`mib[len]=pid`, not via the dotted `sysctlbyname("kern.proc.pathname.1")` form
(which returns `ENOENT` on DragonFly — a resolution quirk, not a privilege
control).
