summaryrefslogtreecommitdiff
path: root/fs/binfmt_misc.c
AgeCommit message (Collapse)Author
5 daystreewide: refresh kmalloc_obj() conversionsKees Cook
This is another run of the Coccinelle script for converting kmalloc() family of allocations to kmalloc_obj() via the existing rules in scripts/coccinelle/api/kmalloc_objs.cocci This catches both the set of kmalloc() uses added since the first kmalloc_obj() conversions in v7.0 and adds a large group missed in the first pass due to Coccinelle not interacting well with the cleanup.h scoped_...() family of macros[1]. I worked around this with spatch's "--macro-file" argument to a file with all the scoped_...() macros mapped to Coccinelle's YACFE_ITERATOR[2] as that was the closest viable control flow indicator I could find. Build tested allmodconfig on x86, arm64, arm, loongarch, mips, powerpc, riscv, and s390 with no new warnings. Link: https://lore.kernel.org/lkml/202609021314.8A9C0B8@keescook/ [1] Link: https://github.com/coccinelle/coccinelle/blob/master/standard.h [2] Signed-off-by: Kees Cook <kees+treewide@kernel.org>
2026-08-17Merge tag 'vfs-7.3-rc1.binfmt' of ↵Linus Torvalds
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 ...
2026-08-10binfmt_misc: don't warn when the mount is completed from another user namespaceChristian Brauner
fsopen() records the caller's user namespace in fc->user_ns and hands back an ordinary file descriptor. Nothing ties the task that calls fsconfig(FSCONFIG_CMD_CREATE) to the task that created the context. The fd is inherited across fork() and exec() and it can be passed over a unix socket. Completing a context from another user namespace is allowed on purpose. vfs_cmd_create() authorizes the create with mount_capable(), which for FS_USERNS_MOUNT checks ns_capable(fc->user_ns, CAP_SYS_ADMIN), and that succeeds for a task holding CAP_SYS_ADMIN in an ancestor of fc->user_ns. So an unprivileged task can reach the WARN_ON() in bm_fill_super(): create a user and a mount namespace in a child, call fsopen("binfmt_misc") there, send the fscontext fd to the parent and let the parent issue FSCONFIG_CMD_CREATE. Both namespaces come from a plain unshare(1) and no capability is needed anywhere: WARNING: fs/binfmt_misc.c:938 at bm_fill_super+0xa2/0xc0 [binfmt_misc] CPU: 15 UID: 1000 PID: 3243382 Comm: fswarn Call Trace: get_tree_keyed+0x7d/0xb0 bm_get_tree+0x34/0x90 [binfmt_misc] vfs_get_tree+0x2a/0x100 vfs_cmd_create+0x60/0xf0 __do_sys_fsconfig+0x4b2/0x500 The child needs the mount namespace because fsopen() itself gates on may_mount(), which asks for CAP_SYS_ADMIN in the user namespace owning the caller's mount namespace. fsconfig() doesn't repeat that check. It is a WARN_ON() and not a WARN_ON_ONCE(), so the condition can be raised in a loop to taint the kernel and flood the log, and it panics a kernel booted with panic_on_warn. Keep refusing the mount and stop warning about it. Nothing in bm_fill_super() depends on the two namespaces matching, it derives everything from sb->s_user_ns. Fixes: 21ca59b365c0 ("binfmt_misc: enable sandboxed mounts") Cc: stable@vger.kernel.org # v6.7+ Link: https://patch.msgid.link/20260802-work-fill_super-warn-v1-2-4e987911a39a@kernel.org Reviewed-by: Jan Kara <jack@suse.cz> Signed-off-by: Christian Brauner (Amutable) <brauner@kernel.org>
2026-08-03binfmt_misc: correctly account pre-opened interpretersChristian Brauner
An 'F' entry, and every interpreter a 'B' entry binds, holds a file open from registration until the entry goes away, pinning the file, its inode, the mount it came from and that mount's superblock. Nothing bounds how many of those a user namespace can hold. An entry binds at most BINFMT_MISC_INTERP_MAX interpreters, but nothing caps the entries. Charge each binding to the user namespace and uid that makes it against a new UCOUNT_BINFMT_MISC_INTERPRETERS. Going over budget causes -ENOSPC. A per-instance cap would suck. Instances are keyed on the user namespace. So any constant is multiplied by the number of namespaces the caller creates. Creating those is virtually free. A ucount charges the namespace and every one of its ancestors. And a namespace can raise only its own limit. So nesting buys nothing. The knob is /proc/sys/user/max_binfmt_misc_interpreters. Leave it at the max_threads/2 default fork_init() gives a new type. No existing configuration comes close to that. binfmt_misc is tristate, which makes it the first ucount user that can be built as a module. Export inc_ucount() and dec_ucount(); without them CONFIG_BINFMT_MISC=m fails to link. Export them to binfmt_misc alone: charging a ucount type is not something a module has any business doing in general, and the list is trivial to extend if a second user shows up. init_user_ns and init_binfmt_misc are already exported for the same module. Link: https://patch.msgid.link/20260803-work-binfmt_misc-interplimit-v1-1-4a2435500bd9@kernel.org Signed-off-by: Christian Brauner (Amutable) <brauner@kernel.org>
2026-08-03binfmt_misc: let a 'B' entry bind its interpretersChristian Brauner
A 'B' entry's load program selects its interpreter by absolute path, which open_exec() resolves at exec time in the mount namespace of whoever runs the binary. The handler names an interpreter but does not get to say which file that is. Whoever controls the filesystem view of the exec decides that instead. Static entries settled this long ago with 'F'. The interpreter is opened at registration in the registrant's context and every exec runs a clone of that file. Give a 'B' entry the same, for as many interpreters as it needs. An entry registered with 'D' cannot be matched yet, so it still belongs to whoever is configuring it and can be given interpreters one write at a time: 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, by the same helper that opens an 'F' interpreter. The load program picks one per exec with bpf_binprm_select_interp() and the entry hands out a clone of it. Nothing is resolved again, in any namespace. The path is everything past the first space, so no interpreter has to fit in a register string. An entry binds at most a hundred interpreters (BINFMT_MISC_INTERP_MAX). Every binding pins a struct file that no file descriptor accounts for, so RLIMIT_NOFILE does not apply and some cap is needed. A hundred is plenty and raising it later is cheap, lowering it is not. Selection is by name so the register string and the program need not agree on an order, and so the handler is not tied to where a distribution puts its interpreters. A name is a single word of printable ASCII so the entry file can report 'name path' lines. The interpreter runs under the path it was registered under. The entry file reads user memory once. bm_entry_write() copies the write in and dispatches on the first byte, and parse_command() takes the copied buffer. The status file has no binding to spell, so it keeps its own small copy in read_command(). That moves the length cap ahead of the dispatch. A write to an entry file longer than a binding can be is now refused with -E2BIG, and one from a bad address reports -EFAULT, where the command parser used to report -EINVAL for anything past three bytes. Configurations of one instance are kept apart by the lock removal already takes. Reading the set out of the entry file takes no lock. Bindings are rcu-published and the open entry file pins the entry together with everything it bound, so a reader either sees a whole node or misses it. The interpreter is opened before the configuration lock because resolving the path may walk this very filesystem, and only after the command has been parsed and the name validated from the copied buffer, so a write that can never bind opens nothing and the errno reflects the actual failure. Link: https://patch.msgid.link/20260730-work-binfmt_misc-preopen-v1-7-4a0b0da71f16@kernel.org Signed-off-by: Christian Brauner (Amutable) <brauner@kernel.org>
2026-08-03binfmt_misc: carry pre-opened interpreters in struct binfmt_misc_interpChristian Brauner
An 'F' entry opens its interpreter at registration and every exec runs a clone of that file. The file lives in a bare struct file pointer next to the path it came from and put_binfmt_handler() closes it as a special case. Give the pre-opened interpreter a type of its own instead. struct binfmt_misc_interp carries the file, the path it was opened from and a selection name in a single allocation and is linked on a list that the entry owns and tears down in put_binfmt_handler(). An 'F' entry binds a single interpreter under the empty name and hands out clones of it as before. The open moves into open_interp_file() and works exactly as the open-coded block in bm_register_write() did. It is opened for execution at registration time, in the writer's context and with the credentials the register file was opened with. The entry can now own objects before it is published, so make put_binfmt_handler() the single teardown. create_entry() returns the entry with its reference held and every failure path in bm_register_write() simply puts it. That also replaces the open-coded bpf_ops release. No functional changes. A later patch lets a 'B' entry bind multiple interpreters selected by name per exec and reuses all of this. Link: https://patch.msgid.link/20260730-work-binfmt_misc-preopen-v1-6-4a0b0da71f16@kernel.org Signed-off-by: Christian Brauner (Amutable) <brauner@kernel.org>
2026-08-03binfmt_misc: let a register string create an entry disabledChristian Brauner
An entry is matchable as soon as it is registered. create_entry() sets the enabled bit for every type and add_entry() links it straight into the instance, so everything an entry needs has to fit in the write that creates it. Add a 'D' flag. The entry is created disabled and has to be enabled by writing '1' to its entry file before it can match anything. That splits a registration into create and activate, which a later patch uses to configure an entry beyond what one register string can carry. It is useful on its own too. Entries can be staged without dispatching the moment they are written. A staged entry stays out of the search list entirely. add_entry() only hashes an entry that is born matchable, and the first '1' written to the entry file hashes a staged one, which takes its place in the search order at that point. The rcu insertion publishes the fully configured entry, so the exec side keeps the plain enabled test it always had. Removal cannot rely on the search list anymore. Whether an entry was already removed is now decided by its dentry, '-1' to the status file walks the directory instead of the list so staged entries do not survive it, and a '1' through a file handle held across a removal publishes nothing. 'D' is consumed at registration and not recorded. What matters afterwards is whether the entry is enabled, and the entry file already reports that. A 'B' entry's flags field had to be empty so far because every flag it could name shaped the invocation, which a bpf handler picks per exec with bpf_binprm_set_flags(). 'D' shapes the registration instead. So the rule becomes what it always meant: a 'B' entry carries no invocation flags, and 'D' composes. Link: https://patch.msgid.link/20260730-work-binfmt_misc-preopen-v1-1-4a0b0da71f16@kernel.org Signed-off-by: Christian Brauner (Amutable) <brauner@kernel.org>
2026-08-03binfmt_misc: let a bpf handler request loader substitutionChristian Brauner
Give bpf handlers the per-exec equivalent of the static 'L' flag. A load program that sets BPF_BINPRM_LOADER has its selected interpreter substituted for the binary's PT_INTERP instead of run with the binary as payload. The binary otherwise executes as a fully native exec. A single handler can now grade its dispatch per binary: native-arch ELF with PT_INTERP gets loader substitution for full native identity. Anything else, such as foreign arch, static, non-ELF can use transparent or classic dispatch. The load program can read the binary's ELF header from bprm->buf to make that call. Link: https://patch.msgid.link/20260721-work-bpf-binfmt_misc-ptinterp-v2-19-e57866e4ae0f@kernel.org Signed-off-by: Christian Brauner (Amutable) <brauner@kernel.org>
2026-08-03binfmt_misc: add the 'L' loader substitution flagChristian Brauner
Add the first activation of the PT_INTERP substitution machinery. A static entry registered with the new 'L' flag no longer runs the registered interpreter with the binary as payload. It stashes the interpreter as bprm->loader and declines the match with -ENOEXEC. The format search continues in the same round. binfmt_elf claims the binary as a fully native exec and substitutes the stashed file for the binary's PT_INTERP. 'L' rejects every classic-dispatch flag at registration. 'T', 'P' and 'O' have nothing to act on (no argv splice, no execfd) and 'C' is subsumed (credentials derive from the binary natively). 'F' composes and is valuable: with it the substitute is pre-opened at registration time and immune to mount namespace changes. Without it the substitute is opened at exec time in the exec'ing task's context, so 'L' joins 'C' in the requirement that the interpreter be named by an absolute path. As with 'C', only trusted interpreters should be registered. The substituted loader runs with credentials derived from the binary. Like the other flag characters 'L' cannot be used as the field delimiter. The flag scan would run off the registration buffer. The interpreter open is shared with the classic path via the entry_open_interpreter() helper. An open error fails the exec. Map -ENOEXEC to -EACCES to avoid letting the binary run with its own PT_INTERP. Link: https://patch.msgid.link/20260721-work-bpf-binfmt_misc-ptinterp-v2-18-e57866e4ae0f@kernel.org Signed-off-by: Christian Brauner (Amutable) <brauner@kernel.org>
2026-08-03binfmt_misc: let a bpf handler run the interpreter transparentlyChristian Brauner
Expose transparent mode 'T' to the bpf handler via a new BPF_BINPRM_TRANSPARENT flag. A bpf handler can decide per binary whether the dispatch is transparent. This way users may choose a native-looking loader for one binary and a visible wrapper invocation for the next. Link: https://patch.msgid.link/20260721-work-bpf-binfmt_misc-ptinterp-v2-12-e57866e4ae0f@kernel.org Signed-off-by: Christian Brauner (Amutable) <brauner@kernel.org>
2026-08-03binfmt_misc: add a static transparent flag 'T'Christian Brauner
Let a registration opt into transparent dispatch. The 'T' flag lets a matched binary keep its argument vector and is sent to the interpreter through AT_EXECFD. The process's identity is the binary's. 'T' implies 'O' exactly like 'C' does. 'P' is rejected in combination with it. Transparency preserves the whole argument vector so there is nothing left for 'P' to say. 'C' remains an independent choice and 'F' keeps working. A pre-opened interpreter is orthogonal to how the binary is handed over. Like the other flag characters 'T' cannot be used as the field delimiter. The flag scan would run off the registration buffer. Link: https://patch.msgid.link/20260721-work-bpf-binfmt_misc-ptinterp-v2-11-e57866e4ae0f@kernel.org Signed-off-by: Christian Brauner (Amutable) <brauner@kernel.org>
2026-08-03binfmt_misc: add transparent interpreter dispatchChristian Brauner
A binfmt_misc interpreter is visible to the binary it runs. argv[0] becomes the interpreter path and the binary's path is appended as an argument and /proc/pid/cmdline shows both. For wine or qemu-user that is the point. For a per-binary loader the interpreter is an implementation detail of running the binary that has no business in the argument vector. And a binary handed to execveat() as an O_CLOEXEC fd without a usable path cannot be run through binfmt_misc at all. The interpreter would have no path to open the binary by. Add the dispatch machinery for a transparent mode. The binary is handed to the interpreter through AT_EXECFD. The argument vector is left exactly as the caller set it. argv[0] and /proc/pid/cmdline look like a direct execution of the binary. bprm->interp still names the interpreter: it drives the next format lookup and the sched_prepare_exec tracepoint, not what the process sees. The interpreter loads the binary from AT_EXECFD for this. A relocatable loader can and glibc's ld.so is gaining AT_EXECFD support [1]. A staged interpreter argument is rejected: no argv slot is built for it to land in. The transparent branch raises BINPRM_FLAGS_TRANSPARENT_INTERP. A dispatch through it labels mm->exe_file with the binary and raises AT_FLAGS_TRANSPARENT_INTERP next to AT_EXECFD. The aux vector bit is the loader's hint to retarget saved_auxv and the statistics markers to the binary, which is only correct while the exe link names the binary too. The inaccessible-path bail moves after handler selection and into the path-building branch. A transparent interpreter takes the binary from AT_EXECFD instead of a path, so the restriction does not apply to it and the O_CLOEXEC execveat() case above can work. Nothing can take the transparent branch yet. Link: https://inbox.sourceware.org/libc-alpha/20260717-work-glibc-binfmt_misc-v3-0-45129bfb13fe@kernel.org [1] Link: https://patch.msgid.link/20260721-work-bpf-binfmt_misc-ptinterp-v2-10-e57866e4ae0f@kernel.org Signed-off-by: Christian Brauner (Amutable) <brauner@kernel.org>
2026-08-03binfmt_misc: split out entry_open_interpreter() and build_interp_argv()Christian Brauner
Opening the interpreter is a property of the matched entry: an 'F' entry hands out a clone of the file it pre-opened at registration time, any other entry opens the selected path. Give that its own helper instead of an if/else in the middle of load_misc_binary(), and let it fail early rather than carrying an ERR_PTR through the successful branch. Building the interpreter's argument vector is the bulk of what remains and the one part of load_misc_binary() that is specific to the classic dispatch. Move it into its own helper too, so the dispatch reads as what it is: pick a handler, pick an interpreter, build the invocation, open it. No functional change. Link: https://patch.msgid.link/20260721-work-bpf-binfmt_misc-ptinterp-v2-5-e57866e4ae0f@kernel.org Reviewed-by: Farid Zakaria <farid.m.zakaria@gmail.com> Signed-off-by: Christian Brauner (Amutable) <brauner@kernel.org>
2026-08-03binfmt_misc: normalize the per-exec invocation flagsChristian Brauner
A static entry fixes its invocation flags at registration. A 'B' entry's load program picks them per exec. Since load_misc_binary() branches on which kind of entry matched and then applies the two flag sets side by side every flag is handled twice and each new one has to be added to both arms. Translate the 'B' flags into the entry flags they mirror and let the dispatch act on a single set of flags. The boolean the two arms communicated 'P' can be removed. No functional change. Link: https://patch.msgid.link/20260721-work-bpf-binfmt_misc-ptinterp-v2-4-e57866e4ae0f@kernel.org Reviewed-by: Farid Zakaria <farid.m.zakaria@gmail.com> Signed-off-by: Christian Brauner (Amutable) <brauner@kernel.org>
2026-08-03binfmt_misc: table-drive the register string flagsChristian Brauner
Every flag character of the register string is spelled out three times: in the parser, in the entry's /proc output and in the delimiter blacklist that keeps a flag character from sending the flag scan off the end of the buffer. The three lists have to agree, and each new flag has to be added to all of them. Describe a flag once - character, entry flag, implied flags and a description for the registration debug output - and drive all three from the table. While at it, express the "a 'B' entry carries no flags" check as what it is, an empty flags field, rather than as a fourth list of every flag character. Equivalent: the check runs right after check_special_flags(), which advances past exactly the flag characters it consumed and sets exactly their flags. No functional change. Link: https://patch.msgid.link/20260721-work-bpf-binfmt_misc-ptinterp-v2-3-e57866e4ae0f@kernel.org Reviewed-by: Farid Zakaria <farid.m.zakaria@gmail.com> Signed-off-by: Christian Brauner (Amutable) <brauner@kernel.org>
2026-08-03binfmt_misc: require an absolute interpreter path with 'C'Christian Brauner
A 'C' entry computes the credentials from the matched binary instead of from the interpreter. So a set*id binary hands its credentials to whatever the entry names as its interpreter. Without 'F' that interpreter is not opened until the exec happens and open_exec() resolves the path relative to the current working directory. The working directory at that point belongs to whoever runs the binary not to whoever registered the entry. So :x:M::\x7fELF::interp:C lets every user who execs a matching set*id binary from a directory they control run their own interp with that binary's credentials. A relative interpreter has no sensible use here to begin with. The registering task cannot know what the working directory will be. Make the register string reject the combination at registration time. This does refuse register strings that used to be accepted. The 'F' flag covers the case where the interpreter really is meant to be resolved in the registrant's context, and it resolves it once, at registration. Link: https://patch.msgid.link/20260721-work-bpf-binfmt_misc-ptinterp-v2-1-e57866e4ae0f@kernel.org Reviewed-by: Farid Zakaria <farid.m.zakaria@gmail.com> Signed-off-by: Christian Brauner (Amutable) <brauner@kernel.org>
2026-08-03binfmt_misc: let a bpf handler choose the invocation flags per execChristian Brauner
The 'P', 'C' and 'O' flags of a binfmt_misc entry - preserve argv[0], compute credentials from the binary, and pass the binary as an open file descriptor - are fixed at registration and apply to every binary the entry matches. A bpf handler matches, selects the interpreter and reads the binary per exec, so the flags should be its per-exec decision too: one handler may match both setuid and non-setuid binaries, argv[0]-sensitive ones and not. Honor the flags the load program stages in bprm->bpf_flags through the bpf_binprm_set_flags() kfunc: BPF_BINPRM_PRESERVE_ARGV0, BPF_BINPRM_CREDENTIALS and BPF_BINPRM_EXECFD map to 'P', 'C' and 'O' and keep the semantics of their static counterparts, credentials implying the open file descriptor included. Flags staged by a load program that then fails are dropped on the way out so they cannot leak into a later handler's exec, and the argv[0] decision acts on the entry's own choice instead of testing the accumulated bprm->interp_flags bit, which an earlier chain level may have left set and binfmt_misc never clears. Since a 'B' entry's flags come from the program, it carries none in the register string: 'P', 'C' and 'O' are rejected there alongside 'F', which was already meaningless for it. load_misc_binary() takes the flags from the entry for a static handler and from bprm->bpf_flags for a bpf one. Link: https://patch.msgid.link/20260714-work-bpf-binfmt_misc-v2-7-57b7529c002c@kernel.org Signed-off-by: Christian Brauner (Amutable) <brauner@kernel.org>
2026-08-03binfmt_misc: let bpf handlers pass an argument to the interpreterChristian Brauner
A bpf binfmt_misc handler selects an interpreter but, unlike binfmt_script, load_misc_binary() builds the argument vector as just [interpreter, binary, ...] with no slot for an argument to the interpreter. A handler that wants to reproduce a #! line therefore cannot express its single optional argument, e.g. a handler that resolves $ORIGIN in a script's #! path loses the argument that followed the interpreter. Have load_misc_binary() consume the argument staged through the bpf_binprm_set_interp_arg() kfunc and insert it between the interpreter and the binary - the same position and single-argument semantics binfmt_script gives the argument of a #! line. The argument is cleared once spliced into the argument vector, and a load program that fails after staging one has it dropped on the way out: whether the exec fails or -ENOEXEC hands the binary back to the remaining formats, a stale argument cannot leak into a nested interpreter's argv. This also lets static-style handlers pass a fixed interpreter argument, which plain binfmt_misc has never been able to express. Link: https://patch.msgid.link/20260714-work-bpf-binfmt_misc-v2-6-57b7529c002c@kernel.org Reviewed-by: Farid Zakaria <farid.m.zakaria@gmail.com> Signed-off-by: Christian Brauner (Amutable) <brauner@kernel.org>
2026-08-03binfmt_misc: wire up bpf-backed 'B' entriesChristian Brauner
Activate a registered binfmt_misc_ops handler through the existing text interface with the new 'B' entry type: echo ':name:B::::<handler-name>:' > <binfmt_misc>/register The offset, magic, and mask fields must be empty since the program does the matching; the interpreter field carries the handler name since the program supplies the interpreter. Reusing the register file keeps the existing permission model intact: activating a handler requires the same write access to a binfmt_misc instance as any other registration, and the per user namespace instance semantics apply unchanged. A 'B' entry in a container's own instance shadows the host's handlers just like any other entry, and the privilege needed to shadow e.g. all ELF binaries is the same as for a static 'M' entry matching \x7fELF today; the only novelty is that matching becomes programmable. The entry takes its own reference on the ops for its whole lifetime. It is dropped from the SRCU callback that frees the entry rather than synchronously on the final put: a walker may be asleep inside the handler's match program while the entry's last reference goes away, so the ops must stay callable until every walker has left the read section - the same deferral the entry's own memory already gets. The registration failure path, where the users refcount is not live yet, drops it explicitly. The match program runs from the lookup walk like magic and extension matching and under the same rules: strict registration order, first match wins. The walk became an SRCU read-side section in the previous patch, so the program can sleep: it decides on the actual file content - program headers beyond the prefetched bprm->buf, say - not just on whatever happens to be resident in the page cache. A match commits the exec to the handler. The sleepable load program then selects the interpreter from load_misc_binary() by calling bpf_binprm_set_interp() and returning zero; a failure fails the exec instead of falling through to later entries. The walk is never left and re-entered, so 'B' entries need no special semantics against concurrent registration and removal whatsoever. -ENOEXEC keeps its usual meaning and moves on to the remaining binary formats - a handler whose load program discovers that it cannot serve the binary after all hands it back to them - and so does returning zero without having selected an interpreter; other program-supplied errors are clamped to the errno range. The 'F' flag is rejected for 'B' entries: it exists to pre-open a fixed interpreter at registration time in the registrar's context, and a 'B' entry has no fixed interpreter to pre-open. 'C' is accepted and behaves exactly as it does for a static entry. It honors the suid bits of the matched binary while executing the interpreter, which makes 'B' handlers usable for the setuid case, e.g. a per-binary loader. This does not let the program's registrant widen access: bprm_fill_uid() gates the credential transition on vfsuid_has_mapping() in the caller's user namespace, so the interpreter can only ever run as a uid that is mapped there, identical to a static 'C' entry. The computed path is opened with open_exec() under the caller's credentials with the usual LSM and noexec checks, and the programs run before the transition with the caller's credentials, never elevated. Link: https://lore.kernel.org/20260704211409.1978485-1-farid.m.zakaria@gmail.com Link: https://patch.msgid.link/20260714-work-bpf-binfmt_misc-v2-4-57b7529c002c@kernel.org Reviewed-by: Farid Zakaria <farid.m.zakaria@gmail.com> Signed-off-by: Christian Brauner (Amutable) <brauner@kernel.org>
2026-08-03binfmt_misc: let the entry lookup walk sleepChristian Brauner
The upcoming bpf-backed binary type handlers run a match program from the entry lookup walk in load_misc_binary(). Deciding whether a handler applies means reading the binary - parsing ELF program headers sitting at arbitrary file offsets, say - and reliable file reads at exec time fault in the file's pages, so the walk must tolerate an entry's evaluation sleeping. Switch the walk from RCU to SRCU in its fast flavor: srcu-fast read sections may block while the read side stays practically as cheap as the RCU read lock it replaces, so the common static-entry lookup does not pay for the new capability. Entry freeing moves from kfree_rcu() to call_srcu(). Removal still unlinks the entry immediately and never blocks: a walker sleeping inside an entry's evaluation just keeps the entry alive until it leaves the read section. The module exit path flushes pending callbacks with srcu_barrier(). Take the reference on a matched entry at the match point inside the walk instead of retrying the whole search when the refcount raise fails. A restarted search was harmless when an entry's evaluation was a memcmp() on bprm->buf, but re-running match programs that may sleep on entries that were already consulted is not. An entry whose refcount hit zero is unlinked and dying, so treating it as absent and walking on is exactly what the bounded retry loop converged to, without ever evaluating an entry twice. Link: https://patch.msgid.link/20260714-work-bpf-binfmt_misc-v2-3-57b7529c002c@kernel.org Signed-off-by: Christian Brauner (Amutable) <brauner@kernel.org>
2026-08-03binfmt_misc: allow removing entries via unlink(2)Christian Brauner
Removing a binary type handler requires echoing -1 into its entry file which works but is an odd interface to discover for something that already looks like a plain file in a filesystem. The comment on remove_binfmt_handler() has been suggesting a proper ->unlink() method for years, so add one: unlinking an entry file unhashes the entry from the handler list and removes the file, exactly like writing -1 to it does. The status and register control files refuse removal with EPERM the same way binderfs protects binder-control. Writing -1 keeps working. Permission-wise nothing new is exposed: unlink(2) requires write access to the root directory which is owned by the (user namespace) root with mode 0755, matching the privilege needed to write to the 0644 entry files. The VFS calls ->unlink() with the root inode lock held so the existing writer serialization scheme applies unchanged, and eviction of the unlinked inode drops the entry reference exactly as for the write based removal. Document the new way in admin-guide/binfmt-misc.rst. Link: https://patch.msgid.link/20260710-work-binfmt_misc-locking-v3-24-a162f7cb58d6@kernel.org Reviewed-by: Jori Koolstra <jkoolstra@xs4all.nl> Signed-off-by: Christian Brauner (Amutable) <brauner@kernel.org>
2026-08-03binfmt_misc: include what is usedChristian Brauner
The include list still reflects code that left this file years ago: nothing here uses sched/mm.h, pagemap.h, namei.h, syscalls.h or anything from fs/internal.h anymore, mount.h and the bm_fs_type forward declaration lost their last user when the pinned bm_mnt machinery was removed. Drop all of that and instead spell out the headers the file actually relies on but so far pulled in transitively: bitops, bits, bug, cleanup, cred, kstrtox, printk, refcount, string and user_namespace. With that nothing needs the kernel.h grab bag anymore, so it goes too, and the list is sorted alphabetically. Link: https://patch.msgid.link/20260710-work-binfmt_misc-locking-v3-23-a162f7cb58d6@kernel.org Signed-off-by: Christian Brauner (Amutable) <brauner@kernel.org>
2026-08-03binfmt_misc: assorted small cleanupsChristian Brauner
Use umode_t for the mode argument of bm_get_inode(), constify the fixed status strings in bm_status_read(), give the super_operations the bm_ prefix everything else in this file uses, replace the stale scanarg() comment which still described parameters and an err variable it lost decades ago and fix the delimiter typo plus a missing space nearby. No functional change. Link: https://patch.msgid.link/20260710-work-binfmt_misc-locking-v3-22-a162f7cb58d6@kernel.org Reviewed-by: Jori Koolstra <jkoolstra@xs4all.nl> Signed-off-by: Christian Brauner (Amutable) <brauner@kernel.org>
2026-08-03binfmt_misc: use __free(kfree) in bm_register_write()Christian Brauner
bm_register_write() has to free the entry it got from create_entry() on every failure until add_entry() has linked it into the filesystem and made the inode its owner. Arm the entry with __free(kfree) so the error branches can simply return and disarm it via retain_and_null_ptr() once ownership has been handed to the inode. The interpreter file keeps its manual error cleanup as freeing the entry would not close it. No functional change. Link: https://patch.msgid.link/20260710-work-binfmt_misc-locking-v3-21-a162f7cb58d6@kernel.org Reviewed-by: Jori Koolstra <jkoolstra@xs4all.nl> Signed-off-by: Christian Brauner (Amutable) <brauner@kernel.org>
2026-08-03binfmt_misc: split the field parsing out of create_entry()Christian Brauner
create_entry() is a two hundred line parser with the M and E field handling inlined as the two arms of its largest branch. Move them into parse_magic_fields() and parse_extension_fields() which return the new parse position or NULL so create_entry() itself reads like the register string grammar again. The offset parsing loses a provably dead check on the way: after *s = '\0' and p = s the subsequent if (*p++) always reads the just written NUL byte and can never fail, it only obscured that the code simply advances past the delimiter. With the field parsing gone every remaining failure unwinds the same way, so hand the entry to __free(kfree), return errors directly and pass ownership out via no_free_ptr() on success instead of routing every exit through goto tails. Link: https://patch.msgid.link/20260710-work-binfmt_misc-locking-v3-20-a162f7cb58d6@kernel.org Signed-off-by: Christian Brauner (Amutable) <brauner@kernel.org>
2026-08-03binfmt_misc: use a flexible array member for the register stringChristian Brauner
create_entry() allocates the entry and the register string it parses into in one chunk and finds the string part again through manual pointer arithmetic behind a cast. Make the layout explicit with a flexible array member and struct_size(), and give the magic pad of trailing delimiters a name while at it. No functional change. Link: https://patch.msgid.link/20260710-work-binfmt_misc-locking-v3-19-a162f7cb58d6@kernel.org Reviewed-by: Jori Koolstra <jkoolstra@xs4all.nl> Signed-off-by: Christian Brauner (Amutable) <brauner@kernel.org>
2026-08-03binfmt_misc: simplify check_special_flags()Christian Brauner
Replace the cont flag and the pointer increment repeated in every case with a for loop that returns from the default case, and shrink the multi-line 'C implies O' remark to one line. No functional change. Link: https://patch.msgid.link/20260710-work-binfmt_misc-locking-v3-18-a162f7cb58d6@kernel.org Reviewed-by: Jori Koolstra <jkoolstra@xs4all.nl> Signed-off-by: Christian Brauner (Amutable) <brauner@kernel.org>
2026-08-03binfmt_misc: factor out the entry removalChristian Brauner
Both write handlers open-code the same removal dance - grab the root inode lock, unlink, unlock - each carrying a verbatim copy of the same eleven-line locking comment, and bm_entry_write() reuses its inode variable for the root inode halfway through to pull it off. Move the dance into bm_remove_entry() and bm_remove_all_entries() and the locking rules into the kernel-doc of remove_binfmt_handler() which both helpers wrap. No functional change. Link: https://patch.msgid.link/20260710-work-binfmt_misc-locking-v3-17-a162f7cb58d6@kernel.org Reviewed-by: Jori Koolstra <jkoolstra@xs4all.nl> Signed-off-by: Christian Brauner (Amutable) <brauner@kernel.org>
2026-08-03binfmt_misc: give the parse_command() results namesChristian Brauner
parse_command() maps "0" to 1, "1" to 2 and "-1" to 3 and the write handlers switch on those bare numbers, leaving every reader to redo the mapping in their head. Name the commands and drop the per-case comments that only existed to translate the numbers back. No functional change. Link: https://patch.msgid.link/20260710-work-binfmt_misc-locking-v3-16-a162f7cb58d6@kernel.org Reviewed-by: Jori Koolstra <jkoolstra@xs4all.nl> Signed-off-by: Christian Brauner (Amutable) <brauner@kernel.org>
2026-08-03binfmt_misc: return errors directly in load_misc_binary()Christian Brauner
load_misc_binary() seeds retval with the error for checks that happen further down, reassigns it along the way and funnels every exit through a ret label whose only job is dropping the entry reference, so figuring out what an early return actually returns means replaying the assignment history. Give put_binfmt_handler() a cleanup class and take the reference with __free() so every failure can return its error right where the condition is checked. The comment at the label restated what the put_binfmt_handler() kernel-doc already explains, it goes with the label. Drop the dead NULL initialization of interp_file which is assigned on all paths before use. No functional change. Link: https://patch.msgid.link/20260710-work-binfmt_misc-locking-v3-15-a162f7cb58d6@kernel.org Reviewed-by: Jori Koolstra <jkoolstra@xs4all.nl> Signed-off-by: Christian Brauner (Amutable) <brauner@kernel.org>
2026-08-03binfmt_misc: rename load_binfmt_misc() to current_binfmt_misc()Christian Brauner
load_binfmt_misc() is one word swap away from load_misc_binary(), the binfmt loader it serves. It doesn't load anything, it looks up the binfmt_misc instance of the caller's user namespace, so name it after what it returns in the style of current_user_ns() and friends. Tighten the parent walk into a for loop and fix the stale wording and typos in the kernel-doc while at it. Link: https://patch.msgid.link/20260710-work-binfmt_misc-locking-v3-14-a162f7cb58d6@kernel.org Reviewed-by: Jori Koolstra <jkoolstra@xs4all.nl> Signed-off-by: Christian Brauner (Amutable) <brauner@kernel.org>
2026-08-03binfmt_misc: factor out the entry matchingChristian Brauner
search_binfmt_handler() open-codes both match types in one loop body with the maskless magic comparison spelled as a manual xor loop that is just memcmp() in disguise. Move the extension and magic checks into helpers so the walk reads as policy - skip disabled entries, match by entry type - and the maskless case actually uses memcmp(). No functional change. Link: https://patch.msgid.link/20260710-work-binfmt_misc-locking-v3-13-a162f7cb58d6@kernel.org Reviewed-by: Jori Koolstra <jkoolstra@xs4all.nl> Signed-off-by: Christian Brauner (Amutable) <brauner@kernel.org>
2026-08-03binfmt_misc: convert the entry file to seq_fileChristian Brauner
Reading an entry file allocates a whole page and formats the status into it with a chain of manually advanced sprintf() calls, silently relying on MAX_REGISTER_LENGTH plus the hex-expanded magic and mask always staying below PAGE_SIZE. Convert the read side to seq_file which sizes its buffer as needed and gets rid of the open-coded pointer arithmetic including the last bin2hex() user in the file. The output is byte for byte identical. seq_open() clears FMODE_PWRITE for historical reasons and would silently turn pwrite() on entry files into -ESPIPE even though bm_entry_write() accepts writes at any offset. Restore the flag in bm_entry_open() the same way kernfs does for its seq_file backed files so pwrite() keeps working. The only user-visible difference is that seeking is now bound by seq_lseek() instead of default_llseek(), i.e. SEEK_END stops working on entry files, which nothing can sensibly use anyway. The status file keeps its simple_read_from_buffer() as it only ever returns one of two fixed strings. Link: https://patch.msgid.link/20260710-work-binfmt_misc-locking-v3-12-a162f7cb58d6@kernel.org Reviewed-by: Jori Koolstra <jkoolstra@xs4all.nl> Signed-off-by: Christian Brauner (Amutable) <brauner@kernel.org>
2026-08-03binfmt_misc: use print_hex_dump_debug() for the register debug outputChristian Brauner
The hex dumps in create_entry() are compiled out unless someone edits the file to define DEBUG while the pr_debug() calls right next to them are dynamic-debug aware. Switch the dumps to print_hex_dump_debug() which follows the same rules as pr_debug() so the register parsing debug output is uniformly controlled through dynamic debug, and remove the USE_DEBUG machinery. Drop the magic[masked] dump instead of converting it: it printed the bitwise AND of two buffers dumped right above it and required a temporary allocation on every registration just to recompute what the reader can derive from the magic and mask dumps directly. Link: https://patch.msgid.link/20260710-work-binfmt_misc-locking-v3-11-a162f7cb58d6@kernel.org Reviewed-by: Jori Koolstra <jkoolstra@xs4all.nl> Signed-off-by: Christian Brauner (Amutable) <brauner@kernel.org>
2026-08-03binfmt_misc: remove the VERBOSE_STATUS toggleChristian Brauner
VERBOSE_STATUS is a compile-time constant that has been fixed to 1 for as long as git history reaches. Turning it off requires editing the source and yields entry files that only ever report "enabled"/"disabled", a format nothing has ever seen in the wild. Remove the pretend knob and the dead branch it guards. Link: https://patch.msgid.link/20260710-work-binfmt_misc-locking-v3-10-a162f7cb58d6@kernel.org Reviewed-by: Jori Koolstra <jkoolstra@xs4all.nl> Signed-off-by: Christian Brauner (Amutable) <brauner@kernel.org>
2026-08-03binfmt_misc: rename Node to struct binfmt_misc_entryChristian Brauner
The CamelCase Node typedef is a 1997 leftover and hides that this is a plain struct. Call it what it is: struct binfmt_misc_entry, matching struct binfmt_misc that it hangs off of and the entry bit and flag enums. Drop the typedef, switch the size computations in create_entry() to sizeof(*e) and adjust the comments that still referred to the old name. No functional change. Link: https://patch.msgid.link/20260710-work-binfmt_misc-locking-v3-9-a162f7cb58d6@kernel.org Reviewed-by: Jori Koolstra <jkoolstra@xs4all.nl> Signed-off-by: Christian Brauner (Amutable) <brauner@kernel.org>
2026-08-03binfmt_misc: turn the entry behavior flags into an enumChristian Brauner
The MISC_FMT_* behavior flags are macros using unsigned long literals while the entry bit numbers right above them are now a proper enum. Move the flags into an enum as well so every flags word constant is declared in one form and shows up in debuginfo. (1U << N) keeps the enumerators within unsigned int range which is well-defined for enum constants and the values are unchanged when promoted to the unsigned long flags word. No functional change. Link: https://patch.msgid.link/20260710-work-binfmt_misc-locking-v3-8-a162f7cb58d6@kernel.org Reviewed-by: Jori Koolstra <jkoolstra@xs4all.nl> Signed-off-by: Christian Brauner (Amutable) <brauner@kernel.org>
2026-08-03binfmt_misc: turn the entry bit numbers into a proper enumChristian Brauner
Enabled and Magic are bit numbers in the flags word of an entry but are declared as bare, unprefixed enumerators with implicit values in a style that predates the git history. Give the enum a name, explicit bit numbers and namespaced names and use BIT() instead of open-coding the shifts when building the initial flags word in create_entry(). No functional change. Link: https://patch.msgid.link/20260710-work-binfmt_misc-locking-v3-7-a162f7cb58d6@kernel.org Reviewed-by: Jori Koolstra <jkoolstra@xs4all.nl> Signed-off-by: Christian Brauner (Amutable) <brauner@kernel.org>
2026-08-03binfmt_misc: annotate racy accesses to ->enabledChristian Brauner
->enabled has always been read and written locklessly: every exec reads it in load_misc_binary() while bm_status_write() or a concurrent remount via bm_fill_super() may flip it. That is fine as it is an independent boolean toggle but the accesses should be marked accordingly for KCSAN. Annotate them with READ_ONCE()/WRITE_ONCE(). Link: https://patch.msgid.link/20260710-work-binfmt_misc-locking-v3-6-a162f7cb58d6@kernel.org Reviewed-by: Jori Koolstra <jkoolstra@xs4all.nl> Signed-off-by: Christian Brauner (Amutable) <brauner@kernel.org>
2026-08-03binfmt_misc: use RCU for the handler lookupChristian Brauner
Once binfmt_misc is loaded load_misc_binary() runs for every execve() on the system since binfmt_misc registers at the head of the formats list. Every exec therefore performs read_lock() and read_unlock() on the entries_lock of the relevant binfmt_misc instance, i.e., two atomic read-modify-writes on a shared cacheline. User namespaces without their own binfmt_misc mount fall back to an ancestor's instance so on container-heavy systems every exec on the machine typically ends up hammering the cacheline of init_binfmt_misc. On PREEMPT_RT the rwlock additionally turns the handler lookup into a sleeping lock on the exec fast path. The lock protects very little. Entries are immutable after publication except for the Enabled bit which is already toggled locklessly via set_bit()/clear_bit() and entry lifetime is already handled by the users refcount via get_binfmt_handler()/put_binfmt_handler(). The read lock's only remaining job is to make "the entry is still linked" and "take a reference" atomic with respect to the unlink sites. Switch the lookup to an RCU walk: * Lookup walks the entry list under rcu_read_lock() and acquires a reference via refcount_inc_not_zero(). The refcount can only drop to zero after an entry has been unlinked so a failed increment means the walk raced with an unlink. Restarting the search is bounded because an unlinked entry cannot be found again. * The unlink sites use hlist_del_init_rcu() which keeps the forward pointer intact for concurrent walkers and preserves hlist_unhashed() as the protection against double removal. * The final put frees the entry via kfree_rcu() as a concurrent walker may still dereference its flags, magic, mask, and inline strings. They all live in the entry allocation itself and thus stay valid until a grace period has elapsed. Closing the interpreter file stays synchronous. It is only used with a reference already held and all final puts run in process context. * Writers remain serialized by the inode lock of the root dentry with one exception. bm_evict_inode() called from generic_shutdown_super() during umount unlinks entries without holding it. Keep a spinlock around the unlink sites instead of relying on superblock lifetime rules to make that exclusion implicit. Handler removal semantics are unchanged. An exec that acquired a reference just before its handler was unregistered already completes with the removed handler today. The read lock never protected against that, it only made the window smaller. With this an exec that matches no binfmt_misc entry, the common case, no longer writes to any shared cacheline at all. Link: https://patch.msgid.link/20260710-work-binfmt_misc-locking-v3-5-a162f7cb58d6@kernel.org Reviewed-by: Jori Koolstra <jkoolstra@xs4all.nl> Signed-off-by: Christian Brauner (Amutable) <brauner@kernel.org>
2026-08-03binfmt_misc: convert entry list to an hlistChristian Brauner
The upcoming conversion of the handler lookup to RCU walks cannot use list_del_init(): reinitializing the forward pointer of a removed entry would make a concurrent lockless walker standing on that entry loop back onto it indefinitely. The removal paths do rely on reinitialization though because bm_{entry,status}_write() and bm_evict_inode() need to detect whether an entry has already been unlinked. hlists support exactly this pattern: hlist_del_init_rcu() keeps the forward pointer of the removed entry intact for concurrent walkers and only zeroes ->pprev with hlist_unhashed() serving as the linked test. Convert the entry list to an hlist now while keeping the rwlock so the subsequent RCU conversion is a pure locking change. hlist_add_head() inserts at the head just as list_add() did so lookup precedence between registered handlers is unchanged. Link: https://patch.msgid.link/20260710-work-binfmt_misc-locking-v3-4-a162f7cb58d6@kernel.org Reviewed-by: Jori Koolstra <jkoolstra@xs4all.nl> Signed-off-by: Christian Brauner (Amutable) <brauner@kernel.org>
2026-07-28binfmt_misc: don't leak the user namespace when the mount failsChristian Brauner
bm_get_tree() takes a reference to the user namespace and hands it to get_tree_keyed() as the sget key. sget_fc() moves that reference into sb->s_fs_info and clears fc->s_fs_info, so from that point on the superblock owns it and bm_free() doesn't see it anymore. The superblock drops it in ->put_super(). But generic_shutdown_super() only calls ->put_super() from inside the if (sb->s_root) branch, so nothing releases it when bm_fill_super() fails: - The kzalloc_obj() failure leaves s_root NULL and the whole branch is skipped. - A simple_fill_super() failure in the file loop leaves s_root set, but s_op still points at simple_super_operations, which has no ->put_super(). bm_fill_super() installs s_ops only once simple_fill_super() returned success, and installing it earlier wouldn't help either because simple_fill_super() overwrites s_op. Either way vfs_get_super() calls deactivate_locked_super() and the reference is gone for good. binfmt_misc mounts are available in a user namespace and both the inode and the dentry cache are SLAB_ACCOUNT, so an unprivileged caller under a tight memory cgroup can fail simple_fill_super() on demand and leak one user namespace per attempt. Drop the reference in ->kill_sb() instead, which runs unconditionally, the same way nfsd and rpc_pipefs release their keyed s_fs_info. That also stops ->put_super() from clearing s_fs_info while the superblock is still on @fs_supers. generic_shutdown_super() leaves it there on purpose so that sget_fc() keeps finding it until kill_sb() has run, but a NULL s_fs_info makes test_keyed_super() miss it, so a concurrent mount for the same user namespace skips the grab_super() wait and creates a second superblock for a namespace that is still being torn down. Link: https://patch.msgid.link/20260728-work-binfmt_misc-usernsleak-v1-1-dbd8d5e626e7@kernel.org Fixes: 21ca59b365c0 ("binfmt_misc: enable sandboxed mounts") Cc: stable@vger.kernel.org Signed-off-by: Christian Brauner (Amutable) <brauner@kernel.org>
2026-07-28binfmt_misc: reject a flag character as the field delimiterChristian Brauner
The registration string starts with a user chosen delimiter that separates the individual fields. So that the field parsers terminate even on a truncated string create_entry() pads the buffer with that same delimiter: memset(buf + count, del, 8); Most fields are scanned for the delimiter with strchr()/scanarg() and happily stop on the padding. The flags field is different: instead of scanning for the delimiter check_special_flags() consumes the flag characters 'P', 'O', 'C' and 'F' and stops at the first byte that is none of them, relying on the trailing delimiter to end the scan. If the delimiter is itself a flag character the padding no longer acts as a terminator. The scan swallows all eight padding bytes and keeps reading past the end of the allocation until it hits a byte that is not a flag character. For example registering PaPEPPxPPiP with 'P' as the delimiter (name "a", type extension, magic "x", interpreter "i", empty flags) leaves the flag scan running off the end of the buffer. The registration is rejected in the end because the parser does not stop exactly at buf + count, but only after the out of bounds read has already happened. With an unlucky allocation layout the scan can walk into an unmapped page; under KASAN it is reported as a slab out of bounds read. binfmt_misc mounts are available to unprivileged users in a user namespace so the read is reachable without privileges. Reject a delimiter that is one of the flag characters up front. Such a registration was always rejected anyway, only after the out of bounds read, so no valid registration string changes meaning. Link: https://patch.msgid.link/20260710-work-binfmt_misc-locking-v3-3-a162f7cb58d6@kernel.org Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") Cc: stable@vger.kernel.org Signed-off-by: Christian Brauner (Amutable) <brauner@kernel.org>
2026-07-28binfmt_misc: use exe_file_deny_write_access() for the interpreter cloneChristian Brauner
For MISC_FMT_OPEN_FILE entries load_misc_binary() clones the registered interpreter file and denies write access to the clone via plain deny_write_access(). The clone is installed as bprm->interpreter and later released by the exec machinery through exe_file_allow_write_access() which skips the i_writecount increment for files with FMODE_FSNOTIFY_HSM set. The deny and allow side can therefore come to different conclusions when pre-content watches are in play: if a pre-content watch is added to the interpreter after registration every subsequent exec through that entry takes a write denial on the clone that is never paired with a write allowance, driving the interpreter inode's i_writecount further down with each exec and leaving the interpreter unwritable even after the entry and all its users are gone. Take the write denial via exe_file_deny_write_access() so both sides of the pairing base their decision on the same file mode, and propagate failure instead of silently ignoring it: an interpreter that is concurrently open for writing now fails the exec with ETXTBSY, exactly like an interpreter freshly opened via open_exec() would. Link: https://patch.msgid.link/20260710-work-binfmt_misc-locking-v3-2-a162f7cb58d6@kernel.org Fixes: 0357ef03c94e ("fs: don't block write during exec on pre-content watched files") Cc: stable@vger.kernel.org Signed-off-by: Christian Brauner (Amutable) <brauner@kernel.org>
2026-07-28binfmt_misc: restore write access when removing an entryChristian Brauner
Registering an entry with the MISC_FMT_OPEN_FILE flag opens the interpreter via open_exec() which denies write access to it for as long as the entry exists. Removing the entry closes the interpreter file via filp_close() but never restores write access, leaving the inode's i_writecount permanently negative. Opening the interpreter for writing keeps failing with ETXTBSY long after the entry is gone until the inode is evicted from the inode cache. Commit 90f601b497d7 ("binfmt_misc: restore write access before closing files opened by open_exec()") fixed the same imbalance in the error path of bm_register_write() but the actual removal path has been leaking the write denial since the introduction of the flag. Restore write access in put_binfmt_handler() before closing the interpreter file. Link: https://patch.msgid.link/20260710-work-binfmt_misc-locking-v3-1-a162f7cb58d6@kernel.org Fixes: 948b701a607f ("binfmt_misc: add persistent opened binary handler for containers") Cc: stable@vger.kernel.org Signed-off-by: Christian Brauner (Amutable) <brauner@kernel.org>
2026-07-28binfmt_misc: don't let an 'F' entry pin its own instanceChristian Brauner
An entry registered with 'F' opens its interpreter at registration time and holds that file until the entry is freed. Any entry nobody removes by hand only gets closed once the binfmt_misc superblock is shut down. If the interpreter lives on a mount that keeps that superblock alive the two pin each other: binfmt_misc sb -> inode -> entry -> interp_file -> vfsmount -> binfmt_misc sb TL;DR the file is never closed. Once the mount namespace is gone there is nothing left to unregister through either. There are two ways to trigger this bug: - Point the interpreter at the instance itself. Its files are regular files owned by the mounter and both bm_get_inode() and simple_fill_super() leave i_op at empty_iops. So notify_change() falls back to simple_setattr() and chmod +x works. We never set SB_I_NOEXEC and so open_exec() accepts it. - Use the instance as an overlayfs lower layer. The overlay superblock holds a clone_private_mount() of every layer until it is destroyed and that clone is in no namespace. So umount_tree() never reaches it. That's a DoS. And it isn't only the superblock that leaks. It pins the user namespace it was mounted in, so every iteration permanently eats one of the caller's user namespace charges. So let's just do the sane thing. SB_I_NOEXEC makes open_exec() fail on the instance's own files and s_stack_depth makes overlayfs reject the layer before it ever takes a clone. That also covers the ecryptfs and fuse passthrough variants. What 'F' promises is unchanged. The stable tag is narrower than the Fixes tags on purpose. Before sandboxed mounts this needed global root against the single instance everyone shares, and the change doesn't apply to those trees anyway. Note that SB_I_NODEV is implicitly raised for userns mounts but raise it explicitly here as well. Link: https://patch.msgid.link/20260728-work-binfmt_misc-selfpin-v1-1-74df5daeca5b@kernel.org Fixes: 948b701a607f ("binfmt_misc: add persistent opened binary handler for containers") Fixes: 21ca59b365c0 ("binfmt_misc: enable sandboxed mounts") Cc: stable@vger.kernel.org # v6.7+ Signed-off-by: Christian Brauner (Amutable) <brauner@kernel.org>
2026-07-20binfmt_misc: set have_execfd only once the interpreter is openedChristian Brauner
load_misc_binary() raises bprm->have_execfd as soon as it sees the 'O' (or 'C') flag. This happens well before it opens the interpreter. If that open fails the flag stays set on the bprm. binfmt_misc is at the head of the format list so an interpreter open failure that returns -ENOEXEC lets the search fall through to a later format. This means it runs the matched binary directly having never staged an interpreter. So bprm->executable is NULL while have_execfd falsely claims a descriptor is present. Consequently, begin_new_exec() dereferences the missing executable: would_dump(bprm, bprm->executable); and NULL derefs. Had it not, the hand-off later in the same function would have failed anyway. FD_ADD(0, bprm->executable) rejects a NULL file with -ENOMEM. Both sites are past the point of no return so the exec cannot be unwound either way. This can be reached by unprivileged users as binfmt_misc can be mounted in user namespaces. So a user can register an 'O' entry whose interpreter lives on a FUSE mount, have the FUSE server fail the open with -ENOEXEC and execute a native ELF file that matches the entry. have_execfd only means anything alongside the executable it describes which is not set until the interpreter has been opened and staged. So lets raise it there, next to execfd_creds, which is already set at that point. An open failure now leaves it clear, so the fallback format derives credentials from the binary and emits no AT_EXECFD, as it would for any native exec. The argv rewrite load_misc_binary() performs before the open is still not undone. This means the binary sees the interpreter path in argv[0] and its own path in argv[1] but that predates this change and only became observable once the exec stopped faulting. Link: https://patch.msgid.link/20260720-beglichen-kognitiv-organismus-5e1e55326c56@brauner Fixes: bc2bf338d54b ("exec: Remove recursion from search_binary_handler") Cc: stable@vger.kernel.org Signed-off-by: Christian Brauner (Amutable) <brauner@kernel.org>
2026-05-28binfmt_misc: replace __get_free_page() with kmalloc()Mike Rapoport (Microsoft)
bm_entry_read() allocates temporary buffer using __get_free_page(). kmalloc() is a better API for such use and it also provides better scalability and more debugging possibilities. Replace use of __get_free_page() with kmalloc(). Signed-off-by: Mike Rapoport (Microsoft) <rppt@kernel.org> Link: https://patch.msgid.link/20260523-b4-fs-v1-16-275e36a83f0e@kernel.org Signed-off-by: Christian Brauner (Amutable) <brauner@kernel.org>
2026-02-21Convert 'alloc_obj' family to use the new default GFP_KERNEL argumentLinus Torvalds
This was done entirely with mindless brute force, using git grep -l '\<k[vmz]*alloc_objs*(.*, GFP_KERNEL)' | xargs sed -i 's/\(alloc_objs*(.*\), GFP_KERNEL)/\1)/' to convert the new alloc_obj() users that had a simple GFP_KERNEL argument to just drop that argument. Note that due to the extreme simplicity of the scripting, any slightly more complex cases spread over multiple lines would not be triggered: they definitely exist, but this covers the vast bulk of the cases, and the resulting diff is also then easier to check automatically. For the same reason the 'flex' versions will be done as a separate conversion. Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2026-02-21treewide: Replace kmalloc with kmalloc_obj for non-scalar typesKees Cook
This is the result of running the Coccinelle script from scripts/coccinelle/api/kmalloc_objs.cocci. The script is designed to avoid scalar types (which need careful case-by-case checking), and instead replace kmalloc-family calls that allocate struct or union object instances: Single allocations: kmalloc(sizeof(TYPE), ...) are replaced with: kmalloc_obj(TYPE, ...) Array allocations: kmalloc_array(COUNT, sizeof(TYPE), ...) are replaced with: kmalloc_objs(TYPE, COUNT, ...) Flex array allocations: kmalloc(struct_size(PTR, FAM, COUNT), ...) are replaced with: kmalloc_flex(*PTR, FAM, COUNT, ...) (where TYPE may also be *VAR) The resulting allocations no longer return "void *", instead returning "TYPE *". Signed-off-by: Kees Cook <kees@kernel.org>