Skip to main content

Module direct

Module direct 

Source
Expand description

Handlers for the syscalls that take a ptrace stop when ptrace is available, served through user notification when it is not.

A notification cannot change registers, only answer the syscall, let it continue, or install a descriptor into the tracee. Three tricks cover the former ptrace tier:

  • chdir, fchdir and chroot are answered without running: the working directory is virtual (procs), every path handler resolves relative paths against it, and the kernel’s own cwd of every tracee stays pinned to the alias directory.
  • connect and bind are performed by the supervisor on a socket of the same type and flags, which then replaces the tracee’s descriptor through ADDFD with SETFD.
  • execve, inotify_add_watch and O_PATH opens must run in the tracee with a different path. The path string is overwritten in place, through /proc/<pid>/mem, with a name of one or two bytes that resolves inside the alias directory, which the kernel cwd makes reachable from any process: e is the exec trampoline (see exec::shim) and a transient one-character symlink stands for any other host path. A symlink to be reached by a bare name, which no <alias>/<name> fits, is reached through a hard link to it instead, the same inode. The syscall then continues. Once the task has consumed the argument, the original bytes are put back, but only when the memory still holds exactly what was written: a buffer may have been freed or reused by then, and must not be touched if so.

clone and its relatives are notified only to snapshot the parent’s state for the child, see procs.

In the guest-stub restricted mode (see guest_stub) the strings these handlers rewrite are the stub’s copies in the mailbox, with room for any host path, so the full host path is written and nothing is put back. An exec is planned from the staged copy and answered with the mailbox descriptor installed for the trampoline, which the stub then execs itself.

Structs§

Placed 🔒
A transient alias in place: the bytes that replace the tracee’s string, and the hard link to remove once the syscall has consumed them.

Enums§

Form 🔒
How a transient alias stands for its target.

Constants§

ALIAS_CHARS 🔒
Characters available for transient alias names; e and r are the trampoline and its records.
CLONE_THREAD 🔒
CLONE_THREAD: the new task shares the process, nothing to inherit.
CLONE_VFORK 🔒
CLONE_VFORK: the child shares the parent’s memory until it execs.
RESTORE_TIMEOUT 🔒
Longest wait for a continued syscall to return before restoring anyway.
SETTLED_CPU 🔒
CPU time a resumed task must have run for its syscall to be past the argument copy and the path walk, with a wide margin over the microseconds those take.

Statics§

ALIASES 🔒
Which names are in use, and where the next search starts: names are handed out round-robin so a name just released is not re-pointed while the kernel may still be walking through it.
STAGING 🔒
Directories holding hard links to symlinks, one per mount reached so far.

Functions§

acquire_alias 🔒
Takes a free one-character alias name, the least recently handed out.
binfmt_misc_matches 🔒
Whether a registered binfmt_misc handler would run a file we do not recognize, by the same magic or extension test the kernel applies.
check_executable 🔒
Refuses a plan the kernel would refuse, with the kernel’s errno.
check_loadable 🔒
Refuses, in the guest-stub mode, a plan the trampolines’ loaders cannot carry out, and tells which trampoline loads the rest. Besides what the kernel refuses (see check_executable) that is a format only binfmt_misc would run, and a 32-bit program where the i386 trampoline cannot run (a kernel without ia32 emulation). A nested launch, which the trampoline sets up first, is only classified.
commit_trapped 🔒
Writes the trampoline’s record for a planned exec in the guest-stub mode and marks the process as about to run it.
cpu_time 🔒
CPU time thread tid has run, in nanoseconds, from /proc/<tid>/schedstat.
dispatch
Routes a former trace-tier syscall to its handler; None for any other.
do_chroot 🔒
chroot: the guest root is a no-op, anything else is refused as it would be for an unprivileged process.
do_clone
clone/fork/vfork/clone3: refuse a new namespace, snapshot the parent for the child without ptrace, then continue.
do_execve 🔒
execve/execveat through the trampoline.
do_execve_trapped 🔒
execve/execveat in the guest-stub restricted mode.
do_inotify_add_watch 🔒
inotify_add_watch: the watch goes on the tracee’s own descriptor, so the path is rewritten to a transient alias, which the tracee then walks.
do_open_path
An O_PATH open without ptrace.
do_sockaddr 🔒
connect/bind on an AF_UNIX path, done on a replacement socket.
do_socketcall
socketcall(call, args) from an i386 tracee: bind (2) and connect (3).
hello
Answers the trampoline’s layout::HELLO: the exec planned for the process has happened, so it now runs the program, in the view the plan named.
io_errno 🔒
The errno of an I/O error, EIO for one without.
kernel_walks_alike 🔒
Whether the kernel, walking path from the tracee’s dirfd by itself, reaches host.
link_nofollow 🔒
linkat without AT_SYMLINK_FOLLOW: a hard link to host itself, a symlink included.
open_host 🔒
Opens a host path for injection.
place_alias 🔒
Places the alias name for host so that its path fits in room bytes, the tracee’s string and its NUL.
plan_first_trapped
Plans the first tracee’s exec in the guest-stub restricted mode, which the supervisor itself sets up rather than a stub: the tracee execs the trampoline through the allow gate with the mailbox it inherited.
ptrace_usable
Whether ptrace can be used from here.
readlink_alias_fd
readlinkat with an empty path on a descriptor opened through a hard link alias: the answer comes from the descriptor’s own inode, reopened through /proc, since the link it was opened by is gone by then and its name may stand for something else.
readlink_reopened 🔒
Reads the target of the symlink a /proc/<pid>/fd/N link leads to, by reopening it O_PATH here, which lands on that inode whether or not its name still exists.
release_alias 🔒
Returns an alias name to the pool. The symlink stays until the name comes round again.
remove_staging
Removes the staging directories, at exit.
restore_if_intact 🔒
Puts orig back at addr in process pid if the memory still holds exactly the rewrite, i.e. written followed by the rest of orig.
retry 🔒
Runs a lookup again while it finds a symlink swapped in since the walk.
rewrite_staged 🔒
Replaces a path the guest stub staged with its host path and lets the syscall continue on it.
set_cwd 🔒
Moves the virtual working directory to path, with chdir’s own checks.
shim_passthrough
Lets the trampoline’s own syscalls through untranslated.
socket_description 🔒
Type and descriptor flags of a tracee’s unix socket.
stage_hard_link 🔒
Makes a hard link named name to host in a staging directory on its mount, creating one under the first of candidates that allows it.
staging_candidates 🔒
Where a staging directory may be created, in order: the user’s cache directory, beside the rootfs, and the temporary directory.
transient_rewrite 🔒
Rewrites a path string in the tracee to a transient alias, continues the syscall, and puts the string back once the syscall has consumed it.
under_alias 🔒
Whether host lies in the alias directory or a staging directory.
unstage 🔒
Removes the hard link an alias was placed through, once the syscall has consumed the rewritten path; a descriptor opened through it keeps the inode.
wait_syscall_consumed 🔒
Waits until the continued syscall has consumed its rewritten argument.