mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-08-31 14:04:27 -04:00
binfmt_misc: document loader substitution
Describe the L mode next to the transparent one. Link: https://patch.msgid.link/20260721-work-bpf-binfmt_misc-ptinterp-v2-21-e57866e4ae0f@kernel.org Signed-off-by: Christian Brauner (Amutable) <brauner@kernel.org>
This commit is contained in:
@@ -260,6 +260,53 @@ direct execution is the address space layout. The interpreter occupies
|
||||
the main-image position and the program lives in the mmap region.
|
||||
|
||||
|
||||
Loader substitution
|
||||
-------------------
|
||||
|
||||
The ``L`` flag turns the execution model around. Instead of running the
|
||||
registered interpreter with the binary as its payload the kernel loads
|
||||
the matched binary itself as the main image and substitutes the registered
|
||||
interpreter for the loader named in the binary's ``PT_INTERP``.
|
||||
|
||||
Because the exec is native, there is no dispatch identity to
|
||||
reconstruct and no contract the substitute has to implement. A stock
|
||||
dynamic loader works unchanged. The argument vector is untouched,
|
||||
credentials and ``AT_SECURE`` derive from the binary, there is no
|
||||
``AT_EXECFD`` and no marker in the aux vector, the binary sits in the
|
||||
main-image slot with the native brk placement so ``/proc/pid/maps``,
|
||||
core dumps and perf mmap records have the native shape, and the
|
||||
identity is already complete when ``PTRACE_EVENT_EXEC`` stops the
|
||||
tracee. So launching under a debugger works, not just attaching. ``L``
|
||||
entries are for ELF binaries of a native architecture. Foreign-arch
|
||||
emulation and non-ELF payloads remain the domain of the classic and
|
||||
transparent modes.
|
||||
|
||||
The override applies when the format that finally claims the file is
|
||||
ELF with a ``PT_INTERP``. A matched binary without one or an
|
||||
interpreter-less ``ET_DYN`` drops the override and runs natively. A file
|
||||
claimed by another format - a ``#!`` script, say - is handled by that
|
||||
format as if the entry had not matched. ``L`` is therefore not an
|
||||
enforcement mechanism: it decides how a binary that asks for a loader is
|
||||
run, it does not guarantee that everything matching the entry runs under
|
||||
the substitute. A format that cannot consume the override at all instead
|
||||
refuses the exec with ``ENOEXEC`` before the point of no return.
|
||||
|
||||
A wrong-architecture ELF fails the whole exec with ``ENOEXEC`` exactly
|
||||
as if no entry had matched. A substitute that is not ELF of the right
|
||||
architecture fails with ``ELIBBAD``. The usual ``PT_INTERP`` sanity
|
||||
checks on the binary still apply. But the segment's content is otherwise
|
||||
irrelevant.
|
||||
|
||||
``L`` rejects the classic-dispatch flags ``T``, ``P``, ``O`` and ``C``
|
||||
at registration. ``F`` composes and is valuable: with it the substitute
|
||||
is opened at registration time, so later mount namespace or path changes
|
||||
cannot redirect it. Without it the substitute is opened when the binary
|
||||
is executed, and the path is resolved in the mount namespace and root of
|
||||
whoever runs the binary, which is why it has to be absolute. As with
|
||||
``C``, register only trusted interpreters. The substituted loader runs
|
||||
with credentials derived from the binary.
|
||||
|
||||
|
||||
Hints
|
||||
-----
|
||||
|
||||
|
||||
Reference in New Issue
Block a user