[RFC PATCH v2] binfmt_misc: add binfmt_misc_select tracepoint
flat view
From: Eneshan Karaca <hidden>
Date: 2026-10-29 18:59:04
Also in:
bpf, linux-fsdevel, linux-mm, lkml
Subsystem:
exec & binfmt api, elf, filesystems (vfs and infrastructure), the rest, tracing · Maintainers:
Kees Cook, Alexander Viro, Christian Brauner, Linus Torvalds, Steven Rostedt, Masami Hiramatsu
From: Eneshan Erdoğan Karaca <redacted> A binfmt_misc entry can select an interpreter for an exec. With a BPF 'B' handler, that selection can be made by a BPF struct_ops program. The kernel commits the decision in bprm->interp and bprm->flags, but it does not emit an event at the selection point. Existing observers have to reconstruct the decision from /proc/PID/exe, AT_EXECFD, AT_FLAGS, or /proc/PID/maps. These sources are mode-dependent: a transparent dispatch still reports the original binary in /proc/PID/exe, and a short-lived process can exit before the observer reads it. A classic dispatch reports the interpreter, but not which handler selected it or which invocation flags were used. Add a tracepoint after the interpreter and the invocation flags are selected. The caller passes the matched entry and the raw flags; the trace event resolves the handler name and masks the flags with MISC_FMT_INVOCATION_FLAGS. The event reports the binary filename, the selected interpreter, the handler name, the invocation flags, and the pid. The tracepoint is observability only; it does not change exec behavior. Assisted-by: LLM Signed-off-by: Eneshan Erdoğan Karaca <redacted> --- v2: - Pass the matched entry and the raw flags to the tracepoint. - Resolve the handler name and mask the flags in the trace event. Thanks to Steven Rostedt for the review and the claws-mail tip. The PoC and A/B results are available on request. fs/binfmt_misc.c | 9 +++++ include/trace/events/binfmt_misc.h | 55 ++++++++++++++++++++++++++++++ 2 files changed, 64 insertions(+) create mode 100644 include/trace/events/binfmt_misc.h
diff --git a/fs/binfmt_misc.c b/fs/binfmt_misc.c
index 620da85..58a8283 100644
--- a/fs/binfmt_misc.c
+++ b/fs/binfmt_misc.c@@ -118,6 +118,13 @@ struct binfmt_misc_entry { char buf[]; /* register string, fields point in here */ }; +/* + * The trace event needs struct binfmt_misc_entry and the MISC_FMT_* + * flags, so include it after they are defined. + */ +#define CREATE_TRACE_POINTS +#include <trace/events/binfmt_misc.h> + /* * Max length of the register string. Determined by: * - 7 delimiters
@@ -644,6 +651,8 @@ static int load_misc_binary(struct linux_binprm *bprm) flags = entry_invocation_flags(fmt, bprm); + trace_binfmt_misc_select(bprm, fmt, interpreter, flags); + /* No argv is built for a staged argument to land in. */ if ((flags & (MISC_FMT_LOADER | MISC_FMT_TRANSPARENT)) && bprm->bpf_interp_arg)
diff --git a/include/trace/events/binfmt_misc.h b/include/trace/events/binfmt_misc.h
new file mode 100644
index 0000000..61a0de0
--- /dev/null
+++ b/include/trace/events/binfmt_misc.h@@ -0,0 +1,55 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Tracepoint for binfmt_misc binary type handler dispatch. + * + * Fires once for every exec a binfmt_misc entry matches, after the + * interpreter and the invocation flags have been selected. Unlike + * sched_process_exec (which reports bprm->filename) and /proc/PID/exe + * (which a transparent dispatch sets to the binary), this reports the + * interpreter that actually runs, so observers can see through a + * transparent dispatch. + */ +#undef TRACE_SYSTEM +#define TRACE_SYSTEM binfmt_misc + +#if !defined(_TRACE_BINFMT_MISC_H) || defined(TRACE_HEADER_MULTI_READ) +#define _TRACE_BINFMT_MISC_H + +#include <linux/tracepoint.h> +#include <linux/binfmts.h> +#include <linux/binfmt_misc.h> +#include <linux/bitops.h> + +TRACE_EVENT(binfmt_misc_select, + + TP_PROTO(struct linux_binprm *bprm, const struct binfmt_misc_entry *fmt, + const char *interp, unsigned long flags), + + TP_ARGS(bprm, fmt, interp, flags), + + TP_STRUCT__entry( + __string(filename, bprm->filename) + __string(interp, interp) + __string(handler, test_bit(MISC_FMT_BPF_BIT, &fmt->flags) ? + fmt->bpf_ops->name : "") + __field(unsigned long, flags) + __field(pid_t, pid) + ), + + TP_fast_assign( + __assign_str(filename); + __assign_str(interp); + __assign_str(handler); + __entry->flags = flags & MISC_FMT_INVOCATION_FLAGS; + __entry->pid = current->pid; + ), + + TP_printk("pid=%d filename=%s interp=%s handler=%s flags=%#lx", + __entry->pid, __get_str(filename), __get_str(interp), + __get_str(handler), __entry->flags) +); + +#endif /* _TRACE_BINFMT_MISC_H */ + +/* This part must be outside protection */ +#include <trace/define_trace.h> --
2.53.0