Re: [PATCH v5 11/23] perf trace: Do not set unaugmented BPF program on sys_exit map

From: Namhyung Kim

Date: Thu Sep 24 2026 - 18:49:50 EST


On Wed, Sep 23, 2026 at 12:13:51AM -0700, Ian Rogers wrote:
> In trace__init_syscalls_bpf_prog_array_maps(), the BPF program array map
> for sys_exit (syscalls_sys_exit) was populated with the result of
> trace__bpf_prog_sys_exit_fd().
>
> When a syscall had no specific exit augmenter,
> trace__find_syscall_bpf_prog() fell back to unaugmented_prog
> (syscall_unaugmented). However, syscall_unaugmented is a sys_enter
> program that outputs enter arguments to __augmented_syscalls__.
>
> As a consequence, when an unaugmented syscall exited, sys_exit
> tail-called syscall_unaugmented, which interpreted the exit arguments as
> enter arguments and emitted a duplicate, corrupt sys_enter event into
> __augmented_syscalls__ right as the syscall completed.

Do you have a reproducer of this problem? I've never seen this before.
IIRC there's no augmentation at exit, then do we need to keep the tail
call?

Thanks,
Namhyung

>
> Fix this by:
> 1. Returning NULL from trace__find_syscall_bpf_prog() when looking up exit
> augmenters and none is found.
> 2. Returning -1 from trace__bpf_prog_sys_exit_fd() when no exit program
> is present.
> 3. Only updating map_exit_fd when prog_fd >= 0.
> 4. Clearing err = 0 when trace__bpf_sys_enter_beauty_map() returns
> non-zero (indicating the syscall has no augmentable pointer arguments)
> before continuing the loop, so a trailing run of such syscalls (e.g.
> 'perf trace -e close') does not leave err non-zero on return and abort
> the session.
>
> Assisted-by: Antigravity:gemini-3.1-pro
> Signed-off-by: Ian Rogers <irogers@xxxxxxxxxx>
> ---
> tools/perf/builtin-trace.c | 28 ++++++++++++++++++++++------
> 1 file changed, 22 insertions(+), 6 deletions(-)
>
> diff --git a/tools/perf/builtin-trace.c b/tools/perf/builtin-trace.c
> index aa2d64eb56bd..0ae14ecd9f00 100644
> --- a/tools/perf/builtin-trace.c
> +++ b/tools/perf/builtin-trace.c
> @@ -4176,7 +4176,12 @@ static struct bpf_program *trace__find_syscall_bpf_prog(struct trace *trace __ma
> pr_debug("Couldn't find BPF prog \"%s\" to associate with syscalls:sys_%s_%s, not augmenting it\n",
> prog_name, type, sc->name);
> out_unaugmented:
> - return unaugmented_prog;
> + /*
> + * Do not set unaugmented_prog for exit: syscall_unaugmented is a
> + * sys_enter program that outputs enter arguments. Exit without a
> + * specialized return augmenter returns 1 directly from sys_exit.
> + */
> + return !strcmp(type, "exit") ? NULL : unaugmented_prog;
> }
>
> static void trace__init_syscall_bpf_progs(struct trace *trace, int e_machine, int id)
> @@ -4199,7 +4204,7 @@ static int trace__bpf_prog_sys_enter_fd(struct trace *trace, int e_machine, int
> static int trace__bpf_prog_sys_exit_fd(struct trace *trace, int e_machine, int id)
> {
> struct syscall *sc = trace__syscall_info(trace, NULL, e_machine, id);
> - return sc ? bpf_program__fd(sc->bpf_prog.sys_exit) : bpf_program__fd(unaugmented_prog);
> + return sc && sc->bpf_prog.sys_exit ? bpf_program__fd(sc->bpf_prog.sys_exit) : -1;
> }
>
> static int trace__bpf_sys_enter_beauty_map(struct trace *trace, int e_machine, int key, unsigned int *beauty_array)
> @@ -4454,16 +4459,27 @@ static int trace__init_syscalls_bpf_prog_array_maps(struct trace *trace, int e_m
> err = bpf_map_update_elem(map_enter_fd, &key, &prog_fd, BPF_ANY);
> if (err)
> break;
> + /* Only update the exit prog array map if an exit augmenter exists */
> prog_fd = trace__bpf_prog_sys_exit_fd(trace, e_machine, key);
> - err = bpf_map_update_elem(map_exit_fd, &key, &prog_fd, BPF_ANY);
> - if (err)
> - break;
> + if (prog_fd >= 0) {
> + err = bpf_map_update_elem(map_exit_fd, &key, &prog_fd, BPF_ANY);
> + if (err)
> + break;
> + }
>
> /* use beauty_map to tell BPF how many bytes to collect, set beauty_map's value here */
> memset(beauty_array, 0, sizeof(beauty_array));
> err = trace__bpf_sys_enter_beauty_map(trace, e_machine, key, (unsigned int *)beauty_array);
> - if (err)
> + if (err) {
> + /*
> + * Not a failure: the syscall just has no augmentable
> + * arguments. Clear err, or a trailing run of such
> + * syscalls, e.g. all of them for 'perf trace -e close',
> + * would leave it set on return and abort the session.
> + */
> + err = 0;
> continue;
> + }
> err = bpf_map_update_elem(beauty_map_fd, &key, beauty_array, BPF_ANY);
> if (err)
> break;
> --
> 2.56.0.rc1.315.gc6ed9934b7-goog
>