diff mbox series

[bpf-next] selftests/bpf: fix strobemeta selftest regression

Message ID 20211029182907.166910-1-andrii@kernel.org (mailing list archive)
State Accepted
Commit 0133c20480b14820d43c37c0e9502da4bffcad3a
Delegated to: BPF
Headers show
Series [bpf-next] selftests/bpf: fix strobemeta selftest regression | expand

Checks

Context Check Description
netdev/cover_letter success Single patches do not need cover letters
netdev/fixes_present success Fixes tag not required for -next series
netdev/patch_count success Link
netdev/tree_selection success Clearly marked for bpf-next
netdev/subject_prefix success Link
netdev/cc_maintainers warning 11 maintainers not CCed: john.fastabend@gmail.com linux-kselftest@vger.kernel.org yhs@fb.com netdev@vger.kernel.org songliubraving@fb.com ndesaulniers@google.com nathan@kernel.org llvm@lists.linux.dev kafai@fb.com kpsingh@kernel.org shuah@kernel.org
netdev/source_inline success Was 0 now: 0
netdev/verify_signedoff success Signed-off-by tag matches author and committer
netdev/module_param success Was 0 now: 0
netdev/build_32bit success Errors and warnings before: 0 this patch: 0
netdev/kdoc success Errors and warnings before: 0 this patch: 0
netdev/verify_fixes success No Fixes tag
netdev/checkpatch fail ERROR: Macros with complex values should be enclosed in parentheses
netdev/build_allmodconfig_warn success Errors and warnings before: 0 this patch: 0
netdev/header_inline success No static functions without inline keyword in header files
bpf/vmtest-bpf-next fail VM_Test
bpf/vmtest-bpf-next-PR fail PR summary

Commit Message

Andrii Nakryiko Oct. 29, 2021, 6:29 p.m. UTC
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] https://github.com/llvm/llvm-project/commit/acabad9ff6bf13e00305d9d8621ee8eafc1f8b08

Signed-off-by: Andrii Nakryiko <andrii@kernel.org>
---
 tools/testing/selftests/bpf/progs/strobemeta.h | 11 +++++++++++
 1 file changed, 11 insertions(+)

Comments

Yonghong Song Oct. 29, 2021, 7:07 p.m. UTC | #1
On 10/29/21 11:29 AM, Andrii Nakryiko wrote:
> 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] https://github.com/llvm/llvm-project/commit/acabad9ff6bf13e00305d9d8621ee8eafc1f8b08
> 
> Signed-off-by: Andrii Nakryiko <andrii@kernel.org>

I am working on a llvm compiler solution which may take some time.
For the time being, the workaround looks good to me.

Acked-by: Yonghong Song <yhs@fb.com>
patchwork-bot+netdevbpf@kernel.org Nov. 1, 2021, 4:20 p.m. UTC | #2
Hello:

This patch was applied to bpf/bpf-next.git (master)
by Daniel Borkmann <daniel@iogearbox.net>:

On Fri, 29 Oct 2021 11:29:07 -0700 you wrote:
> 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
> 
> [...]

Here is the summary with links:
  - [bpf-next] selftests/bpf: fix strobemeta selftest regression
    https://git.kernel.org/bpf/bpf-next/c/0133c20480b1

You are awesome, thank you!
diff mbox series

Patch

diff --git a/tools/testing/selftests/bpf/progs/strobemeta.h b/tools/testing/selftests/bpf/progs/strobemeta.h
index 7de534f38c3f..3687ea755ab5 100644
--- a/tools/testing/selftests/bpf/progs/strobemeta.h
+++ b/tools/testing/selftests/bpf/progs/strobemeta.h
@@ -10,6 +10,14 @@ 
 #include <linux/types.h>
 #include <bpf/bpf_helpers.h>
 
+#define bpf_clamp_umax(VAR, UMAX)					\
+	asm volatile (							\
+		"if %0 <= %[max] goto +1\n"				\
+		"%0 = %[max]\n"						\
+		: "+r"(VAR)						\
+		: [max]"i"(UMAX)					\
+	)
+
 typedef uint32_t pid_t;
 struct task_struct {};
 
@@ -413,6 +421,7 @@  static __always_inline void *read_map_var(struct strobemeta_cfg *cfg,
 
 	len = bpf_probe_read_user_str(payload, STROBE_MAX_STR_LEN, map.tag);
 	if (len <= STROBE_MAX_STR_LEN) {
+		bpf_clamp_umax(len, STROBE_MAX_STR_LEN);
 		descr->tag_len = len;
 		payload += len;
 	}
@@ -430,6 +439,7 @@  static __always_inline void *read_map_var(struct strobemeta_cfg *cfg,
 		len = bpf_probe_read_user_str(payload, STROBE_MAX_STR_LEN,
 					      map.entries[i].key);
 		if (len <= STROBE_MAX_STR_LEN) {
+			bpf_clamp_umax(len, STROBE_MAX_STR_LEN);
 			descr->key_lens[i] = len;
 			payload += len;
 		}
@@ -437,6 +447,7 @@  static __always_inline void *read_map_var(struct strobemeta_cfg *cfg,
 		len = bpf_probe_read_user_str(payload, STROBE_MAX_STR_LEN,
 					      map.entries[i].val);
 		if (len <= STROBE_MAX_STR_LEN) {
+			bpf_clamp_umax(len, STROBE_MAX_STR_LEN);
 			descr->val_lens[i] = len;
 			payload += len;
 		}