Re: [RFC PATCH] binfmt_misc: add binfmt_misc_select tracepoint

From: Steven Rostedt

Date: Mon Oct 26 2026 - 16:29:10 EST



You shouldn't attach patches but inline them. Yeah, I know a lot of email
clients can't handle that. But claws-mail can! (and it can also reply to
attachments like they were inlined ;-) ).

I'll let others comment on whether or not this patch is needed, but I'll
comment on the tracing side of things.


On Mon, 26 Oct 2026 20:17:26 +0000
BoxStrikesTeam <BoxStrikesTeam@xxxxxxxxx> wrote:

> From: Eneshan Erdoğan Karaca <BoxStrikesTeam@xxxxxxxxx>
> Subject: [RFC PATCH] binfmt_misc: add binfmt_misc_select tracepoint
>
> 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. It reports the binary filename, the selected interpreter,
> the handler name (for BPF handlers), the invocation flags, and the
> pid. The flags are masked with MISC_FMT_INVOCATION_FLAGS so that
> static entry state does not leak into the event.
>
> The tracepoint is observability only; it does not change exec
> behavior.
>
> Assisted-by: LLM
> Signed-off-by: Eneshan Erdoğan Karaca <BoxStrikesTeam@xxxxxxxxx>
> ---
>
> This is an RFC. A small PoC and short A/B results are available for
> context; they are not needed to review the patch.
>
> fs/binfmt_misc.c | 8 ++++++++
> include/trace/events/binfmt_misc.h | 52 ++++++++++++++++++++++++++++++++++++++
> 2 files changed, 60 insertions(+)
>
> diff --git a/fs/binfmt_misc.c b/fs/binfmt_misc.c
> --- a/fs/binfmt_misc.c
> +++ b/fs/binfmt_misc.c
> @@ -41,6 +41,9 @@
>
> #include "internal.h"
>
> +#define CREATE_TRACE_POINTS
> +#include <trace/events/binfmt_misc.h>
> +
> /* Entry status and match type bit numbers. */
> enum binfmt_misc_entry_bits {
> MISC_FMT_ENABLED_BIT = 0,
> @@ -644,6 +647,11 @@
>
> flags = entry_invocation_flags(fmt, bprm);
>
> + trace_binfmt_misc_select(bprm, interpreter,
> + test_bit(MISC_FMT_BPF_BIT, &fmt->flags) ?
> + fmt->bpf_ops->name : "",
> + flags & MISC_FMT_INVOCATION_FLAGS);

Logic like the above should be done in the trace event itself. Not in the
code path. That is, pass in fmt and 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
> --- /dev/null
> +++ b/include/trace/events/binfmt_misc.h
> @@ -0,0 +1,52 @@
> +/* 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>
> +
> +TRACE_EVENT(binfmt_misc_select,
> +
> + TP_PROTO(struct linux_binprm *bprm, const char *interp,
> + const char *handler, unsigned long flags),
> +
> + TP_ARGS(bprm, interp, handler, flags),
> +
> + TP_STRUCT__entry(
> + __string(filename, bprm->filename)
> + __string(interp, interp)
> + __string(handler, handler)

Then here you would have:

__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;

and here:

__entry->flags = flags & MISC_FMT_INVOCATION_FLAGS;

-- Steve


> + __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>