Skip to main content

Module access

Module access 

Source
Expand description

How the supervisor gets the right to reach its tracees.

Both modes need the kernel’s ptrace access check to pass towards every tracee: the tracer for PTRACE_SEIZE, the no-ptrace mode for process_vm_readv and /proc/<pid>/mem. Yama’s ptrace_scope of 2 grants that only to a holder of CAP_SYS_PTRACE in the tracee’s user namespace, so where the plain check is refused the first tracee is moved into a user namespace of its own, which the supervisor owns from outside and therefore holds every capability in. The namespace maps the caller’s own uid and gid onto themselves and nothing else.

Where neither ptrace nor a user namespace works (the common Kubernetes case), the guest-stub restricted mode (see guest_stub) needs no access to a guest’s memory at all: a stub inside each guest process moves the memory a served syscall uses into a mailbox both sides map. It is the fallback on x86_64 and aarch64, ruled out by PROOT_GUEST_STUB=0.

The choice is made empirically: a child is forked and the supervisor tries the accesses it will need on it, first as it is, then inside a user namespace. A host where neither works (Yama 3, an LSM policy, a profile that also filters unshare) falls back to the guest stub, or where that is unavailable or ruled out gets an error instead of a guest that hangs.

Structs§

Access
What the probe settled on.
Trial 🔒
Outcome of one probe child.
UserNs
Everything the first tracee needs to enter its user namespace, prepared before fork so the child does not allocate.

Statics§

MARKER 🔒
A value the probe reads back from the child’s copy of the supervisor’s memory, proving the read reached it.

Functions§

probe
Decides how the supervisor reaches its tracees.
read_marker 🔒
Reads MARKER from the child the way the notification handlers will: process_vm_readv, or /proc/<pid>/mem where that is filtered.
refusal 🔒
Builds the message for a host where no plan reaches a child.
seize 🔒
Seizes the probe child; it is killed right after, which ends the trace.
trial 🔒
Forks a child that waits, tries the supervisor’s accesses on it, and kills it.
write_file 🔒
Writes text to the file at path. Allocation free.