1*d3305286SEduard Zingerman // SPDX-License-Identifier: GPL-2.0
2*d3305286SEduard Zingerman /* Converted from tools/testing/selftests/bpf/verifier/value_or_null.c */
3*d3305286SEduard Zingerman 
4*d3305286SEduard Zingerman #include <linux/bpf.h>
5*d3305286SEduard Zingerman #include <bpf/bpf_helpers.h>
6*d3305286SEduard Zingerman #include "bpf_misc.h"
7*d3305286SEduard Zingerman 
8*d3305286SEduard Zingerman #define MAX_ENTRIES 11
9*d3305286SEduard Zingerman 
10*d3305286SEduard Zingerman struct test_val {
11*d3305286SEduard Zingerman 	unsigned int index;
12*d3305286SEduard Zingerman 	int foo[MAX_ENTRIES];
13*d3305286SEduard Zingerman };
14*d3305286SEduard Zingerman 
15*d3305286SEduard Zingerman struct {
16*d3305286SEduard Zingerman 	__uint(type, BPF_MAP_TYPE_HASH);
17*d3305286SEduard Zingerman 	__uint(max_entries, 1);
18*d3305286SEduard Zingerman 	__type(key, long long);
19*d3305286SEduard Zingerman 	__type(value, struct test_val);
20*d3305286SEduard Zingerman } map_hash_48b SEC(".maps");
21*d3305286SEduard Zingerman 
22*d3305286SEduard Zingerman struct {
23*d3305286SEduard Zingerman 	__uint(type, BPF_MAP_TYPE_HASH);
24*d3305286SEduard Zingerman 	__uint(max_entries, 1);
25*d3305286SEduard Zingerman 	__type(key, long long);
26*d3305286SEduard Zingerman 	__type(value, long long);
27*d3305286SEduard Zingerman } map_hash_8b SEC(".maps");
28*d3305286SEduard Zingerman 
29*d3305286SEduard Zingerman SEC("tc")
30*d3305286SEduard Zingerman __description("multiple registers share map_lookup_elem result")
31*d3305286SEduard Zingerman __success __retval(0)
share_map_lookup_elem_result(void)32*d3305286SEduard Zingerman __naked void share_map_lookup_elem_result(void)
33*d3305286SEduard Zingerman {
34*d3305286SEduard Zingerman 	asm volatile ("					\
35*d3305286SEduard Zingerman 	r1 = 10;					\
36*d3305286SEduard Zingerman 	*(u64*)(r10 - 8) = r1;				\
37*d3305286SEduard Zingerman 	r2 = r10;					\
38*d3305286SEduard Zingerman 	r2 += -8;					\
39*d3305286SEduard Zingerman 	r1 = %[map_hash_8b] ll;				\
40*d3305286SEduard Zingerman 	call %[bpf_map_lookup_elem];			\
41*d3305286SEduard Zingerman 	r4 = r0;					\
42*d3305286SEduard Zingerman 	if r0 == 0 goto l0_%=;				\
43*d3305286SEduard Zingerman 	r1 = 0;						\
44*d3305286SEduard Zingerman 	*(u64*)(r4 + 0) = r1;				\
45*d3305286SEduard Zingerman l0_%=:	exit;						\
46*d3305286SEduard Zingerman "	:
47*d3305286SEduard Zingerman 	: __imm(bpf_map_lookup_elem),
48*d3305286SEduard Zingerman 	  __imm_addr(map_hash_8b)
49*d3305286SEduard Zingerman 	: __clobber_all);
50*d3305286SEduard Zingerman }
51*d3305286SEduard Zingerman 
52*d3305286SEduard Zingerman SEC("tc")
53*d3305286SEduard Zingerman __description("alu ops on ptr_to_map_value_or_null, 1")
54*d3305286SEduard Zingerman __failure __msg("R4 pointer arithmetic on map_value_or_null")
map_value_or_null_1(void)55*d3305286SEduard Zingerman __naked void map_value_or_null_1(void)
56*d3305286SEduard Zingerman {
57*d3305286SEduard Zingerman 	asm volatile ("					\
58*d3305286SEduard Zingerman 	r1 = 10;					\
59*d3305286SEduard Zingerman 	*(u64*)(r10 - 8) = r1;				\
60*d3305286SEduard Zingerman 	r2 = r10;					\
61*d3305286SEduard Zingerman 	r2 += -8;					\
62*d3305286SEduard Zingerman 	r1 = %[map_hash_8b] ll;				\
63*d3305286SEduard Zingerman 	call %[bpf_map_lookup_elem];			\
64*d3305286SEduard Zingerman 	r4 = r0;					\
65*d3305286SEduard Zingerman 	r4 += -2;					\
66*d3305286SEduard Zingerman 	r4 += 2;					\
67*d3305286SEduard Zingerman 	if r0 == 0 goto l0_%=;				\
68*d3305286SEduard Zingerman 	r1 = 0;						\
69*d3305286SEduard Zingerman 	*(u64*)(r4 + 0) = r1;				\
70*d3305286SEduard Zingerman l0_%=:	exit;						\
71*d3305286SEduard Zingerman "	:
72*d3305286SEduard Zingerman 	: __imm(bpf_map_lookup_elem),
73*d3305286SEduard Zingerman 	  __imm_addr(map_hash_8b)
74*d3305286SEduard Zingerman 	: __clobber_all);
75*d3305286SEduard Zingerman }
76*d3305286SEduard Zingerman 
77*d3305286SEduard Zingerman SEC("tc")
78*d3305286SEduard Zingerman __description("alu ops on ptr_to_map_value_or_null, 2")
79*d3305286SEduard Zingerman __failure __msg("R4 pointer arithmetic on map_value_or_null")
map_value_or_null_2(void)80*d3305286SEduard Zingerman __naked void map_value_or_null_2(void)
81*d3305286SEduard Zingerman {
82*d3305286SEduard Zingerman 	asm volatile ("					\
83*d3305286SEduard Zingerman 	r1 = 10;					\
84*d3305286SEduard Zingerman 	*(u64*)(r10 - 8) = r1;				\
85*d3305286SEduard Zingerman 	r2 = r10;					\
86*d3305286SEduard Zingerman 	r2 += -8;					\
87*d3305286SEduard Zingerman 	r1 = %[map_hash_8b] ll;				\
88*d3305286SEduard Zingerman 	call %[bpf_map_lookup_elem];			\
89*d3305286SEduard Zingerman 	r4 = r0;					\
90*d3305286SEduard Zingerman 	r4 &= -1;					\
91*d3305286SEduard Zingerman 	if r0 == 0 goto l0_%=;				\
92*d3305286SEduard Zingerman 	r1 = 0;						\
93*d3305286SEduard Zingerman 	*(u64*)(r4 + 0) = r1;				\
94*d3305286SEduard Zingerman l0_%=:	exit;						\
95*d3305286SEduard Zingerman "	:
96*d3305286SEduard Zingerman 	: __imm(bpf_map_lookup_elem),
97*d3305286SEduard Zingerman 	  __imm_addr(map_hash_8b)
98*d3305286SEduard Zingerman 	: __clobber_all);
99*d3305286SEduard Zingerman }
100*d3305286SEduard Zingerman 
101*d3305286SEduard Zingerman SEC("tc")
102*d3305286SEduard Zingerman __description("alu ops on ptr_to_map_value_or_null, 3")
103*d3305286SEduard Zingerman __failure __msg("R4 pointer arithmetic on map_value_or_null")
map_value_or_null_3(void)104*d3305286SEduard Zingerman __naked void map_value_or_null_3(void)
105*d3305286SEduard Zingerman {
106*d3305286SEduard Zingerman 	asm volatile ("					\
107*d3305286SEduard Zingerman 	r1 = 10;					\
108*d3305286SEduard Zingerman 	*(u64*)(r10 - 8) = r1;				\
109*d3305286SEduard Zingerman 	r2 = r10;					\
110*d3305286SEduard Zingerman 	r2 += -8;					\
111*d3305286SEduard Zingerman 	r1 = %[map_hash_8b] ll;				\
112*d3305286SEduard Zingerman 	call %[bpf_map_lookup_elem];			\
113*d3305286SEduard Zingerman 	r4 = r0;					\
114*d3305286SEduard Zingerman 	r4 <<= 1;					\
115*d3305286SEduard Zingerman 	if r0 == 0 goto l0_%=;				\
116*d3305286SEduard Zingerman 	r1 = 0;						\
117*d3305286SEduard Zingerman 	*(u64*)(r4 + 0) = r1;				\
118*d3305286SEduard Zingerman l0_%=:	exit;						\
119*d3305286SEduard Zingerman "	:
120*d3305286SEduard Zingerman 	: __imm(bpf_map_lookup_elem),
121*d3305286SEduard Zingerman 	  __imm_addr(map_hash_8b)
122*d3305286SEduard Zingerman 	: __clobber_all);
123*d3305286SEduard Zingerman }
124*d3305286SEduard Zingerman 
125*d3305286SEduard Zingerman SEC("tc")
126*d3305286SEduard Zingerman __description("invalid memory access with multiple map_lookup_elem calls")
127*d3305286SEduard Zingerman __failure __msg("R4 !read_ok")
multiple_map_lookup_elem_calls(void)128*d3305286SEduard Zingerman __naked void multiple_map_lookup_elem_calls(void)
129*d3305286SEduard Zingerman {
130*d3305286SEduard Zingerman 	asm volatile ("					\
131*d3305286SEduard Zingerman 	r1 = 10;					\
132*d3305286SEduard Zingerman 	*(u64*)(r10 - 8) = r1;				\
133*d3305286SEduard Zingerman 	r2 = r10;					\
134*d3305286SEduard Zingerman 	r2 += -8;					\
135*d3305286SEduard Zingerman 	r1 = %[map_hash_8b] ll;				\
136*d3305286SEduard Zingerman 	r8 = r1;					\
137*d3305286SEduard Zingerman 	r7 = r2;					\
138*d3305286SEduard Zingerman 	call %[bpf_map_lookup_elem];			\
139*d3305286SEduard Zingerman 	r4 = r0;					\
140*d3305286SEduard Zingerman 	r1 = r8;					\
141*d3305286SEduard Zingerman 	r2 = r7;					\
142*d3305286SEduard Zingerman 	call %[bpf_map_lookup_elem];			\
143*d3305286SEduard Zingerman 	if r0 == 0 goto l0_%=;				\
144*d3305286SEduard Zingerman 	r1 = 0;						\
145*d3305286SEduard Zingerman 	*(u64*)(r4 + 0) = r1;				\
146*d3305286SEduard Zingerman l0_%=:	exit;						\
147*d3305286SEduard Zingerman "	:
148*d3305286SEduard Zingerman 	: __imm(bpf_map_lookup_elem),
149*d3305286SEduard Zingerman 	  __imm_addr(map_hash_8b)
150*d3305286SEduard Zingerman 	: __clobber_all);
151*d3305286SEduard Zingerman }
152*d3305286SEduard Zingerman 
153*d3305286SEduard Zingerman SEC("tc")
154*d3305286SEduard Zingerman __description("valid indirect map_lookup_elem access with 2nd lookup in branch")
155*d3305286SEduard Zingerman __success __retval(0)
with_2nd_lookup_in_branch(void)156*d3305286SEduard Zingerman __naked void with_2nd_lookup_in_branch(void)
157*d3305286SEduard Zingerman {
158*d3305286SEduard Zingerman 	asm volatile ("					\
159*d3305286SEduard Zingerman 	r1 = 10;					\
160*d3305286SEduard Zingerman 	*(u64*)(r10 - 8) = r1;				\
161*d3305286SEduard Zingerman 	r2 = r10;					\
162*d3305286SEduard Zingerman 	r2 += -8;					\
163*d3305286SEduard Zingerman 	r1 = %[map_hash_8b] ll;				\
164*d3305286SEduard Zingerman 	r8 = r1;					\
165*d3305286SEduard Zingerman 	r7 = r2;					\
166*d3305286SEduard Zingerman 	call %[bpf_map_lookup_elem];			\
167*d3305286SEduard Zingerman 	r2 = 10;					\
168*d3305286SEduard Zingerman 	if r2 != 0 goto l0_%=;				\
169*d3305286SEduard Zingerman 	r1 = r8;					\
170*d3305286SEduard Zingerman 	r2 = r7;					\
171*d3305286SEduard Zingerman 	call %[bpf_map_lookup_elem];			\
172*d3305286SEduard Zingerman l0_%=:	r4 = r0;					\
173*d3305286SEduard Zingerman 	if r0 == 0 goto l1_%=;				\
174*d3305286SEduard Zingerman 	r1 = 0;						\
175*d3305286SEduard Zingerman 	*(u64*)(r4 + 0) = r1;				\
176*d3305286SEduard Zingerman l1_%=:	exit;						\
177*d3305286SEduard Zingerman "	:
178*d3305286SEduard Zingerman 	: __imm(bpf_map_lookup_elem),
179*d3305286SEduard Zingerman 	  __imm_addr(map_hash_8b)
180*d3305286SEduard Zingerman 	: __clobber_all);
181*d3305286SEduard Zingerman }
182*d3305286SEduard Zingerman 
183*d3305286SEduard Zingerman SEC("socket")
184*d3305286SEduard Zingerman __description("invalid map access from else condition")
185*d3305286SEduard Zingerman __failure __msg("R0 unbounded memory access")
186*d3305286SEduard Zingerman __failure_unpriv __msg_unpriv("R0 leaks addr")
__flag(BPF_F_ANY_ALIGNMENT)187*d3305286SEduard Zingerman __flag(BPF_F_ANY_ALIGNMENT)
188*d3305286SEduard Zingerman __naked void map_access_from_else_condition(void)
189*d3305286SEduard Zingerman {
190*d3305286SEduard Zingerman 	asm volatile ("					\
191*d3305286SEduard Zingerman 	r1 = 0;						\
192*d3305286SEduard Zingerman 	*(u64*)(r10 - 8) = r1;				\
193*d3305286SEduard Zingerman 	r2 = r10;					\
194*d3305286SEduard Zingerman 	r2 += -8;					\
195*d3305286SEduard Zingerman 	r1 = %[map_hash_48b] ll;			\
196*d3305286SEduard Zingerman 	call %[bpf_map_lookup_elem];			\
197*d3305286SEduard Zingerman 	if r0 == 0 goto l0_%=;				\
198*d3305286SEduard Zingerman 	r1 = *(u32*)(r0 + 0);				\
199*d3305286SEduard Zingerman 	if r1 >= %[__imm_0] goto l1_%=;			\
200*d3305286SEduard Zingerman 	r1 += 1;					\
201*d3305286SEduard Zingerman l1_%=:	r1 <<= 2;					\
202*d3305286SEduard Zingerman 	r0 += r1;					\
203*d3305286SEduard Zingerman 	r1 = %[test_val_foo];				\
204*d3305286SEduard Zingerman 	*(u64*)(r0 + 0) = r1;				\
205*d3305286SEduard Zingerman l0_%=:	exit;						\
206*d3305286SEduard Zingerman "	:
207*d3305286SEduard Zingerman 	: __imm(bpf_map_lookup_elem),
208*d3305286SEduard Zingerman 	  __imm_addr(map_hash_48b),
209*d3305286SEduard Zingerman 	  __imm_const(__imm_0, MAX_ENTRIES-1),
210*d3305286SEduard Zingerman 	  __imm_const(test_val_foo, offsetof(struct test_val, foo))
211*d3305286SEduard Zingerman 	: __clobber_all);
212*d3305286SEduard Zingerman }
213*d3305286SEduard Zingerman 
214*d3305286SEduard Zingerman SEC("tc")
215*d3305286SEduard Zingerman __description("map lookup and null branch prediction")
216*d3305286SEduard Zingerman __success __retval(0)
lookup_and_null_branch_prediction(void)217*d3305286SEduard Zingerman __naked void lookup_and_null_branch_prediction(void)
218*d3305286SEduard Zingerman {
219*d3305286SEduard Zingerman 	asm volatile ("					\
220*d3305286SEduard Zingerman 	r1 = 10;					\
221*d3305286SEduard Zingerman 	*(u64*)(r10 - 8) = r1;				\
222*d3305286SEduard Zingerman 	r2 = r10;					\
223*d3305286SEduard Zingerman 	r2 += -8;					\
224*d3305286SEduard Zingerman 	r1 = %[map_hash_8b] ll;				\
225*d3305286SEduard Zingerman 	call %[bpf_map_lookup_elem];			\
226*d3305286SEduard Zingerman 	r6 = r0;					\
227*d3305286SEduard Zingerman 	if r6 == 0 goto l0_%=;				\
228*d3305286SEduard Zingerman 	if r6 != 0 goto l0_%=;				\
229*d3305286SEduard Zingerman 	r10 += 10;					\
230*d3305286SEduard Zingerman l0_%=:	exit;						\
231*d3305286SEduard Zingerman "	:
232*d3305286SEduard Zingerman 	: __imm(bpf_map_lookup_elem),
233*d3305286SEduard Zingerman 	  __imm_addr(map_hash_8b)
234*d3305286SEduard Zingerman 	: __clobber_all);
235*d3305286SEduard Zingerman }
236*d3305286SEduard Zingerman 
237*d3305286SEduard Zingerman SEC("cgroup/skb")
238*d3305286SEduard Zingerman __description("MAP_VALUE_OR_NULL check_ids() in regsafe()")
239*d3305286SEduard Zingerman __failure __msg("R8 invalid mem access 'map_value_or_null'")
240*d3305286SEduard Zingerman __failure_unpriv __msg_unpriv("")
__flag(BPF_F_TEST_STATE_FREQ)241*d3305286SEduard Zingerman __flag(BPF_F_TEST_STATE_FREQ)
242*d3305286SEduard Zingerman __naked void null_check_ids_in_regsafe(void)
243*d3305286SEduard Zingerman {
244*d3305286SEduard Zingerman 	asm volatile ("					\
245*d3305286SEduard Zingerman 	r1 = 0;						\
246*d3305286SEduard Zingerman 	*(u64*)(r10 - 8) = r1;				\
247*d3305286SEduard Zingerman 	/* r9 = map_lookup_elem(...) */			\
248*d3305286SEduard Zingerman 	r2 = r10;					\
249*d3305286SEduard Zingerman 	r2 += -8;					\
250*d3305286SEduard Zingerman 	r1 = %[map_hash_8b] ll;				\
251*d3305286SEduard Zingerman 	call %[bpf_map_lookup_elem];			\
252*d3305286SEduard Zingerman 	r9 = r0;					\
253*d3305286SEduard Zingerman 	/* r8 = map_lookup_elem(...) */			\
254*d3305286SEduard Zingerman 	r2 = r10;					\
255*d3305286SEduard Zingerman 	r2 += -8;					\
256*d3305286SEduard Zingerman 	r1 = %[map_hash_8b] ll;				\
257*d3305286SEduard Zingerman 	call %[bpf_map_lookup_elem];			\
258*d3305286SEduard Zingerman 	r8 = r0;					\
259*d3305286SEduard Zingerman 	/* r7 = ktime_get_ns() */			\
260*d3305286SEduard Zingerman 	call %[bpf_ktime_get_ns];			\
261*d3305286SEduard Zingerman 	r7 = r0;					\
262*d3305286SEduard Zingerman 	/* r6 = ktime_get_ns() */			\
263*d3305286SEduard Zingerman 	call %[bpf_ktime_get_ns];			\
264*d3305286SEduard Zingerman 	r6 = r0;					\
265*d3305286SEduard Zingerman 	/* if r6 > r7 goto +1    ; no new information about the state is derived from\
266*d3305286SEduard Zingerman 	 *                       ; this check, thus produced verifier states differ\
267*d3305286SEduard Zingerman 	 *                       ; only in 'insn_idx'	\
268*d3305286SEduard Zingerman 	 * r9 = r8               ; optionally share ID between r9 and r8\
269*d3305286SEduard Zingerman 	 */						\
270*d3305286SEduard Zingerman 	if r6 > r7 goto l0_%=;				\
271*d3305286SEduard Zingerman 	r9 = r8;					\
272*d3305286SEduard Zingerman l0_%=:	/* if r9 == 0 goto <exit> */			\
273*d3305286SEduard Zingerman 	if r9 == 0 goto l1_%=;				\
274*d3305286SEduard Zingerman 	/* read map value via r8, this is not always	\
275*d3305286SEduard Zingerman 	 * safe because r8 might be not equal to r9.	\
276*d3305286SEduard Zingerman 	 */						\
277*d3305286SEduard Zingerman 	r0 = *(u64*)(r8 + 0);				\
278*d3305286SEduard Zingerman l1_%=:	/* exit 0 */					\
279*d3305286SEduard Zingerman 	r0 = 0;						\
280*d3305286SEduard Zingerman 	exit;						\
281*d3305286SEduard Zingerman "	:
282*d3305286SEduard Zingerman 	: __imm(bpf_ktime_get_ns),
283*d3305286SEduard Zingerman 	  __imm(bpf_map_lookup_elem),
284*d3305286SEduard Zingerman 	  __imm_addr(map_hash_8b)
285*d3305286SEduard Zingerman 	: __clobber_all);
286*d3305286SEduard Zingerman }
287*d3305286SEduard Zingerman 
288*d3305286SEduard Zingerman char _license[] SEC("license") = "GPL";
289