Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

selftests/bpf: Add a selftest for x86 jit convergence issues

The core part of the selftest, i.e., the je <-> jmp cycle, mimics the
original sched-ext bpf program. The test will fail without the
previous patch.

I tried to create some cases for other potential cycles
(je <-> je, jmp <-> je and jmp <-> jmp) with similar pattern
to the test in this patch, but failed. So this patch
only contains one test for je <-> jmp cycle.

Signed-off-by: Yonghong Song <yonghong.song@linux.dev>
Link: https://lore.kernel.org/r/20240904221256.37389-1-yonghong.song@linux.dev
Signed-off-by: Alexei Starovoitov <ast@kernel.org>

authored by

Yonghong Song and committed by
Alexei Starovoitov
eff5b5ff c8831bdb

+116
+2
tools/testing/selftests/bpf/prog_tests/verifier.c
··· 39 39 #include "verifier_int_ptr.skel.h" 40 40 #include "verifier_iterating_callbacks.skel.h" 41 41 #include "verifier_jeq_infer_not_null.skel.h" 42 + #include "verifier_jit_convergence.skel.h" 42 43 #include "verifier_ld_ind.skel.h" 43 44 #include "verifier_ldsx.skel.h" 44 45 #include "verifier_leak_ptr.skel.h" ··· 164 163 void test_verifier_int_ptr(void) { RUN(verifier_int_ptr); } 165 164 void test_verifier_iterating_callbacks(void) { RUN(verifier_iterating_callbacks); } 166 165 void test_verifier_jeq_infer_not_null(void) { RUN(verifier_jeq_infer_not_null); } 166 + void test_verifier_jit_convergence(void) { RUN(verifier_jit_convergence); } 167 167 void test_verifier_ld_ind(void) { RUN(verifier_ld_ind); } 168 168 void test_verifier_ldsx(void) { RUN(verifier_ldsx); } 169 169 void test_verifier_leak_ptr(void) { RUN(verifier_leak_ptr); }
+114
tools/testing/selftests/bpf/progs/verifier_jit_convergence.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + /* Copyright (c) 2024 Meta Platforms, Inc. and affiliates. */ 3 + 4 + #include <linux/bpf.h> 5 + #include <bpf/bpf_helpers.h> 6 + #include "bpf_misc.h" 7 + 8 + struct value_t { 9 + long long a[32]; 10 + }; 11 + 12 + struct { 13 + __uint(type, BPF_MAP_TYPE_HASH); 14 + __uint(max_entries, 1); 15 + __type(key, long long); 16 + __type(value, struct value_t); 17 + } map_hash SEC(".maps"); 18 + 19 + SEC("socket") 20 + __description("bpf_jit_convergence je <-> jmp") 21 + __success __retval(0) 22 + __arch_x86_64 23 + __jited(" pushq %rbp") 24 + __naked void btf_jit_convergence_je_jmp(void) 25 + { 26 + asm volatile ( 27 + "call %[bpf_get_prandom_u32];" 28 + "if r0 == 0 goto l20_%=;" 29 + "if r0 == 1 goto l21_%=;" 30 + "if r0 == 2 goto l22_%=;" 31 + "if r0 == 3 goto l23_%=;" 32 + "if r0 == 4 goto l24_%=;" 33 + "call %[bpf_get_prandom_u32];" 34 + "call %[bpf_get_prandom_u32];" 35 + "l20_%=:" 36 + "l21_%=:" 37 + "l22_%=:" 38 + "l23_%=:" 39 + "l24_%=:" 40 + "r1 = 0;" 41 + "*(u64 *)(r10 - 8) = r1;" 42 + "r2 = r10;" 43 + "r2 += -8;" 44 + "r1 = %[map_hash] ll;" 45 + "call %[bpf_map_lookup_elem];" 46 + "if r0 == 0 goto l1_%=;" 47 + "r6 = r0;" 48 + "call %[bpf_get_prandom_u32];" 49 + "r7 = r0;" 50 + "r5 = r6;" 51 + "if r0 != 0x0 goto l12_%=;" 52 + "call %[bpf_get_prandom_u32];" 53 + "r1 = r0;" 54 + "r2 = r6;" 55 + "if r1 == 0x0 goto l0_%=;" 56 + "l9_%=:" 57 + "r2 = *(u64 *)(r6 + 0x0);" 58 + "r2 += 0x1;" 59 + "*(u64 *)(r6 + 0x0) = r2;" 60 + "goto l1_%=;" 61 + "l12_%=:" 62 + "r1 = r7;" 63 + "r1 += 0x98;" 64 + "r2 = r5;" 65 + "r2 += 0x90;" 66 + "r2 = *(u32 *)(r2 + 0x0);" 67 + "r3 = r7;" 68 + "r3 &= 0x1;" 69 + "r2 *= 0xa8;" 70 + "if r3 == 0x0 goto l2_%=;" 71 + "r1 += r2;" 72 + "r1 -= r7;" 73 + "r1 += 0x8;" 74 + "if r1 <= 0xb20 goto l3_%=;" 75 + "r1 = 0x0;" 76 + "goto l4_%=;" 77 + "l3_%=:" 78 + "r1 += r7;" 79 + "l4_%=:" 80 + "if r1 == 0x0 goto l8_%=;" 81 + "goto l9_%=;" 82 + "l2_%=:" 83 + "r1 += r2;" 84 + "r1 -= r7;" 85 + "r1 += 0x10;" 86 + "if r1 <= 0xb20 goto l6_%=;" 87 + "r1 = 0x0;" 88 + "goto l7_%=;" 89 + "l6_%=:" 90 + "r1 += r7;" 91 + "l7_%=:" 92 + "if r1 == 0x0 goto l8_%=;" 93 + "goto l9_%=;" 94 + "l0_%=:" 95 + "r1 = 0x3;" 96 + "*(u64 *)(r10 - 0x10) = r1;" 97 + "r2 = r1;" 98 + "goto l1_%=;" 99 + "l8_%=:" 100 + "r1 = r5;" 101 + "r1 += 0x4;" 102 + "r1 = *(u32 *)(r1 + 0x0);" 103 + "*(u64 *)(r10 - 0x8) = r1;" 104 + "l1_%=:" 105 + "r0 = 0;" 106 + "exit;" 107 + : 108 + : __imm(bpf_get_prandom_u32), 109 + __imm(bpf_map_lookup_elem), 110 + __imm_addr(map_hash) 111 + : __clobber_all); 112 + } 113 + 114 + char _license[] SEC("license") = "GPL";