From: Viktor Malik <vmalik@redhat.com>
To: linux-perf-users@vger.kernel.org
Cc: Peter Zijlstra <peterz@infradead.org>,
Ingo Molnar <mingo@redhat.com>,
Arnaldo Carvalho de Melo <acme@kernel.org>,
Namhyung Kim <namhyung@kernel.org>,
Mark Rutland <mark.rutland@arm.com>,
Alexander Shishkin <alexander.shishkin@linux.intel.com>,
Jiri Olsa <jolsa@kernel.org>, Ian Rogers <irogers@google.com>,
Adrian Hunter <adrian.hunter@intel.com>,
James Clark <james.clark@linaro.org>,
Viktor Malik <vmalik@redhat.com>,
Howard Chu <howardchu95@gmail.com>,
linux-kernel@vger.kernel.org, bpf@vger.kernel.org,
Michael Petlan <mpetlan@redhat.com>,
Andrii Nakryiko <andrii@kernel.org>,
stable@vger.kernel.org
Subject: [PATCH v4 2/2] perf trace: Refactor augmented_raw_syscalls using bpf_for
Date: Tue, 7 Jul 2026 08:52:47 +0200 [thread overview]
Message-ID: <a4a363ae325a670ba122fee2cabcebc7ecd236bd.1783406979.git.vmalik@redhat.com> (raw)
In-Reply-To: <cover.1783406979.git.vmalik@redhat.com>
The loop for processing syscall args in augment_raw_syscalls has a
history of breaking with Clang updates, see e.g. commit 013eb043f37b
("perf trace: Fix BPF loading failure (-E2BIG)") from Clang 15 to 16.
Now, a similar thing happened between Clang 21 and 22. While the issue
is mitigated on the main line by a recent verifier update, it remains
broken on the 6.12 and 6.18 stable branches:
[linux-6.18.y]# sudo perf trace true
libbpf: prog 'sys_enter': BPF program load failed: -E2BIG
libbpf: prog 'sys_enter': -- BEGIN PROG LOAD LOG --
[...]
BPF program is too large. Processed 1000001 insn
processed 1000001 insns (limit 1000000) max_states_per_insn 40 total_states 37941 peak_states 232 mark_read 0
-- END PROG LOAD LOG --
libbpf: prog 'sys_enter': failed to load: -E2BIG
libbpf: failed to load object 'augmented_raw_syscalls_bpf'
libbpf: failed to load BPF skeleton 'augmented_raw_syscalls_bpf': -E2BIG
Error: failed to get syscall or beauty map fd
[...]
The reason is that the loop is quite complex and the BPF verifier often
struggles to prove that it terminates.
Fix the issue by replacing the standard for loop with the bpf_for macro,
which uses a numeric BPF iterator. This should prevent future breakages
of this kind since the verifier has a much easier job proving that the
loop terminates.
Small adjustments were necessary for the loop to make it work. The main
problem is that the verifier sometimes has problems with bpf_for loops
that use a carry-over state, such as the `payload_offset` and `output`
vars here, since the verifier tries to track their values too precisely
and cannot prove loop convergence. To resolve the issue, we (1)
explicitly recompute `payload_offset` in every iteration and (2) use a
trick with adding a global zero to `output` to help the verifier forget
its precise state and use a range instead.
Finally, to keep backwards compatibility with older kernel versions that
don't have bpf_for (i.e. numeric iterators), fall back to standard loop.
Signed-off-by: Viktor Malik <vmalik@redhat.com>
Suggested-by: Andrii Nakryiko <andrii@kernel.org>
Fixes: a68fd6a6cdd3 ("perf trace: Collect augmented data using BPF")
Cc: stable@vger.kernel.org
---
.../bpf_skel/augmented_raw_syscalls.bpf.c | 47 ++++++++++++++-----
1 file changed, 35 insertions(+), 12 deletions(-)
diff --git a/tools/perf/util/bpf_skel/augmented_raw_syscalls.bpf.c b/tools/perf/util/bpf_skel/augmented_raw_syscalls.bpf.c
index bc036a348079..3bc9e28a9b8a 100644
--- a/tools/perf/util/bpf_skel/augmented_raw_syscalls.bpf.c
+++ b/tools/perf/util/bpf_skel/augmented_raw_syscalls.bpf.c
@@ -429,6 +429,8 @@ static bool pid_filter__has(struct pids_filtered *pids, pid_t pid)
return bpf_map_lookup_elem(pids, &pid) != NULL;
}
+u64 ZERO = 0;
+
/*
* Determine what type of argument and how many bytes to read from user space, using the
* value in the beauty_map. This is the relation of parameter type and its corresponding
@@ -440,9 +442,10 @@ static bool pid_filter__has(struct pids_filtered *pids, pid_t pid)
*/
static inline int augment_arg(struct syscall_enter_args *args, int i,
unsigned int *beauty_map,
- struct augmented_arg *payload_offset)
+ struct beauty_payload_enter *payload, u64 offset)
{
int index, value_size = sizeof(struct augmented_arg) - offsetof(struct augmented_arg, value);
+ struct augmented_arg *payload_offset;
s64 aug_size, size;
bool augmented;
void *arg;
@@ -455,6 +458,12 @@ static inline int augment_arg(struct syscall_enter_args *args, int i,
if (size == 0 || arg == NULL)
return 0;
+ /* bounds check for the verifier */
+ if (offset > sizeof(payload->aug_args) - sizeof(payload->aug_args[0]))
+ return -1;
+ barrier_var(offset);
+ payload_offset = (struct augmented_arg *)((void *)&payload->aug_args + offset);
+
if (size == 1) { /* string */
aug_size = bpf_probe_read_user_str(payload_offset->value, value_size, arg);
/* minimum of 0 to pass the verifier */
@@ -498,11 +507,10 @@ static inline int augment_arg(struct syscall_enter_args *args, int i,
static int augment_sys_enter(void *ctx, struct syscall_enter_args *args)
{
bool do_output = false;
- int zero = 0, written;
+ int i, zero = 0, written;
u64 output = 0; /* has to be u64, otherwise it won't pass the verifier */
unsigned int nr, *beauty_map;
struct beauty_payload_enter *payload;
- void *payload_offset;
/* fall back to do predefined tail call */
if (args == NULL)
@@ -514,7 +522,6 @@ static int augment_sys_enter(void *ctx, struct syscall_enter_args *args)
/* set up payload for output */
payload = bpf_map_lookup_elem(&beauty_payload_enter_map, &zero);
- payload_offset = (void *)&payload->aug_args;
if (beauty_map == NULL || payload == NULL)
return 1;
@@ -522,14 +529,30 @@ static int augment_sys_enter(void *ctx, struct syscall_enter_args *args)
/* copy the sys_enter header, which has the syscall_nr */
__builtin_memcpy(&payload->args, args, sizeof(struct syscall_enter_args));
- for (int i = 0; i < 6; i++) {
- written = augment_arg(args, i, beauty_map, (struct augmented_arg *)payload_offset);
- if (written < 0)
- return 1;
- if (written > 0) {
- output += written;
- payload_offset += written;
- do_output = true;
+ if (bpf_ksym_exists(bpf_iter_num_new)) {
+ bpf_for(i, 0, 6) {
+ written = augment_arg(args, i, beauty_map, payload, output);
+ if (written < 0)
+ return 1;
+ if (written > 0) {
+ output += written;
+ /*
+ * guide the verifier to forget range of `output`, which
+ * helps to prove convergence of the loop
+ */
+ output += ZERO;
+ do_output = true;
+ }
+ }
+ } else {
+ for (i = 0; i < 6; i++) {
+ written = augment_arg(args, i, beauty_map, payload, output);
+ if (written < 0)
+ return 1;
+ if (written > 0) {
+ output += written;
+ do_output = true;
+ }
}
}
--
2.54.0
prev parent reply other threads:[~2026-07-07 6:53 UTC|newest]
Thread overview: 3+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-07-07 6:52 [PATCH v4 0/2] perf trace: Refactor augmented_raw_syscalls using bpf_for Viktor Malik
2026-07-07 6:52 ` [PATCH v4 1/2] perf trace: Factor out BPF loop body Viktor Malik
2026-07-07 6:52 ` Viktor Malik [this message]
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=a4a363ae325a670ba122fee2cabcebc7ecd236bd.1783406979.git.vmalik@redhat.com \
--to=vmalik@redhat.com \
--cc=acme@kernel.org \
--cc=adrian.hunter@intel.com \
--cc=alexander.shishkin@linux.intel.com \
--cc=andrii@kernel.org \
--cc=bpf@vger.kernel.org \
--cc=howardchu95@gmail.com \
--cc=irogers@google.com \
--cc=james.clark@linaro.org \
--cc=jolsa@kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-perf-users@vger.kernel.org \
--cc=mark.rutland@arm.com \
--cc=mingo@redhat.com \
--cc=mpetlan@redhat.com \
--cc=namhyung@kernel.org \
--cc=peterz@infradead.org \
--cc=stable@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox