[RFC] binfmt_misc: add a tracepoint for BPF-selected interpreters

From: BoxStrikesTeam

Date: Sat Oct 24 2026 - 13:29:49 EST


Hello,
The 'B' (BPF struct_ops) binfmt_misc handlers added in v7.3 can
select an interpreter per exec.  In transparent mode the selected
interpreter is not visible through the usual interfaces:
/proc/PID/exe, /proc/PID/cmdline and sched_process_exec all describe
the binary, not the interpreter that actually runs.  That is useful
for concealment, and it also leaves tracing and security monitoring
blind to the dispatch.

I built a small PoC to understand the mechanism and measure the gap.
It registers three struct_ops handlers (classic, transparent, loader)
and runs each target twice: once without a handler, once with the
handler and entry active.  In the transparent case the process sees
/tmp/target_trans as its exe and keeps its argv, while the code that
runs is /tmp/poc_interp, reached through AT_EXECFD.  In the loader
case the binary runs natively and only the PT_INTERP loader changes;
/proc/self/maps and AT_BASE show the substitution.  The match program
checks the ELF magic and marker bytes in the e_ident padding; it does
not check the machine type, so the PoC is architecture-independent
and does not target a specific real binary format.

The official binfmt_misc_bpf selftest passes 16/16 on the same
kernel (v7.3-rc7).  The test needed a small arm64 adaptation because
it assumes an x86_64 host: the foreign-architecture constants and the
interp_bind match rule were adjusted, while the assertions and
coverage are unchanged.

The gap is not a bug in the feature; it is a missing observation
point.  I would like to propose a tracepoint after the entry has
selected its interpreter and the invocation flags are final:

  binfmt_misc_select(struct linux_binprm *bprm, const char *interp,
                     const char *handler, unsigned long flags)

The event would record filename, interp, handler, flags and pid.
handler is the struct_ops name for a 'B' entry and empty for a static
entry; flags is masked with MISC_FMT_INVOCATION_FLAGS so only the
P/C/O/F/T/L bits are reported.  The event is disabled by default and
costs a static key check when off.  It does not change dispatch
behaviour.

I tested a patch on v7.3-rc7-32-g0fcb05b72344 (2 files, 60
insertions).  In an A/B run the event does not fire without a
matching entry; with a classic handler it reports flags=0x0, and
with a transparent handler it reports:

  binfmt_misc_select: pid=96 filename=/tmp/target_trans \
      interp=/tmp/poc_interp handler=poc_transparent flags=0x48000000

while the process itself still sees /tmp/target_trans as its exe.
The selftest stays at 16/16 with the patch applied.

Before sending the patch, I would like to ask:

- Is a tracepoint the right primitive here, or would you prefer
  another interface (audit, a /proc file, a BPF iterator)?
- Is the event name and placement acceptable?  I put it in
  fs/binfmt_misc.c and the header in include/trace/events/.
- Should this go through the VFS tree or the tracing tree?
- Is the flags mask the right ABI, or should the event report the raw
  entry flags and the resolved BPF flags separately?
- Would you want this at all?

The tracepoint is observability, not enforcement.  tracefs is
normally root-only, and a root-capable attacker can turn the event
off; I am not claiming it stops a rootkit.  If the approach is
acceptable, I can send the patch as an RFC PATCH or a formal PATCH,
rebased on whichever tree you prefer.  If not, I would rather hear
that now than send code that is not wanted.

The PoC is attached as binfmt-poc-upstream.tar.gz (source and logs,
about 70K).  It includes an English README.upstream.md; some of the
original notes are in Turkish.  It needs v7.3+ with
CONFIG_BINFMT_MISC_BPF=y and root inside the VM.  The patch is not
attached yet; I can send it inline on request.  If the list strips the
PoC attachment, I can send it directly.

I prepared this email and the PoC with an LLM assistant; I reviewed
the code and ran the tests above.

Thanks,
Eneshan Erdoğan Karaca

Attachment: binfmt-poc (1).tar.gz
Description: application/gzip