Skip to content

Commit ddf3e71

Browse files
ADSWT518Kernel Patches Daemon
authored andcommitted
selftests/bpf: Add test for large offset bpf-to-bpf call
Add a selftest to verify the verifier and JIT behavior when handling bpf-to-bpf calls with relative jump offsets exceeding the s16 boundary. The test utilizes an inline assembly block with ".rept 32765" to generate a massive dummy subprogram. By placing this padding between the main program and the target subprogram, it forces the verifier to process a bpf-to-bpf call where the imm field exceeds the s16 range. - When JIT is enabled, it asserts that the program is successfully loaded and executes correctly to return the expected value. Since patch 1/2 does not change the JIT behavior, the test passes whether the fix is applied or not. - When JIT is disabled, it also asserts that the program is successfully loaded and executes correctly to return the expected value. - Before the fix, the verifier rewrites the call instruction with a truncated offset (here 32768 -> -32768) and lets it pass. When the program is executed, the call instruction causes a kernel panic due to an invalid jump target. - After the fix, the verifier correctly handles the large offset and allows it to pass. The program then executes correctly to return the expected value. Co-developed-by: Tianci Cao <ziye@zju.edu.cn> Signed-off-by: Tianci Cao <ziye@zju.edu.cn> Co-developed-by: Shenghao Yuan <shenghaoyuan0928@163.com> Signed-off-by: Shenghao Yuan <shenghaoyuan0928@163.com> Signed-off-by: Yazhou Tang <tangyazhou518@outlook.com>
1 parent 5a09c75 commit ddf3e71

2 files changed

Lines changed: 75 additions & 0 deletions

File tree

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
// SPDX-License-Identifier: GPL-2.0
2+
#include <test_progs.h>
3+
#include "call_large_imm.skel.h"
4+
5+
void test_call_large_imm(void)
6+
{
7+
struct call_large_imm *skel;
8+
int err, prog_fd;
9+
10+
LIBBPF_OPTS(bpf_test_run_opts, opts);
11+
12+
skel = call_large_imm__open();
13+
if (!ASSERT_OK_PTR(skel, "skel_open"))
14+
return;
15+
16+
err = call_large_imm__load(skel);
17+
18+
if (!ASSERT_OK(err, "load_should_succeed"))
19+
goto cleanup;
20+
21+
prog_fd = bpf_program__fd(skel->progs.call_large_imm_test);
22+
err = bpf_prog_test_run_opts(prog_fd, &opts);
23+
24+
if (ASSERT_OK(err, "prog_run_success"))
25+
ASSERT_EQ(opts.retval, 3, "prog_retval");
26+
27+
cleanup:
28+
call_large_imm__destroy(skel);
29+
}
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
// SPDX-License-Identifier: GPL-2.0
2+
#include <linux/bpf.h>
3+
#include <bpf/bpf_helpers.h>
4+
5+
/*
6+
* A volatile global variable is used here, so that padding_subprog()
7+
* will not be optimized, and it will not be really executed even if
8+
* it is successfully loaded (when JIT is enabled).
9+
*/
10+
volatile int zero = 0;
11+
12+
/*
13+
* 32765 is the exact minimum number of padding instructions needed to
14+
* trigger the verifier failure, because:
15+
* 1. Counting the wrapper instructions around the padding block (one
16+
* "r0=0" and two "exit" instructions), the actual jump distance
17+
* evaluates to N + 3.
18+
* 2. To overflow the s16 max bound (32767), we need N + 3 > 32767.
19+
* Thus, N = 32765 is the exact minimum padding size required.
20+
*/
21+
static __attribute__((noinline)) void padding_subprog(void)
22+
{
23+
asm volatile (" \
24+
r0 = 0; \
25+
.rept 32765; \
26+
r0 += 0; \
27+
.endr; \
28+
" ::: "r0");
29+
}
30+
31+
static __attribute__((noinline)) int target_subprog(void)
32+
{
33+
/* A volatile variable is used here to prevent optimization. */
34+
volatile int magic_ret = 3;
35+
return magic_ret;
36+
}
37+
38+
SEC("syscall")
39+
int call_large_imm_test(void *ctx)
40+
{
41+
if (zero)
42+
padding_subprog();
43+
return target_subprog();
44+
}
45+
46+
char LICENSE[] SEC("license") = "GPL";

0 commit comments

Comments
 (0)