[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
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help