linux/include
Christian Brauner b4bfe2f6b0
binfmt_misc: add binfmt_misc_ops bpf struct_ops
Add the bpf plumbing for binary type handlers whose matching and
interpreter selection are implemented by bpf programs instead of a
fixed magic/extension and a fixed interpreter string recorded at
registration time. This serves relocatable binary formats where the
interpreter must be computed per binary, e.g. relative to the location
of the binary itself, as discussed for hermetic Nix-style executables.

A handler is an instance of the new binfmt_misc_ops struct_ops with a
name that binfmt_misc entries reference it by and two ops:

        bool (*match)(struct linux_binprm *bprm);
        int (*load)(struct linux_binprm *bprm);

struct_ops is the sanctioned mechanism for this kind of user-supplied
policy callback: program types, attach types, and the uapi helper list
are frozen, and every recently added subsystem hook (bpf qdisc, SMC
handshake control, io_uring loop ops, sched_ext) is a struct_ops user.
The ops receive the bprm as a trusted BTF pointer, so a program can
match on the header in bprm->buf, read arbitrary file content via
bpf_dynptr_from_file() to parse e.g. ELF program headers, and inspect
the binary's location. No dedicated program type, ctx blob, or uapi
helper is needed.

The two ops split along what they decide, not what they may do: the
match program decides whether the handler applies to a binary, the
load program decides how a matched binary is run. Both are required
to be sleepable. Matching cannot be limited to the prefetched 256
bytes in bprm->buf: deciding whether a handler applies takes e.g.
parsing the ELF program headers to find an interpreter segment, which
sits at an arbitrary file offset, and non-sleepable file reads are
limited to whatever happens to be resident in the page cache. A match
program that cannot read the file reliably would have to match
broadly and leave the rejection to its load program, which breaks
first-match-wins entry semantics the moment more than one handler is
registered. Reliable file reads at exec time fault in the file's
pages, so both ops must be able to sleep. This also constrains the
caller: binfmt_misc must invoke both from sleepable context, which a
later patch takes care of. Both ops are required; a handler that
wants to decide everything from the load program supplies a match
program that just returns true.

The load program communicates its decisions through three new kfuncs:

        int bpf_binprm_set_interp(struct linux_binprm *bprm,
                                  const char *path, size_t path__sz);

selects the interpreter and enforces an absolute path shorter than
PATH_MAX.

        int bpf_binprm_set_interp_arg(struct linux_binprm *bprm,
                                      const char *arg, size_t arg__sz);

passes a single optional argument to the interpreter, mirroring the
optional argument of a #! interpreter line - something a static entry
cannot express at all.

        int bpf_binprm_set_flags(struct linux_binprm *bprm,
                                 enum bpf_binprm_flags flags);

chooses the invocation flags for this exec, with
BPF_BINPRM_PRESERVE_ARGV0, BPF_BINPRM_CREDENTIALS and
BPF_BINPRM_EXECFD mapping to 'P', 'C' and 'O'. Unknown bits are
rejected so a program built against a newer kernel fails loudly on an
older one rather than silently losing a flag. Repeated calls replace
the staged flags and a zero argument clears them again - the
set-or-clear semantics of bpf_bprm_opts_set() on the same struct. A
flags word carries this better than a kfunc per flag: it is one call,
it is set atomically, and new behaviour is a new bit rather than new
surface - the same shape the register string's flags field already
has.

All three stage their result in the bprm; consuming it from
load_misc_binary() is wired up by the following patches. The bprm is
exclusively owned by the task doing the exec, so no shared or per-CPU
state is involved and nothing here can race. The kfuncs are registered
for struct_ops programs with a filter that limits them to the load
program of a binfmt_misc_ops instance, keyed off the struct_ops member
offset the program attaches to: match decides whether a handler
applies, load decides how the binary is run, and the verifier enforces
that split at program load time.

Registering an ops instance (updating the struct_ops map or attaching
its link) publishes the handler under its name in a registry keyed by
the registering task's user namespace. Lookups do not walk that
hierarchy: a handler is only visible in the user namespace it was
registered in, so an entry can only reference a handler registered in
the same user namespace as its binfmt_misc instance. Consumers take a
reference on the ops via bpf_struct_ops_get() which pins the underlying
map and programs, so an activated handler keeps working even if the map
is deleted or the registering container goes away; deregistration only
prevents new activations, exactly like unregistering a tcp congestion
ops with live users.

Link: https://lore.kernel.org/20260704211409.1978485-1-farid.m.zakaria@gmail.com
Link: https://patch.msgid.link/20260714-work-bpf-binfmt_misc-v2-2-57b7529c002c@kernel.org
Signed-off-by: Christian Brauner (Amutable) <brauner@kernel.org>
2026-08-03 10:08:41 +02:00
..
acpi ACPICA: Define acpi_ut_safe_strncpy() as strscpy_pad() alias 2026-07-01 12:29:24 +02:00
asm-generic mm.git review status for mm-hotfixes-stable..mm-nonmm-stable 2026-06-21 13:20:19 -07:00
clocksource
crypto Networking changes for 7.2. 2026-06-17 08:17:00 +01:00
cxl cxl/region: Introduce devm_cxl_probe_mem() 2026-06-12 13:47:30 -07:00
drm drm-misc-fixes for v7.2-rc5: 2026-07-24 18:30:29 +10:00
dt-bindings SoC fixes for 7.2 2026-07-17 08:52:09 -07:00
hyperv
keys keys: Pin request_key_auth payload in instantiate paths 2026-06-15 15:19:13 +03:00
kunit linux_kselftest-kunit-7.2-rc1 2026-06-16 16:33:57 +05:30
kvm Merge branch kvm-arm64/vgic-v5-PPI-fixes into kvmarm-master/next 2026-06-12 09:08:31 +01:00
linux binfmt_misc: add binfmt_misc_ops bpf struct_ops 2026-08-03 10:08:41 +02:00
math-emu
media media: v4l2-fwnode: Fix subdev owner overwritten in v4l2_async_register_subdev_sensor() 2026-06-05 10:28:03 +03:00
memory
misc
net tcp: challenge ACK for non-exact RST in SYN-RECEIVED 2026-07-23 08:27:22 -07:00
pcmcia Replace <linux/mod_devicetable.h> by more specific <linux/device-id/*.h> (headers) 2026-07-03 07:38:16 +02:00
ras
rdma RDMA v7.2 merge window 2026-06-18 08:16:21 -07:00
rv
scsi scsi: core: wake eh reliably when using scsi_schedule_eh 2026-07-12 22:21:22 -04:00
soc soc/tegra: pmc: Fixes for v7.2 2026-07-10 14:40:52 +02:00
sound Replace <linux/mod_devicetable.h> by more specific <linux/device-id/*.h> (headers) 2026-07-03 07:38:16 +02:00
target
trace mm/memory-failure: trace: change memory_failure_event to ras subsystem 2026-07-09 15:48:56 -07:00
uapi io_uring-7.2-20260724 2026-07-24 19:58:03 -07:00
ufs Merge branch 7.1/scsi-fixes into 7.2/scsi-staging 2026-06-15 21:01:30 -04:00
vdso
video
xen xen: Replace __ASSEMBLY__ with __ASSEMBLER__ in header files 2026-07-01 09:49:52 +02:00
Kbuild