As you may well be aware, ptrace can be used to observe and control processes on Linux. With the help of seccomp, this proof of concept uses this functionality to create a kind of client-server runtime.
When you run a program through this runtime, the runtime process calls fork on itself, splitting
For the child process, the following occurs:
- First, it performs a
PTRACE_TRACEMErequest. - Then it creates a
bpf(Berkeley Packet Filter) program that defines the set of "top-level" rules for the program's syscalls. - The child then ensures that the
no_new_privsbit is set to make sure that theseccompoperation performed in the next step succeeds. - It will use the BPF program create in step 2 to apply a
seccompfilter to itself. - Finally, the child calls
execveon the program to start it in the child's place.
And for the parent process, the following occurs:
- First, the parent waits for the child process to finish its startup process (see above).
- Once the child is ready, the parent then sets up its
ptraceoptions to handle theseccomptraps it will receive. This is primarily done by settingPTRACE_O_TRACESECCOMP. - Finally, the parent enters its event loop in which it:
- Waits for the child to perform a syscall, exit, etc.
- Handles that action in whatever way it sees fit. Maybe by stopping the syscall entirely, modifying the child's registers, or whatever creative idea I think would be cool.
proot-rs, a Rust implementation of a ptrace-based sandbox. Has some very interesting ideas/implementations.ptrace_syscalls, a demonstration of the capabilities of using ptrace for injection. Has some more projects that explore some more injection capabilities:havoc, a useful reference for a Rust implementation of some basic ptrace functionality.