| #
b9cba7eb |
| 17-Aug-2026 |
Linus Torvalds <torvalds@linux-foundation.org> |
Merge tag 'vfs-7.3-rc1.binfmt' of git://git.kernel.org/pub/scm/linux/kernel/git/vfs/vfs
Pull binfmt updates from Christian Brauner: "This contains a bunch of work for binfmt_misc. It fixes a bunch
Merge tag 'vfs-7.3-rc1.binfmt' of git://git.kernel.org/pub/scm/linux/kernel/git/vfs/vfs
Pull binfmt updates from Christian Brauner: "This contains a bunch of work for binfmt_misc. It fixes a bunch of old bugs, reworks the locking, and then extends the format registry so a binary type can be matched programmatically and its interpreter computed per exec instead of being a fixed string recorded at registration time.
This allows nixos and other to e.g., implement relocatable binaries meaning the interpreter/dynamic loader can be determined programatically, say found relative to the binary. The mechanism is flexible and can support other policies:
- Handler lookup is now an rcu walk. An exec that matches no binfmt_misc entry should now never write to a shared cacheline
- remove the VERBOSE_STATUS and USE_DEBUG compile time toggles
- convert the entry file to a seq_file which simplifies things quite a bit and kills a lot of custom logic
- make flags proper enums
- rename struct Node to binfmt_misc_entry
- allow entries to be removed with unlink(2)
- Add the ability to attach bpf programs to binfmt_misc entries so it's possible to dynamically choose the execution environment such as the loader or interpreter on a per binary basis.
A handler is an instance of a binfmt_misc_ops struct_ops with a ->match() and a ->load() program. match() decides from the entry lookup walk whether the handler applies under the same registration-order. It can read file content as needed not only the prefetched 256 bytes in bprm->buf.
load() then selects the interpreter and stages it through the new bpf_binprm_set_interp(), bpf_binprm_set_interp_arg() and bpf_binprm_set_flags() kfuncs.
Handlers are published in a registry keyed by the registering task's user namespace and activated through the existing text interface with a new 'B' type carrying the handler name:
echo ':origin:B::::nix:' > /proc/sys/fs/binfmt_misc/register
The permission and namespacing model is unchanged. Activating a handler requires the same write access to an instance as any other registration. A container mounting its own instance escapes the host's entries exactly as before. The computed interpreter is opened with open_exec() under the caller's credentials and goes through full LSM vetting as the next binprm level. A program can only ever redirect the caller to something the caller could exec anyway.
- Two dispatch modes are added. So far the chosen interpreter owns the whole process identity (argv[0], /proc/pid/cmdline, /proc/self/exe all name interpreter information). So relocatable find the dynamic linker instead. Also a binary passed to execveat() as an inaccessible O_CLOEXEC fd cannot run at all and gdb trips because AT_ENTRY and AT_PHDR do not match the exe file. So PIE symbols are unrelocated.
This adds transparent dispatch which allows the interpreter to load the binary through AT_EXECFD and leaves the argument vector exactly as the caller built it and labels mm->exe_file and comm with the binary. It also raises the AT_FLAGS_TRANSPARENT_INTERP aux vector bit. The interpreter keeps control of mapping the binary.
The second mode is loader substitution. This allows a binary to be executed natively and only the interpreter to be changed.
- Last, interpreters can be bound at registration time. Each interpreter is opened by its own write with the credentials the entry file was opened with. The program picks one per exec with bpf_binprm_select_interp().
Ucounts are used to properly account for pre-opened interpreters via /proc/sys/user/max_binfmt_misc_interpreters"
* tag 'vfs-7.3-rc1.binfmt' of git://git.kernel.org/pub/scm/linux/kernel/git/vfs/vfs: (63 commits) binfmt_misc: document the pre-opened interpreter limit selftests/exec: test the pre-opened interpreter limit binfmt_misc: correctly account pre-opened interpreters binfmt_misc: document interpreters bound by a 'B' entry selftests/exec: test interpreters bound to a 'B' entry binfmt_misc: let a 'B' entry bind its interpreters binfmt_misc: carry pre-opened interpreters in struct binfmt_misc_interp selftests/exec: share the bpf handler preconditions binfmt_misc: document registering an entry disabled selftests/exec: test registering an entry disabled selftests/exec: let binfmt_flag_supported() return a bool selftests/exec: check that a binfmt_misc instance cannot be pinned binfmt_misc: let a register string create an entry disabled binfmt_misc: document loader substitution selftests/exec: test binfmt_misc loader substitution binfmt_misc: let a bpf handler request loader substitution binfmt_misc: add the 'L' loader substitution flag binfmt_elf_fdpic: consume a stashed PT_INTERP substitute binfmt_elf: consume a stashed PT_INTERP substitute exec: carry a PT_INTERP substitute in struct linux_binprm ...
show more ...
|
| #
e98067e7 |
| 31-Jul-2026 |
Christian Brauner <brauner@kernel.org> |
Merge patch series "binfmt_misc: bind interpreters to a bpf-backed entry"
Christian Brauner <brauner@kernel.org> says:
binfmt_misc: bind interpreters to a bpf-backed entry
A 'B' entry's load progr
Merge patch series "binfmt_misc: bind interpreters to a bpf-backed entry"
Christian Brauner <brauner@kernel.org> says:
binfmt_misc: bind interpreters to a bpf-backed entry
A 'B' entry's load program hands the kernel an absolute path and open_exec() resolves it at exec time in the mount namespace of whoever runs the binary. So the handler names an interpreter but never gets to say which file that is. Whoever controls the filesystem view of the exec does.
Static entries have had the answer for a while. 'F' opens the file at registration and every exec runs a clone of it. I can't just reuse it as it stands. It pre-opens the one interpreter named in the register string and a 'B' entry has no fixed interpreter. The program picks per exec, and a qemu-user shaped handler wants one per guest architecture. So it may want a whole set of them and that doesn't fit in a register string.
An entry is matchable the moment it is registered, so everything it needs has to fit in that one write. Patch 1 adds a 'D' flag that creates the entry disabled and splits a registration into create and activate:
echo ':qemu:B::::qemu_user:D' > register echo '+aarch64 /usr/bin/qemu-aarch64' > qemu echo '+arm /usr/bin/qemu-arm' > qemu echo 1 > qemu
Each path is opened by its write, with the credentials the entry file was opened with. Same open_exec() call, same place as 'F'. The program picks one per exec with bpf_binprm_select_interp() and gets a clone of the file. Nothing is resolved again, in any namespace.
A 'D' entry simply isn't hashed until that first '1', so the rcu insertion that publishes the entry also publishes its interpreters and the exec side needs no barriers. Reading the entry file doesn't take any locks either. Bindings are rcu-published and the open file already pins everything the read looks at. We use paths, not fds which makes the config remain nice and static and can be shipped via /etc/binfmt.d.
* patches from https://patch.msgid.link/20260730-work-binfmt_misc-preopen-v1-0-4a0b0da71f16@kernel.org: binfmt_misc: document interpreters bound by a 'B' entry selftests/exec: test interpreters bound to a 'B' entry binfmt_misc: let a 'B' entry bind its interpreters binfmt_misc: carry pre-opened interpreters in struct binfmt_misc_interp selftests/exec: share the bpf handler preconditions binfmt_misc: document registering an entry disabled selftests/exec: test registering an entry disabled selftests/exec: let binfmt_flag_supported() return a bool binfmt_misc: let a register string create an entry disabled
Link: https://patch.msgid.link/20260730-work-binfmt_misc-preopen-v1-0-4a0b0da71f16@kernel.org Signed-off-by: Christian Brauner (Amutable) <brauner@kernel.org>
show more ...
|
| #
6bd0c7ab |
| 30-Jul-2026 |
Christian Brauner <brauner@kernel.org> |
selftests/exec: test registering an entry disabled
A magic entry registered with 'D' and the same entry without it, to pin down what the flag decides and what it leaves alone:
- the entry reports i
selftests/exec: test registering an entry disabled
A magic entry registered with 'D' and the same entry without it, to pin down what the flag decides and what it leaves alone:
- the entry reports itself disabled and nothing dispatches until '1' is written to it
- without 'D' it dispatches straight away
- 'D' is not read back among the entry's flags
- enabling and disabling afterwards works as it does for any entry
- 'D' composes with the flags that shape the invocation
- '-1' to the status file removes a staged entry like any other
- a file handle held across a removal cannot resurrect the entry
Put the entry write and read-back helpers into binfmt_misc_common.h. The bpf suite will need them as well.
Link: https://patch.msgid.link/20260730-work-binfmt_misc-preopen-v1-3-4a0b0da71f16@kernel.org Signed-off-by: Christian Brauner (Amutable) <brauner@kernel.org>
show more ...
|