# DF-2706 — `kern.proc.pid.<pid>` bypasses `security.ps_showallprocs=0`

Unprivileged local information disclosure / authorization bypass in
`sysctl_kern_proc()` (sys/kern/kern_proc.c).

## Build

On the guest (any user):

    cc -O -o /tmp/pidsnoop /tmp/pidsnoop.c

## Run

Root prepares a root-owned marker process and turns the visibility knob off:

    cp /bin/sleep /tmp/snoopmark && chmod 700 /tmp/snoopmark
    nohup /tmp/snoopmark 600 &            # uid-0 process, pid noted
    sysctl security.ps_showallprocs=0

Unprivileged user runs the A/B/C contrast:

    /tmp/pidsnoop <root-pid>   # [A] kern.proc.pid.<pid>  (raw-MIB form)
    /tmp/pidsnoop -all         # [B] kern.proc.all        (gated path)
    /tmp/pidsnoop -uid 0       # [C] kern.proc.uid.0      (gated path)

## Expected output (vulnerable kernel)

    [A] kern.proc.pid.<pid> -> 1 record(s)
        pid=<pid> ppid=1 uid=0 pgid=.. sid=.. comm="snoopmark"
        kp_paddr (kernel heap ptr) = 0xfffff8..          <-- BYPASS
    [B] kern.proc.all       -> 3 record(s)   (only the caller's own)
    [C] kern.proc.uid.0     -> 0 records

[A] returning the full struct kinfo_proc of a uid-0 process (including the
raw kernel-heap pointer `kp_paddr`) while [B]/[C] correctly hide it proves
the KERN_PROC_PID fast path skips the `ps_showallprocs`/`p_trespass()` gate
that all sibling selectors enforce.

## Root cause

sys/kern/kern_proc.c:1686-1694 — the `oid == KERN_PROC_PID` fast path only
applies `PRISON_CHECK(cr1, crcache)` (jail boundary), then calls
`sysctl_out_proc()` unconditionally. The main enumeration loop applies the
visibility gate at kern_proc.c:1715-1721
(`ps_showallprocs == 0 → p_trespass(cr1, crcache) → continue`), and
KERN_PROC_PGRP/TTY/UID/RUID all flow through it; only KERN_PROC_PID dodges
it. Reachability of the branch with an arbitrary trailing pid component is
provided by kern_sysctl.c:1476-1478, which forwards trailing MIB components
to a node handler (`sysctlnametomib("kern.proc.pid")` + append pid; the
string form `kern.proc.pid.<pid>` does not name-resolve — that is why
`sysctl(8)` alone does not expose it, but any C program trivially does).
