Skip to content

Commit 0133c20

Browse files
anakryikoborkmann
authored andcommitted
selftests/bpf: Fix strobemeta selftest regression
After most recent nightly Clang update strobemeta selftests started failing with the following error (relevant portion of assembly included): 1624: (85) call bpf_probe_read_user_str#114 1625: (bf) r1 = r0 1626: (18) r2 = 0xfffffffe 1628: (5f) r1 &= r2 1629: (55) if r1 != 0x0 goto pc+7 1630: (07) r9 += 104 1631: (6b) *(u16 *)(r9 +0) = r0 1632: (67) r0 <<= 32 1633: (77) r0 >>= 32 1634: (79) r1 = *(u64 *)(r10 -456) 1635: (0f) r1 += r0 1636: (7b) *(u64 *)(r10 -456) = r1 1637: (79) r1 = *(u64 *)(r10 -368) 1638: (c5) if r1 s< 0x1 goto pc+778 1639: (bf) r6 = r8 1640: (0f) r6 += r7 1641: (b4) w1 = 0 1642: (6b) *(u16 *)(r6 +108) = r1 1643: (79) r3 = *(u64 *)(r10 -352) 1644: (79) r9 = *(u64 *)(r10 -456) 1645: (bf) r1 = r9 1646: (b4) w2 = 1 1647: (85) call bpf_probe_read_user_str#114 R1 unbounded memory access, make sure to bounds check any such access In the above code r0 and r1 are implicitly related. Clang knows that, but verifier isn't able to infer this relationship. Yonghong Song narrowed down this "regression" in code generation to a recent Clang optimization change ([0]), which for BPF target generates code pattern that BPF verifier can't handle and loses track of register boundaries. This patch works around the issue by adding an BPF assembly-based helper that helps to prove to the verifier that upper bound of the register is a given constant by controlling the exact share of generated BPF instruction sequence. This fixes the immediate issue for strobemeta selftest. [0] llvm/llvm-project@acabad9 Signed-off-by: Andrii Nakryiko <[email protected]> Signed-off-by: Daniel Borkmann <[email protected]> Acked-by: Yonghong Song <[email protected]> Link: https://lore.kernel.org/bpf/[email protected]
1 parent 8a03e56 commit 0133c20

File tree

1 file changed

+11
-0
lines changed

1 file changed

+11
-0
lines changed

tools/testing/selftests/bpf/progs/strobemeta.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,14 @@
1010
#include <linux/types.h>
1111
#include <bpf/bpf_helpers.h>
1212

13+
#define bpf_clamp_umax(VAR, UMAX) \
14+
asm volatile ( \
15+
"if %0 <= %[max] goto +1\n" \
16+
"%0 = %[max]\n" \
17+
: "+r"(VAR) \
18+
: [max]"i"(UMAX) \
19+
)
20+
1321
typedef uint32_t pid_t;
1422
struct task_struct {};
1523

@@ -413,6 +421,7 @@ static __always_inline void *read_map_var(struct strobemeta_cfg *cfg,
413421

414422
len = bpf_probe_read_user_str(payload, STROBE_MAX_STR_LEN, map.tag);
415423
if (len <= STROBE_MAX_STR_LEN) {
424+
bpf_clamp_umax(len, STROBE_MAX_STR_LEN);
416425
descr->tag_len = len;
417426
payload += len;
418427
}
@@ -430,13 +439,15 @@ static __always_inline void *read_map_var(struct strobemeta_cfg *cfg,
430439
len = bpf_probe_read_user_str(payload, STROBE_MAX_STR_LEN,
431440
map.entries[i].key);
432441
if (len <= STROBE_MAX_STR_LEN) {
442+
bpf_clamp_umax(len, STROBE_MAX_STR_LEN);
433443
descr->key_lens[i] = len;
434444
payload += len;
435445
}
436446
descr->val_lens[i] = 0;
437447
len = bpf_probe_read_user_str(payload, STROBE_MAX_STR_LEN,
438448
map.entries[i].val);
439449
if (len <= STROBE_MAX_STR_LEN) {
450+
bpf_clamp_umax(len, STROBE_MAX_STR_LEN);
440451
descr->val_lens[i] = len;
441452
payload += len;
442453
}

0 commit comments

Comments
 (0)