xref: /linux/tools/testing/selftests/bpf/progs/verifier_call_large_imm.c (revision 513480da5e9c8f55b4f8f5e89f386e26188fbb3f)
1 // SPDX-License-Identifier: GPL-2.0
2 #include <linux/bpf.h>
3 #include <bpf/bpf_helpers.h>
4 #include "bpf_misc.h"
5 
6 int call_happened = 0;
7 
8 /*
9  * 32765 is the exact minimum number of padding instructions needed to
10  * trigger the verifier failure, because:
11  * 1. Counting the wrapper instructions around the padding block (one
12  *    "r0=0" and two "exit" instructions), the actual jump distance
13  *    evaluates to N + 3.
14  * 2. To overflow the s16 max bound (32767), we need N + 3 > 32767.
15  * Thus, N = 32765 is the exact minimum padding size required.
16  */
17 static __attribute__((noinline)) void padding_subprog(void)
18 {
19 	asm volatile (
20 	"r0 = 0;"
21 	".rept 32765;"
22 	"r0 += 0;"
23 	".endr;"
24 	::: __clobber_all);
25 }
26 
27 static __attribute__((noinline)) int target_subprog(void)
28 {
29 	/* Use volatile variable here to prevent optimization. */
30 	volatile int magic_ret = 3;
31 	return magic_ret;
32 }
33 
34 SEC("syscall")
35 __success __retval(3)
36 int call_large_imm_test(void *ctx)
37 {
38 	/*
39 	 * Landing pad to handle call error on kernel without the fix,
40 	 * preventing kernel panic.
41 	 */
42 	asm volatile (
43 	"r0 = 0;"
44 	".rept 32768;"
45 	"r0 += 0;"
46 	".endr;"
47 	::: __clobber_all);
48 
49 	/*
50 	 * The call_happened variable is 1 only when the call insn wrongly
51 	 * go back to the landing pad above.
52 	 */
53 	if (call_happened == 1) {
54 		/* Use volatile variable here to prevent optimization. */
55 		volatile int flag = -1;
56 		return flag;
57 	}
58 
59 	call_happened = 1;
60 
61 	padding_subprog();
62 
63 	return target_subprog();
64 }
65 
66 char LICENSE[] SEC("license") = "GPL";
67