1*c9233655SEduard Zingerman // SPDX-License-Identifier: GPL-2.0
2*c9233655SEduard Zingerman /* Converted from tools/testing/selftests/bpf/verifier/bounds.c */
3*c9233655SEduard Zingerman 
4*c9233655SEduard Zingerman #include <linux/bpf.h>
5*c9233655SEduard Zingerman #include <bpf/bpf_helpers.h>
6*c9233655SEduard Zingerman #include "bpf_misc.h"
7*c9233655SEduard Zingerman 
8*c9233655SEduard Zingerman struct {
9*c9233655SEduard Zingerman 	__uint(type, BPF_MAP_TYPE_HASH);
10*c9233655SEduard Zingerman 	__uint(max_entries, 1);
11*c9233655SEduard Zingerman 	__type(key, long long);
12*c9233655SEduard Zingerman 	__type(value, long long);
13*c9233655SEduard Zingerman } map_hash_8b SEC(".maps");
14*c9233655SEduard Zingerman 
15*c9233655SEduard Zingerman SEC("socket")
16*c9233655SEduard Zingerman __description("subtraction bounds (map value) variant 1")
17*c9233655SEduard Zingerman __failure __msg("R0 max value is outside of the allowed memory range")
18*c9233655SEduard Zingerman __failure_unpriv
bounds_map_value_variant_1(void)19*c9233655SEduard Zingerman __naked void bounds_map_value_variant_1(void)
20*c9233655SEduard Zingerman {
21*c9233655SEduard Zingerman 	asm volatile ("					\
22*c9233655SEduard Zingerman 	r1 = 0;						\
23*c9233655SEduard Zingerman 	*(u64*)(r10 - 8) = r1;				\
24*c9233655SEduard Zingerman 	r2 = r10;					\
25*c9233655SEduard Zingerman 	r2 += -8;					\
26*c9233655SEduard Zingerman 	r1 = %[map_hash_8b] ll;				\
27*c9233655SEduard Zingerman 	call %[bpf_map_lookup_elem];			\
28*c9233655SEduard Zingerman 	if r0 == 0 goto l0_%=;				\
29*c9233655SEduard Zingerman 	r1 = *(u8*)(r0 + 0);				\
30*c9233655SEduard Zingerman 	if r1 > 0xff goto l0_%=;			\
31*c9233655SEduard Zingerman 	r3 = *(u8*)(r0 + 1);				\
32*c9233655SEduard Zingerman 	if r3 > 0xff goto l0_%=;			\
33*c9233655SEduard Zingerman 	r1 -= r3;					\
34*c9233655SEduard Zingerman 	r1 >>= 56;					\
35*c9233655SEduard Zingerman 	r0 += r1;					\
36*c9233655SEduard Zingerman 	r0 = *(u8*)(r0 + 0);				\
37*c9233655SEduard Zingerman 	exit;						\
38*c9233655SEduard Zingerman l0_%=:	r0 = 0;						\
39*c9233655SEduard Zingerman 	exit;						\
40*c9233655SEduard Zingerman "	:
41*c9233655SEduard Zingerman 	: __imm(bpf_map_lookup_elem),
42*c9233655SEduard Zingerman 	  __imm_addr(map_hash_8b)
43*c9233655SEduard Zingerman 	: __clobber_all);
44*c9233655SEduard Zingerman }
45*c9233655SEduard Zingerman 
46*c9233655SEduard Zingerman SEC("socket")
47*c9233655SEduard Zingerman __description("subtraction bounds (map value) variant 2")
48*c9233655SEduard Zingerman __failure
49*c9233655SEduard Zingerman __msg("R0 min value is negative, either use unsigned index or do a if (index >=0) check.")
50*c9233655SEduard Zingerman __msg_unpriv("R1 has unknown scalar with mixed signed bounds")
bounds_map_value_variant_2(void)51*c9233655SEduard Zingerman __naked void bounds_map_value_variant_2(void)
52*c9233655SEduard Zingerman {
53*c9233655SEduard Zingerman 	asm volatile ("					\
54*c9233655SEduard Zingerman 	r1 = 0;						\
55*c9233655SEduard Zingerman 	*(u64*)(r10 - 8) = r1;				\
56*c9233655SEduard Zingerman 	r2 = r10;					\
57*c9233655SEduard Zingerman 	r2 += -8;					\
58*c9233655SEduard Zingerman 	r1 = %[map_hash_8b] ll;				\
59*c9233655SEduard Zingerman 	call %[bpf_map_lookup_elem];			\
60*c9233655SEduard Zingerman 	if r0 == 0 goto l0_%=;				\
61*c9233655SEduard Zingerman 	r1 = *(u8*)(r0 + 0);				\
62*c9233655SEduard Zingerman 	if r1 > 0xff goto l0_%=;			\
63*c9233655SEduard Zingerman 	r3 = *(u8*)(r0 + 1);				\
64*c9233655SEduard Zingerman 	if r3 > 0xff goto l0_%=;			\
65*c9233655SEduard Zingerman 	r1 -= r3;					\
66*c9233655SEduard Zingerman 	r0 += r1;					\
67*c9233655SEduard Zingerman 	r0 = *(u8*)(r0 + 0);				\
68*c9233655SEduard Zingerman 	exit;						\
69*c9233655SEduard Zingerman l0_%=:	r0 = 0;						\
70*c9233655SEduard Zingerman 	exit;						\
71*c9233655SEduard Zingerman "	:
72*c9233655SEduard Zingerman 	: __imm(bpf_map_lookup_elem),
73*c9233655SEduard Zingerman 	  __imm_addr(map_hash_8b)
74*c9233655SEduard Zingerman 	: __clobber_all);
75*c9233655SEduard Zingerman }
76*c9233655SEduard Zingerman 
77*c9233655SEduard Zingerman SEC("socket")
78*c9233655SEduard Zingerman __description("check subtraction on pointers for unpriv")
79*c9233655SEduard Zingerman __success __failure_unpriv __msg_unpriv("R9 pointer -= pointer prohibited")
80*c9233655SEduard Zingerman __retval(0)
subtraction_on_pointers_for_unpriv(void)81*c9233655SEduard Zingerman __naked void subtraction_on_pointers_for_unpriv(void)
82*c9233655SEduard Zingerman {
83*c9233655SEduard Zingerman 	asm volatile ("					\
84*c9233655SEduard Zingerman 	r0 = 0;						\
85*c9233655SEduard Zingerman 	r1 = %[map_hash_8b] ll;				\
86*c9233655SEduard Zingerman 	r2 = r10;					\
87*c9233655SEduard Zingerman 	r2 += -8;					\
88*c9233655SEduard Zingerman 	r6 = 9;						\
89*c9233655SEduard Zingerman 	*(u64*)(r2 + 0) = r6;				\
90*c9233655SEduard Zingerman 	call %[bpf_map_lookup_elem];			\
91*c9233655SEduard Zingerman 	r9 = r10;					\
92*c9233655SEduard Zingerman 	r9 -= r0;					\
93*c9233655SEduard Zingerman 	r1 = %[map_hash_8b] ll;				\
94*c9233655SEduard Zingerman 	r2 = r10;					\
95*c9233655SEduard Zingerman 	r2 += -8;					\
96*c9233655SEduard Zingerman 	r6 = 0;						\
97*c9233655SEduard Zingerman 	*(u64*)(r2 + 0) = r6;				\
98*c9233655SEduard Zingerman 	call %[bpf_map_lookup_elem];			\
99*c9233655SEduard Zingerman 	if r0 != 0 goto l0_%=;				\
100*c9233655SEduard Zingerman 	exit;						\
101*c9233655SEduard Zingerman l0_%=:	*(u64*)(r0 + 0) = r9;				\
102*c9233655SEduard Zingerman 	r0 = 0;						\
103*c9233655SEduard Zingerman 	exit;						\
104*c9233655SEduard Zingerman "	:
105*c9233655SEduard Zingerman 	: __imm(bpf_map_lookup_elem),
106*c9233655SEduard Zingerman 	  __imm_addr(map_hash_8b)
107*c9233655SEduard Zingerman 	: __clobber_all);
108*c9233655SEduard Zingerman }
109*c9233655SEduard Zingerman 
110*c9233655SEduard Zingerman SEC("socket")
111*c9233655SEduard Zingerman __description("bounds check based on zero-extended MOV")
112*c9233655SEduard Zingerman __success __success_unpriv __retval(0)
based_on_zero_extended_mov(void)113*c9233655SEduard Zingerman __naked void based_on_zero_extended_mov(void)
114*c9233655SEduard Zingerman {
115*c9233655SEduard Zingerman 	asm volatile ("					\
116*c9233655SEduard Zingerman 	r1 = 0;						\
117*c9233655SEduard Zingerman 	*(u64*)(r10 - 8) = r1;				\
118*c9233655SEduard Zingerman 	r2 = r10;					\
119*c9233655SEduard Zingerman 	r2 += -8;					\
120*c9233655SEduard Zingerman 	r1 = %[map_hash_8b] ll;				\
121*c9233655SEduard Zingerman 	call %[bpf_map_lookup_elem];			\
122*c9233655SEduard Zingerman 	if r0 == 0 goto l0_%=;				\
123*c9233655SEduard Zingerman 	/* r2 = 0x0000'0000'ffff'ffff */		\
124*c9233655SEduard Zingerman 	w2 = 0xffffffff;				\
125*c9233655SEduard Zingerman 	/* r2 = 0 */					\
126*c9233655SEduard Zingerman 	r2 >>= 32;					\
127*c9233655SEduard Zingerman 	/* no-op */					\
128*c9233655SEduard Zingerman 	r0 += r2;					\
129*c9233655SEduard Zingerman 	/* access at offset 0 */			\
130*c9233655SEduard Zingerman 	r0 = *(u8*)(r0 + 0);				\
131*c9233655SEduard Zingerman l0_%=:	/* exit */					\
132*c9233655SEduard Zingerman 	r0 = 0;						\
133*c9233655SEduard Zingerman 	exit;						\
134*c9233655SEduard Zingerman "	:
135*c9233655SEduard Zingerman 	: __imm(bpf_map_lookup_elem),
136*c9233655SEduard Zingerman 	  __imm_addr(map_hash_8b)
137*c9233655SEduard Zingerman 	: __clobber_all);
138*c9233655SEduard Zingerman }
139*c9233655SEduard Zingerman 
140*c9233655SEduard Zingerman SEC("socket")
141*c9233655SEduard Zingerman __description("bounds check based on sign-extended MOV. test1")
142*c9233655SEduard Zingerman __failure __msg("map_value pointer and 4294967295")
143*c9233655SEduard Zingerman __failure_unpriv
on_sign_extended_mov_test1(void)144*c9233655SEduard Zingerman __naked void on_sign_extended_mov_test1(void)
145*c9233655SEduard Zingerman {
146*c9233655SEduard Zingerman 	asm volatile ("					\
147*c9233655SEduard Zingerman 	r1 = 0;						\
148*c9233655SEduard Zingerman 	*(u64*)(r10 - 8) = r1;				\
149*c9233655SEduard Zingerman 	r2 = r10;					\
150*c9233655SEduard Zingerman 	r2 += -8;					\
151*c9233655SEduard Zingerman 	r1 = %[map_hash_8b] ll;				\
152*c9233655SEduard Zingerman 	call %[bpf_map_lookup_elem];			\
153*c9233655SEduard Zingerman 	if r0 == 0 goto l0_%=;				\
154*c9233655SEduard Zingerman 	/* r2 = 0xffff'ffff'ffff'ffff */		\
155*c9233655SEduard Zingerman 	r2 = 0xffffffff;				\
156*c9233655SEduard Zingerman 	/* r2 = 0xffff'ffff */				\
157*c9233655SEduard Zingerman 	r2 >>= 32;					\
158*c9233655SEduard Zingerman 	/* r0 = <oob pointer> */			\
159*c9233655SEduard Zingerman 	r0 += r2;					\
160*c9233655SEduard Zingerman 	/* access to OOB pointer */			\
161*c9233655SEduard Zingerman 	r0 = *(u8*)(r0 + 0);				\
162*c9233655SEduard Zingerman l0_%=:	/* exit */					\
163*c9233655SEduard Zingerman 	r0 = 0;						\
164*c9233655SEduard Zingerman 	exit;						\
165*c9233655SEduard Zingerman "	:
166*c9233655SEduard Zingerman 	: __imm(bpf_map_lookup_elem),
167*c9233655SEduard Zingerman 	  __imm_addr(map_hash_8b)
168*c9233655SEduard Zingerman 	: __clobber_all);
169*c9233655SEduard Zingerman }
170*c9233655SEduard Zingerman 
171*c9233655SEduard Zingerman SEC("socket")
172*c9233655SEduard Zingerman __description("bounds check based on sign-extended MOV. test2")
173*c9233655SEduard Zingerman __failure __msg("R0 min value is outside of the allowed memory range")
174*c9233655SEduard Zingerman __failure_unpriv
on_sign_extended_mov_test2(void)175*c9233655SEduard Zingerman __naked void on_sign_extended_mov_test2(void)
176*c9233655SEduard Zingerman {
177*c9233655SEduard Zingerman 	asm volatile ("					\
178*c9233655SEduard Zingerman 	r1 = 0;						\
179*c9233655SEduard Zingerman 	*(u64*)(r10 - 8) = r1;				\
180*c9233655SEduard Zingerman 	r2 = r10;					\
181*c9233655SEduard Zingerman 	r2 += -8;					\
182*c9233655SEduard Zingerman 	r1 = %[map_hash_8b] ll;				\
183*c9233655SEduard Zingerman 	call %[bpf_map_lookup_elem];			\
184*c9233655SEduard Zingerman 	if r0 == 0 goto l0_%=;				\
185*c9233655SEduard Zingerman 	/* r2 = 0xffff'ffff'ffff'ffff */		\
186*c9233655SEduard Zingerman 	r2 = 0xffffffff;				\
187*c9233655SEduard Zingerman 	/* r2 = 0xfff'ffff */				\
188*c9233655SEduard Zingerman 	r2 >>= 36;					\
189*c9233655SEduard Zingerman 	/* r0 = <oob pointer> */			\
190*c9233655SEduard Zingerman 	r0 += r2;					\
191*c9233655SEduard Zingerman 	/* access to OOB pointer */			\
192*c9233655SEduard Zingerman 	r0 = *(u8*)(r0 + 0);				\
193*c9233655SEduard Zingerman l0_%=:	/* exit */					\
194*c9233655SEduard Zingerman 	r0 = 0;						\
195*c9233655SEduard Zingerman 	exit;						\
196*c9233655SEduard Zingerman "	:
197*c9233655SEduard Zingerman 	: __imm(bpf_map_lookup_elem),
198*c9233655SEduard Zingerman 	  __imm_addr(map_hash_8b)
199*c9233655SEduard Zingerman 	: __clobber_all);
200*c9233655SEduard Zingerman }
201*c9233655SEduard Zingerman 
202*c9233655SEduard Zingerman SEC("tc")
203*c9233655SEduard Zingerman __description("bounds check based on reg_off + var_off + insn_off. test1")
204*c9233655SEduard Zingerman __failure __msg("value_size=8 off=1073741825")
var_off_insn_off_test1(void)205*c9233655SEduard Zingerman __naked void var_off_insn_off_test1(void)
206*c9233655SEduard Zingerman {
207*c9233655SEduard Zingerman 	asm volatile ("					\
208*c9233655SEduard Zingerman 	r6 = *(u32*)(r1 + %[__sk_buff_mark]);		\
209*c9233655SEduard Zingerman 	r1 = 0;						\
210*c9233655SEduard Zingerman 	*(u64*)(r10 - 8) = r1;				\
211*c9233655SEduard Zingerman 	r2 = r10;					\
212*c9233655SEduard Zingerman 	r2 += -8;					\
213*c9233655SEduard Zingerman 	r1 = %[map_hash_8b] ll;				\
214*c9233655SEduard Zingerman 	call %[bpf_map_lookup_elem];			\
215*c9233655SEduard Zingerman 	if r0 == 0 goto l0_%=;				\
216*c9233655SEduard Zingerman 	r6 &= 1;					\
217*c9233655SEduard Zingerman 	r6 += %[__imm_0];				\
218*c9233655SEduard Zingerman 	r0 += r6;					\
219*c9233655SEduard Zingerman 	r0 += %[__imm_0];				\
220*c9233655SEduard Zingerman l0_%=:	r0 = *(u8*)(r0 + 3);				\
221*c9233655SEduard Zingerman 	r0 = 0;						\
222*c9233655SEduard Zingerman 	exit;						\
223*c9233655SEduard Zingerman "	:
224*c9233655SEduard Zingerman 	: __imm(bpf_map_lookup_elem),
225*c9233655SEduard Zingerman 	  __imm_addr(map_hash_8b),
226*c9233655SEduard Zingerman 	  __imm_const(__imm_0, (1 << 29) - 1),
227*c9233655SEduard Zingerman 	  __imm_const(__sk_buff_mark, offsetof(struct __sk_buff, mark))
228*c9233655SEduard Zingerman 	: __clobber_all);
229*c9233655SEduard Zingerman }
230*c9233655SEduard Zingerman 
231*c9233655SEduard Zingerman SEC("tc")
232*c9233655SEduard Zingerman __description("bounds check based on reg_off + var_off + insn_off. test2")
233*c9233655SEduard Zingerman __failure __msg("value 1073741823")
var_off_insn_off_test2(void)234*c9233655SEduard Zingerman __naked void var_off_insn_off_test2(void)
235*c9233655SEduard Zingerman {
236*c9233655SEduard Zingerman 	asm volatile ("					\
237*c9233655SEduard Zingerman 	r6 = *(u32*)(r1 + %[__sk_buff_mark]);		\
238*c9233655SEduard Zingerman 	r1 = 0;						\
239*c9233655SEduard Zingerman 	*(u64*)(r10 - 8) = r1;				\
240*c9233655SEduard Zingerman 	r2 = r10;					\
241*c9233655SEduard Zingerman 	r2 += -8;					\
242*c9233655SEduard Zingerman 	r1 = %[map_hash_8b] ll;				\
243*c9233655SEduard Zingerman 	call %[bpf_map_lookup_elem];			\
244*c9233655SEduard Zingerman 	if r0 == 0 goto l0_%=;				\
245*c9233655SEduard Zingerman 	r6 &= 1;					\
246*c9233655SEduard Zingerman 	r6 += %[__imm_0];				\
247*c9233655SEduard Zingerman 	r0 += r6;					\
248*c9233655SEduard Zingerman 	r0 += %[__imm_1];				\
249*c9233655SEduard Zingerman l0_%=:	r0 = *(u8*)(r0 + 3);				\
250*c9233655SEduard Zingerman 	r0 = 0;						\
251*c9233655SEduard Zingerman 	exit;						\
252*c9233655SEduard Zingerman "	:
253*c9233655SEduard Zingerman 	: __imm(bpf_map_lookup_elem),
254*c9233655SEduard Zingerman 	  __imm_addr(map_hash_8b),
255*c9233655SEduard Zingerman 	  __imm_const(__imm_0, (1 << 30) - 1),
256*c9233655SEduard Zingerman 	  __imm_const(__imm_1, (1 << 29) - 1),
257*c9233655SEduard Zingerman 	  __imm_const(__sk_buff_mark, offsetof(struct __sk_buff, mark))
258*c9233655SEduard Zingerman 	: __clobber_all);
259*c9233655SEduard Zingerman }
260*c9233655SEduard Zingerman 
261*c9233655SEduard Zingerman SEC("socket")
262*c9233655SEduard Zingerman __description("bounds check after truncation of non-boundary-crossing range")
263*c9233655SEduard Zingerman __success __success_unpriv __retval(0)
of_non_boundary_crossing_range(void)264*c9233655SEduard Zingerman __naked void of_non_boundary_crossing_range(void)
265*c9233655SEduard Zingerman {
266*c9233655SEduard Zingerman 	asm volatile ("					\
267*c9233655SEduard Zingerman 	r1 = 0;						\
268*c9233655SEduard Zingerman 	*(u64*)(r10 - 8) = r1;				\
269*c9233655SEduard Zingerman 	r2 = r10;					\
270*c9233655SEduard Zingerman 	r2 += -8;					\
271*c9233655SEduard Zingerman 	r1 = %[map_hash_8b] ll;				\
272*c9233655SEduard Zingerman 	call %[bpf_map_lookup_elem];			\
273*c9233655SEduard Zingerman 	if r0 == 0 goto l0_%=;				\
274*c9233655SEduard Zingerman 	/* r1 = [0x00, 0xff] */				\
275*c9233655SEduard Zingerman 	r1 = *(u8*)(r0 + 0);				\
276*c9233655SEduard Zingerman 	r2 = 1;						\
277*c9233655SEduard Zingerman 	/* r2 = 0x10'0000'0000 */			\
278*c9233655SEduard Zingerman 	r2 <<= 36;					\
279*c9233655SEduard Zingerman 	/* r1 = [0x10'0000'0000, 0x10'0000'00ff] */	\
280*c9233655SEduard Zingerman 	r1 += r2;					\
281*c9233655SEduard Zingerman 	/* r1 = [0x10'7fff'ffff, 0x10'8000'00fe] */	\
282*c9233655SEduard Zingerman 	r1 += 0x7fffffff;				\
283*c9233655SEduard Zingerman 	/* r1 = [0x00, 0xff] */				\
284*c9233655SEduard Zingerman 	w1 -= 0x7fffffff;				\
285*c9233655SEduard Zingerman 	/* r1 = 0 */					\
286*c9233655SEduard Zingerman 	r1 >>= 8;					\
287*c9233655SEduard Zingerman 	/* no-op */					\
288*c9233655SEduard Zingerman 	r0 += r1;					\
289*c9233655SEduard Zingerman 	/* access at offset 0 */			\
290*c9233655SEduard Zingerman 	r0 = *(u8*)(r0 + 0);				\
291*c9233655SEduard Zingerman l0_%=:	/* exit */					\
292*c9233655SEduard Zingerman 	r0 = 0;						\
293*c9233655SEduard Zingerman 	exit;						\
294*c9233655SEduard Zingerman "	:
295*c9233655SEduard Zingerman 	: __imm(bpf_map_lookup_elem),
296*c9233655SEduard Zingerman 	  __imm_addr(map_hash_8b)
297*c9233655SEduard Zingerman 	: __clobber_all);
298*c9233655SEduard Zingerman }
299*c9233655SEduard Zingerman 
300*c9233655SEduard Zingerman SEC("socket")
301*c9233655SEduard Zingerman __description("bounds check after truncation of boundary-crossing range (1)")
302*c9233655SEduard Zingerman __failure
303*c9233655SEduard Zingerman /* not actually fully unbounded, but the bound is very high */
304*c9233655SEduard Zingerman __msg("value -4294967168 makes map_value pointer be out of bounds")
305*c9233655SEduard Zingerman __failure_unpriv
of_boundary_crossing_range_1(void)306*c9233655SEduard Zingerman __naked void of_boundary_crossing_range_1(void)
307*c9233655SEduard Zingerman {
308*c9233655SEduard Zingerman 	asm volatile ("					\
309*c9233655SEduard Zingerman 	r1 = 0;						\
310*c9233655SEduard Zingerman 	*(u64*)(r10 - 8) = r1;				\
311*c9233655SEduard Zingerman 	r2 = r10;					\
312*c9233655SEduard Zingerman 	r2 += -8;					\
313*c9233655SEduard Zingerman 	r1 = %[map_hash_8b] ll;				\
314*c9233655SEduard Zingerman 	call %[bpf_map_lookup_elem];			\
315*c9233655SEduard Zingerman 	if r0 == 0 goto l0_%=;				\
316*c9233655SEduard Zingerman 	/* r1 = [0x00, 0xff] */				\
317*c9233655SEduard Zingerman 	r1 = *(u8*)(r0 + 0);				\
318*c9233655SEduard Zingerman 	r1 += %[__imm_0];				\
319*c9233655SEduard Zingerman 	/* r1 = [0xffff'ff80, 0x1'0000'007f] */		\
320*c9233655SEduard Zingerman 	r1 += %[__imm_0];				\
321*c9233655SEduard Zingerman 	/* r1 = [0xffff'ff80, 0xffff'ffff] or		\
322*c9233655SEduard Zingerman 	 *      [0x0000'0000, 0x0000'007f]		\
323*c9233655SEduard Zingerman 	 */						\
324*c9233655SEduard Zingerman 	w1 += 0;					\
325*c9233655SEduard Zingerman 	r1 -= %[__imm_0];				\
326*c9233655SEduard Zingerman 	/* r1 = [0x00, 0xff] or				\
327*c9233655SEduard Zingerman 	 *      [0xffff'ffff'0000'0080, 0xffff'ffff'ffff'ffff]\
328*c9233655SEduard Zingerman 	 */						\
329*c9233655SEduard Zingerman 	r1 -= %[__imm_0];				\
330*c9233655SEduard Zingerman 	/* error on OOB pointer computation */		\
331*c9233655SEduard Zingerman 	r0 += r1;					\
332*c9233655SEduard Zingerman 	/* exit */					\
333*c9233655SEduard Zingerman 	r0 = 0;						\
334*c9233655SEduard Zingerman l0_%=:	exit;						\
335*c9233655SEduard Zingerman "	:
336*c9233655SEduard Zingerman 	: __imm(bpf_map_lookup_elem),
337*c9233655SEduard Zingerman 	  __imm_addr(map_hash_8b),
338*c9233655SEduard Zingerman 	  __imm_const(__imm_0, 0xffffff80 >> 1)
339*c9233655SEduard Zingerman 	: __clobber_all);
340*c9233655SEduard Zingerman }
341*c9233655SEduard Zingerman 
342*c9233655SEduard Zingerman SEC("socket")
343*c9233655SEduard Zingerman __description("bounds check after truncation of boundary-crossing range (2)")
344*c9233655SEduard Zingerman __failure __msg("value -4294967168 makes map_value pointer be out of bounds")
345*c9233655SEduard Zingerman __failure_unpriv
of_boundary_crossing_range_2(void)346*c9233655SEduard Zingerman __naked void of_boundary_crossing_range_2(void)
347*c9233655SEduard Zingerman {
348*c9233655SEduard Zingerman 	asm volatile ("					\
349*c9233655SEduard Zingerman 	r1 = 0;						\
350*c9233655SEduard Zingerman 	*(u64*)(r10 - 8) = r1;				\
351*c9233655SEduard Zingerman 	r2 = r10;					\
352*c9233655SEduard Zingerman 	r2 += -8;					\
353*c9233655SEduard Zingerman 	r1 = %[map_hash_8b] ll;				\
354*c9233655SEduard Zingerman 	call %[bpf_map_lookup_elem];			\
355*c9233655SEduard Zingerman 	if r0 == 0 goto l0_%=;				\
356*c9233655SEduard Zingerman 	/* r1 = [0x00, 0xff] */				\
357*c9233655SEduard Zingerman 	r1 = *(u8*)(r0 + 0);				\
358*c9233655SEduard Zingerman 	r1 += %[__imm_0];				\
359*c9233655SEduard Zingerman 	/* r1 = [0xffff'ff80, 0x1'0000'007f] */		\
360*c9233655SEduard Zingerman 	r1 += %[__imm_0];				\
361*c9233655SEduard Zingerman 	/* r1 = [0xffff'ff80, 0xffff'ffff] or		\
362*c9233655SEduard Zingerman 	 *      [0x0000'0000, 0x0000'007f]		\
363*c9233655SEduard Zingerman 	 * difference to previous test: truncation via MOV32\
364*c9233655SEduard Zingerman 	 * instead of ALU32.				\
365*c9233655SEduard Zingerman 	 */						\
366*c9233655SEduard Zingerman 	w1 = w1;					\
367*c9233655SEduard Zingerman 	r1 -= %[__imm_0];				\
368*c9233655SEduard Zingerman 	/* r1 = [0x00, 0xff] or				\
369*c9233655SEduard Zingerman 	 *      [0xffff'ffff'0000'0080, 0xffff'ffff'ffff'ffff]\
370*c9233655SEduard Zingerman 	 */						\
371*c9233655SEduard Zingerman 	r1 -= %[__imm_0];				\
372*c9233655SEduard Zingerman 	/* error on OOB pointer computation */		\
373*c9233655SEduard Zingerman 	r0 += r1;					\
374*c9233655SEduard Zingerman 	/* exit */					\
375*c9233655SEduard Zingerman 	r0 = 0;						\
376*c9233655SEduard Zingerman l0_%=:	exit;						\
377*c9233655SEduard Zingerman "	:
378*c9233655SEduard Zingerman 	: __imm(bpf_map_lookup_elem),
379*c9233655SEduard Zingerman 	  __imm_addr(map_hash_8b),
380*c9233655SEduard Zingerman 	  __imm_const(__imm_0, 0xffffff80 >> 1)
381*c9233655SEduard Zingerman 	: __clobber_all);
382*c9233655SEduard Zingerman }
383*c9233655SEduard Zingerman 
384*c9233655SEduard Zingerman SEC("socket")
385*c9233655SEduard Zingerman __description("bounds check after wrapping 32-bit addition")
386*c9233655SEduard Zingerman __success __success_unpriv __retval(0)
after_wrapping_32_bit_addition(void)387*c9233655SEduard Zingerman __naked void after_wrapping_32_bit_addition(void)
388*c9233655SEduard Zingerman {
389*c9233655SEduard Zingerman 	asm volatile ("					\
390*c9233655SEduard Zingerman 	r1 = 0;						\
391*c9233655SEduard Zingerman 	*(u64*)(r10 - 8) = r1;				\
392*c9233655SEduard Zingerman 	r2 = r10;					\
393*c9233655SEduard Zingerman 	r2 += -8;					\
394*c9233655SEduard Zingerman 	r1 = %[map_hash_8b] ll;				\
395*c9233655SEduard Zingerman 	call %[bpf_map_lookup_elem];			\
396*c9233655SEduard Zingerman 	if r0 == 0 goto l0_%=;				\
397*c9233655SEduard Zingerman 	/* r1 = 0x7fff'ffff */				\
398*c9233655SEduard Zingerman 	r1 = 0x7fffffff;				\
399*c9233655SEduard Zingerman 	/* r1 = 0xffff'fffe */				\
400*c9233655SEduard Zingerman 	r1 += 0x7fffffff;				\
401*c9233655SEduard Zingerman 	/* r1 = 0 */					\
402*c9233655SEduard Zingerman 	w1 += 2;					\
403*c9233655SEduard Zingerman 	/* no-op */					\
404*c9233655SEduard Zingerman 	r0 += r1;					\
405*c9233655SEduard Zingerman 	/* access at offset 0 */			\
406*c9233655SEduard Zingerman 	r0 = *(u8*)(r0 + 0);				\
407*c9233655SEduard Zingerman l0_%=:	/* exit */					\
408*c9233655SEduard Zingerman 	r0 = 0;						\
409*c9233655SEduard Zingerman 	exit;						\
410*c9233655SEduard Zingerman "	:
411*c9233655SEduard Zingerman 	: __imm(bpf_map_lookup_elem),
412*c9233655SEduard Zingerman 	  __imm_addr(map_hash_8b)
413*c9233655SEduard Zingerman 	: __clobber_all);
414*c9233655SEduard Zingerman }
415*c9233655SEduard Zingerman 
416*c9233655SEduard Zingerman SEC("socket")
417*c9233655SEduard Zingerman __description("bounds check after shift with oversized count operand")
418*c9233655SEduard Zingerman __failure __msg("R0 max value is outside of the allowed memory range")
419*c9233655SEduard Zingerman __failure_unpriv
shift_with_oversized_count_operand(void)420*c9233655SEduard Zingerman __naked void shift_with_oversized_count_operand(void)
421*c9233655SEduard Zingerman {
422*c9233655SEduard Zingerman 	asm volatile ("					\
423*c9233655SEduard Zingerman 	r1 = 0;						\
424*c9233655SEduard Zingerman 	*(u64*)(r10 - 8) = r1;				\
425*c9233655SEduard Zingerman 	r2 = r10;					\
426*c9233655SEduard Zingerman 	r2 += -8;					\
427*c9233655SEduard Zingerman 	r1 = %[map_hash_8b] ll;				\
428*c9233655SEduard Zingerman 	call %[bpf_map_lookup_elem];			\
429*c9233655SEduard Zingerman 	if r0 == 0 goto l0_%=;				\
430*c9233655SEduard Zingerman 	r2 = 32;					\
431*c9233655SEduard Zingerman 	r1 = 1;						\
432*c9233655SEduard Zingerman 	/* r1 = (u32)1 << (u32)32 = ? */		\
433*c9233655SEduard Zingerman 	w1 <<= w2;					\
434*c9233655SEduard Zingerman 	/* r1 = [0x0000, 0xffff] */			\
435*c9233655SEduard Zingerman 	r1 &= 0xffff;					\
436*c9233655SEduard Zingerman 	/* computes unknown pointer, potentially OOB */	\
437*c9233655SEduard Zingerman 	r0 += r1;					\
438*c9233655SEduard Zingerman 	/* potentially OOB access */			\
439*c9233655SEduard Zingerman 	r0 = *(u8*)(r0 + 0);				\
440*c9233655SEduard Zingerman l0_%=:	/* exit */					\
441*c9233655SEduard Zingerman 	r0 = 0;						\
442*c9233655SEduard Zingerman 	exit;						\
443*c9233655SEduard Zingerman "	:
444*c9233655SEduard Zingerman 	: __imm(bpf_map_lookup_elem),
445*c9233655SEduard Zingerman 	  __imm_addr(map_hash_8b)
446*c9233655SEduard Zingerman 	: __clobber_all);
447*c9233655SEduard Zingerman }
448*c9233655SEduard Zingerman 
449*c9233655SEduard Zingerman SEC("socket")
450*c9233655SEduard Zingerman __description("bounds check after right shift of maybe-negative number")
451*c9233655SEduard Zingerman __failure __msg("R0 unbounded memory access")
452*c9233655SEduard Zingerman __failure_unpriv
shift_of_maybe_negative_number(void)453*c9233655SEduard Zingerman __naked void shift_of_maybe_negative_number(void)
454*c9233655SEduard Zingerman {
455*c9233655SEduard Zingerman 	asm volatile ("					\
456*c9233655SEduard Zingerman 	r1 = 0;						\
457*c9233655SEduard Zingerman 	*(u64*)(r10 - 8) = r1;				\
458*c9233655SEduard Zingerman 	r2 = r10;					\
459*c9233655SEduard Zingerman 	r2 += -8;					\
460*c9233655SEduard Zingerman 	r1 = %[map_hash_8b] ll;				\
461*c9233655SEduard Zingerman 	call %[bpf_map_lookup_elem];			\
462*c9233655SEduard Zingerman 	if r0 == 0 goto l0_%=;				\
463*c9233655SEduard Zingerman 	/* r1 = [0x00, 0xff] */				\
464*c9233655SEduard Zingerman 	r1 = *(u8*)(r0 + 0);				\
465*c9233655SEduard Zingerman 	/* r1 = [-0x01, 0xfe] */			\
466*c9233655SEduard Zingerman 	r1 -= 1;					\
467*c9233655SEduard Zingerman 	/* r1 = 0 or 0xff'ffff'ffff'ffff */		\
468*c9233655SEduard Zingerman 	r1 >>= 8;					\
469*c9233655SEduard Zingerman 	/* r1 = 0 or 0xffff'ffff'ffff */		\
470*c9233655SEduard Zingerman 	r1 >>= 8;					\
471*c9233655SEduard Zingerman 	/* computes unknown pointer, potentially OOB */	\
472*c9233655SEduard Zingerman 	r0 += r1;					\
473*c9233655SEduard Zingerman 	/* potentially OOB access */			\
474*c9233655SEduard Zingerman 	r0 = *(u8*)(r0 + 0);				\
475*c9233655SEduard Zingerman l0_%=:	/* exit */					\
476*c9233655SEduard Zingerman 	r0 = 0;						\
477*c9233655SEduard Zingerman 	exit;						\
478*c9233655SEduard Zingerman "	:
479*c9233655SEduard Zingerman 	: __imm(bpf_map_lookup_elem),
480*c9233655SEduard Zingerman 	  __imm_addr(map_hash_8b)
481*c9233655SEduard Zingerman 	: __clobber_all);
482*c9233655SEduard Zingerman }
483*c9233655SEduard Zingerman 
484*c9233655SEduard Zingerman SEC("socket")
485*c9233655SEduard Zingerman __description("bounds check after 32-bit right shift with 64-bit input")
486*c9233655SEduard Zingerman __failure __msg("math between map_value pointer and 4294967294 is not allowed")
487*c9233655SEduard Zingerman __failure_unpriv
shift_with_64_bit_input(void)488*c9233655SEduard Zingerman __naked void shift_with_64_bit_input(void)
489*c9233655SEduard Zingerman {
490*c9233655SEduard Zingerman 	asm volatile ("					\
491*c9233655SEduard Zingerman 	r1 = 0;						\
492*c9233655SEduard Zingerman 	*(u64*)(r10 - 8) = r1;				\
493*c9233655SEduard Zingerman 	r2 = r10;					\
494*c9233655SEduard Zingerman 	r2 += -8;					\
495*c9233655SEduard Zingerman 	r1 = %[map_hash_8b] ll;				\
496*c9233655SEduard Zingerman 	call %[bpf_map_lookup_elem];			\
497*c9233655SEduard Zingerman 	if r0 == 0 goto l0_%=;				\
498*c9233655SEduard Zingerman 	r1 = 2;						\
499*c9233655SEduard Zingerman 	/* r1 = 1<<32 */				\
500*c9233655SEduard Zingerman 	r1 <<= 31;					\
501*c9233655SEduard Zingerman 	/* r1 = 0 (NOT 2!) */				\
502*c9233655SEduard Zingerman 	w1 >>= 31;					\
503*c9233655SEduard Zingerman 	/* r1 = 0xffff'fffe (NOT 0!) */			\
504*c9233655SEduard Zingerman 	w1 -= 2;					\
505*c9233655SEduard Zingerman 	/* error on computing OOB pointer */		\
506*c9233655SEduard Zingerman 	r0 += r1;					\
507*c9233655SEduard Zingerman 	/* exit */					\
508*c9233655SEduard Zingerman 	r0 = 0;						\
509*c9233655SEduard Zingerman l0_%=:	exit;						\
510*c9233655SEduard Zingerman "	:
511*c9233655SEduard Zingerman 	: __imm(bpf_map_lookup_elem),
512*c9233655SEduard Zingerman 	  __imm_addr(map_hash_8b)
513*c9233655SEduard Zingerman 	: __clobber_all);
514*c9233655SEduard Zingerman }
515*c9233655SEduard Zingerman 
516*c9233655SEduard Zingerman SEC("socket")
517*c9233655SEduard Zingerman __description("bounds check map access with off+size signed 32bit overflow. test1")
518*c9233655SEduard Zingerman __failure __msg("map_value pointer and 2147483646")
519*c9233655SEduard Zingerman __failure_unpriv
size_signed_32bit_overflow_test1(void)520*c9233655SEduard Zingerman __naked void size_signed_32bit_overflow_test1(void)
521*c9233655SEduard Zingerman {
522*c9233655SEduard Zingerman 	asm volatile ("					\
523*c9233655SEduard Zingerman 	r1 = 0;						\
524*c9233655SEduard Zingerman 	*(u64*)(r10 - 8) = r1;				\
525*c9233655SEduard Zingerman 	r2 = r10;					\
526*c9233655SEduard Zingerman 	r2 += -8;					\
527*c9233655SEduard Zingerman 	r1 = %[map_hash_8b] ll;				\
528*c9233655SEduard Zingerman 	call %[bpf_map_lookup_elem];			\
529*c9233655SEduard Zingerman 	if r0 != 0 goto l0_%=;				\
530*c9233655SEduard Zingerman 	exit;						\
531*c9233655SEduard Zingerman l0_%=:	r0 += 0x7ffffffe;				\
532*c9233655SEduard Zingerman 	r0 = *(u64*)(r0 + 0);				\
533*c9233655SEduard Zingerman 	goto l1_%=;					\
534*c9233655SEduard Zingerman l1_%=:	exit;						\
535*c9233655SEduard Zingerman "	:
536*c9233655SEduard Zingerman 	: __imm(bpf_map_lookup_elem),
537*c9233655SEduard Zingerman 	  __imm_addr(map_hash_8b)
538*c9233655SEduard Zingerman 	: __clobber_all);
539*c9233655SEduard Zingerman }
540*c9233655SEduard Zingerman 
541*c9233655SEduard Zingerman SEC("socket")
542*c9233655SEduard Zingerman __description("bounds check map access with off+size signed 32bit overflow. test2")
543*c9233655SEduard Zingerman __failure __msg("pointer offset 1073741822")
544*c9233655SEduard Zingerman __msg_unpriv("R0 pointer arithmetic of map value goes out of range")
size_signed_32bit_overflow_test2(void)545*c9233655SEduard Zingerman __naked void size_signed_32bit_overflow_test2(void)
546*c9233655SEduard Zingerman {
547*c9233655SEduard Zingerman 	asm volatile ("					\
548*c9233655SEduard Zingerman 	r1 = 0;						\
549*c9233655SEduard Zingerman 	*(u64*)(r10 - 8) = r1;				\
550*c9233655SEduard Zingerman 	r2 = r10;					\
551*c9233655SEduard Zingerman 	r2 += -8;					\
552*c9233655SEduard Zingerman 	r1 = %[map_hash_8b] ll;				\
553*c9233655SEduard Zingerman 	call %[bpf_map_lookup_elem];			\
554*c9233655SEduard Zingerman 	if r0 != 0 goto l0_%=;				\
555*c9233655SEduard Zingerman 	exit;						\
556*c9233655SEduard Zingerman l0_%=:	r0 += 0x1fffffff;				\
557*c9233655SEduard Zingerman 	r0 += 0x1fffffff;				\
558*c9233655SEduard Zingerman 	r0 += 0x1fffffff;				\
559*c9233655SEduard Zingerman 	r0 = *(u64*)(r0 + 0);				\
560*c9233655SEduard Zingerman 	goto l1_%=;					\
561*c9233655SEduard Zingerman l1_%=:	exit;						\
562*c9233655SEduard Zingerman "	:
563*c9233655SEduard Zingerman 	: __imm(bpf_map_lookup_elem),
564*c9233655SEduard Zingerman 	  __imm_addr(map_hash_8b)
565*c9233655SEduard Zingerman 	: __clobber_all);
566*c9233655SEduard Zingerman }
567*c9233655SEduard Zingerman 
568*c9233655SEduard Zingerman SEC("socket")
569*c9233655SEduard Zingerman __description("bounds check map access with off+size signed 32bit overflow. test3")
570*c9233655SEduard Zingerman __failure __msg("pointer offset -1073741822")
571*c9233655SEduard Zingerman __msg_unpriv("R0 pointer arithmetic of map value goes out of range")
size_signed_32bit_overflow_test3(void)572*c9233655SEduard Zingerman __naked void size_signed_32bit_overflow_test3(void)
573*c9233655SEduard Zingerman {
574*c9233655SEduard Zingerman 	asm volatile ("					\
575*c9233655SEduard Zingerman 	r1 = 0;						\
576*c9233655SEduard Zingerman 	*(u64*)(r10 - 8) = r1;				\
577*c9233655SEduard Zingerman 	r2 = r10;					\
578*c9233655SEduard Zingerman 	r2 += -8;					\
579*c9233655SEduard Zingerman 	r1 = %[map_hash_8b] ll;				\
580*c9233655SEduard Zingerman 	call %[bpf_map_lookup_elem];			\
581*c9233655SEduard Zingerman 	if r0 != 0 goto l0_%=;				\
582*c9233655SEduard Zingerman 	exit;						\
583*c9233655SEduard Zingerman l0_%=:	r0 -= 0x1fffffff;				\
584*c9233655SEduard Zingerman 	r0 -= 0x1fffffff;				\
585*c9233655SEduard Zingerman 	r0 = *(u64*)(r0 + 2);				\
586*c9233655SEduard Zingerman 	goto l1_%=;					\
587*c9233655SEduard Zingerman l1_%=:	exit;						\
588*c9233655SEduard Zingerman "	:
589*c9233655SEduard Zingerman 	: __imm(bpf_map_lookup_elem),
590*c9233655SEduard Zingerman 	  __imm_addr(map_hash_8b)
591*c9233655SEduard Zingerman 	: __clobber_all);
592*c9233655SEduard Zingerman }
593*c9233655SEduard Zingerman 
594*c9233655SEduard Zingerman SEC("socket")
595*c9233655SEduard Zingerman __description("bounds check map access with off+size signed 32bit overflow. test4")
596*c9233655SEduard Zingerman __failure __msg("map_value pointer and 1000000000000")
597*c9233655SEduard Zingerman __failure_unpriv
size_signed_32bit_overflow_test4(void)598*c9233655SEduard Zingerman __naked void size_signed_32bit_overflow_test4(void)
599*c9233655SEduard Zingerman {
600*c9233655SEduard Zingerman 	asm volatile ("					\
601*c9233655SEduard Zingerman 	r1 = 0;						\
602*c9233655SEduard Zingerman 	*(u64*)(r10 - 8) = r1;				\
603*c9233655SEduard Zingerman 	r2 = r10;					\
604*c9233655SEduard Zingerman 	r2 += -8;					\
605*c9233655SEduard Zingerman 	r1 = %[map_hash_8b] ll;				\
606*c9233655SEduard Zingerman 	call %[bpf_map_lookup_elem];			\
607*c9233655SEduard Zingerman 	if r0 != 0 goto l0_%=;				\
608*c9233655SEduard Zingerman 	exit;						\
609*c9233655SEduard Zingerman l0_%=:	r1 = 1000000;					\
610*c9233655SEduard Zingerman 	r1 *= 1000000;					\
611*c9233655SEduard Zingerman 	r0 += r1;					\
612*c9233655SEduard Zingerman 	r0 = *(u64*)(r0 + 2);				\
613*c9233655SEduard Zingerman 	goto l1_%=;					\
614*c9233655SEduard Zingerman l1_%=:	exit;						\
615*c9233655SEduard Zingerman "	:
616*c9233655SEduard Zingerman 	: __imm(bpf_map_lookup_elem),
617*c9233655SEduard Zingerman 	  __imm_addr(map_hash_8b)
618*c9233655SEduard Zingerman 	: __clobber_all);
619*c9233655SEduard Zingerman }
620*c9233655SEduard Zingerman 
621*c9233655SEduard Zingerman SEC("socket")
622*c9233655SEduard Zingerman __description("bounds check mixed 32bit and 64bit arithmetic. test1")
623*c9233655SEduard Zingerman __success __failure_unpriv __msg_unpriv("R0 invalid mem access 'scalar'")
624*c9233655SEduard Zingerman __retval(0)
_32bit_and_64bit_arithmetic_test1(void)625*c9233655SEduard Zingerman __naked void _32bit_and_64bit_arithmetic_test1(void)
626*c9233655SEduard Zingerman {
627*c9233655SEduard Zingerman 	asm volatile ("					\
628*c9233655SEduard Zingerman 	r0 = 0;						\
629*c9233655SEduard Zingerman 	r1 = -1;					\
630*c9233655SEduard Zingerman 	r1 <<= 32;					\
631*c9233655SEduard Zingerman 	r1 += 1;					\
632*c9233655SEduard Zingerman 	/* r1 = 0xffffFFFF00000001 */			\
633*c9233655SEduard Zingerman 	if w1 > 1 goto l0_%=;				\
634*c9233655SEduard Zingerman 	/* check ALU64 op keeps 32bit bounds */		\
635*c9233655SEduard Zingerman 	r1 += 1;					\
636*c9233655SEduard Zingerman 	if w1 > 2 goto l0_%=;				\
637*c9233655SEduard Zingerman 	goto l1_%=;					\
638*c9233655SEduard Zingerman l0_%=:	/* invalid ldx if bounds are lost above */	\
639*c9233655SEduard Zingerman 	r0 = *(u64*)(r0 - 1);				\
640*c9233655SEduard Zingerman l1_%=:	exit;						\
641*c9233655SEduard Zingerman "	::: __clobber_all);
642*c9233655SEduard Zingerman }
643*c9233655SEduard Zingerman 
644*c9233655SEduard Zingerman SEC("socket")
645*c9233655SEduard Zingerman __description("bounds check mixed 32bit and 64bit arithmetic. test2")
646*c9233655SEduard Zingerman __success __failure_unpriv __msg_unpriv("R0 invalid mem access 'scalar'")
647*c9233655SEduard Zingerman __retval(0)
_32bit_and_64bit_arithmetic_test2(void)648*c9233655SEduard Zingerman __naked void _32bit_and_64bit_arithmetic_test2(void)
649*c9233655SEduard Zingerman {
650*c9233655SEduard Zingerman 	asm volatile ("					\
651*c9233655SEduard Zingerman 	r0 = 0;						\
652*c9233655SEduard Zingerman 	r1 = -1;					\
653*c9233655SEduard Zingerman 	r1 <<= 32;					\
654*c9233655SEduard Zingerman 	r1 += 1;					\
655*c9233655SEduard Zingerman 	/* r1 = 0xffffFFFF00000001 */			\
656*c9233655SEduard Zingerman 	r2 = 3;						\
657*c9233655SEduard Zingerman 	/* r1 = 0x2 */					\
658*c9233655SEduard Zingerman 	w1 += 1;					\
659*c9233655SEduard Zingerman 	/* check ALU32 op zero extends 64bit bounds */	\
660*c9233655SEduard Zingerman 	if r1 > r2 goto l0_%=;				\
661*c9233655SEduard Zingerman 	goto l1_%=;					\
662*c9233655SEduard Zingerman l0_%=:	/* invalid ldx if bounds are lost above */	\
663*c9233655SEduard Zingerman 	r0 = *(u64*)(r0 - 1);				\
664*c9233655SEduard Zingerman l1_%=:	exit;						\
665*c9233655SEduard Zingerman "	::: __clobber_all);
666*c9233655SEduard Zingerman }
667*c9233655SEduard Zingerman 
668*c9233655SEduard Zingerman SEC("tc")
669*c9233655SEduard Zingerman __description("assigning 32bit bounds to 64bit for wA = 0, wB = wA")
__flag(BPF_F_ANY_ALIGNMENT)670*c9233655SEduard Zingerman __success __retval(0) __flag(BPF_F_ANY_ALIGNMENT)
671*c9233655SEduard Zingerman __naked void for_wa_0_wb_wa(void)
672*c9233655SEduard Zingerman {
673*c9233655SEduard Zingerman 	asm volatile ("					\
674*c9233655SEduard Zingerman 	r8 = *(u32*)(r1 + %[__sk_buff_data_end]);	\
675*c9233655SEduard Zingerman 	r7 = *(u32*)(r1 + %[__sk_buff_data]);		\
676*c9233655SEduard Zingerman 	w9 = 0;						\
677*c9233655SEduard Zingerman 	w2 = w9;					\
678*c9233655SEduard Zingerman 	r6 = r7;					\
679*c9233655SEduard Zingerman 	r6 += r2;					\
680*c9233655SEduard Zingerman 	r3 = r6;					\
681*c9233655SEduard Zingerman 	r3 += 8;					\
682*c9233655SEduard Zingerman 	if r3 > r8 goto l0_%=;				\
683*c9233655SEduard Zingerman 	r5 = *(u32*)(r6 + 0);				\
684*c9233655SEduard Zingerman l0_%=:	r0 = 0;						\
685*c9233655SEduard Zingerman 	exit;						\
686*c9233655SEduard Zingerman "	:
687*c9233655SEduard Zingerman 	: __imm_const(__sk_buff_data, offsetof(struct __sk_buff, data)),
688*c9233655SEduard Zingerman 	  __imm_const(__sk_buff_data_end, offsetof(struct __sk_buff, data_end))
689*c9233655SEduard Zingerman 	: __clobber_all);
690*c9233655SEduard Zingerman }
691*c9233655SEduard Zingerman 
692*c9233655SEduard Zingerman SEC("socket")
693*c9233655SEduard Zingerman __description("bounds check for reg = 0, reg xor 1")
694*c9233655SEduard Zingerman __success __failure_unpriv
695*c9233655SEduard Zingerman __msg_unpriv("R0 min value is outside of the allowed memory range")
696*c9233655SEduard Zingerman __retval(0)
reg_0_reg_xor_1(void)697*c9233655SEduard Zingerman __naked void reg_0_reg_xor_1(void)
698*c9233655SEduard Zingerman {
699*c9233655SEduard Zingerman 	asm volatile ("					\
700*c9233655SEduard Zingerman 	r1 = 0;						\
701*c9233655SEduard Zingerman 	*(u64*)(r10 - 8) = r1;				\
702*c9233655SEduard Zingerman 	r2 = r10;					\
703*c9233655SEduard Zingerman 	r2 += -8;					\
704*c9233655SEduard Zingerman 	r1 = %[map_hash_8b] ll;				\
705*c9233655SEduard Zingerman 	call %[bpf_map_lookup_elem];			\
706*c9233655SEduard Zingerman 	if r0 != 0 goto l0_%=;				\
707*c9233655SEduard Zingerman 	exit;						\
708*c9233655SEduard Zingerman l0_%=:	r1 = 0;						\
709*c9233655SEduard Zingerman 	r1 ^= 1;					\
710*c9233655SEduard Zingerman 	if r1 != 0 goto l1_%=;				\
711*c9233655SEduard Zingerman 	r0 = *(u64*)(r0 + 8);				\
712*c9233655SEduard Zingerman l1_%=:	r0 = 0;						\
713*c9233655SEduard Zingerman 	exit;						\
714*c9233655SEduard Zingerman "	:
715*c9233655SEduard Zingerman 	: __imm(bpf_map_lookup_elem),
716*c9233655SEduard Zingerman 	  __imm_addr(map_hash_8b)
717*c9233655SEduard Zingerman 	: __clobber_all);
718*c9233655SEduard Zingerman }
719*c9233655SEduard Zingerman 
720*c9233655SEduard Zingerman SEC("socket")
721*c9233655SEduard Zingerman __description("bounds check for reg32 = 0, reg32 xor 1")
722*c9233655SEduard Zingerman __success __failure_unpriv
723*c9233655SEduard Zingerman __msg_unpriv("R0 min value is outside of the allowed memory range")
724*c9233655SEduard Zingerman __retval(0)
reg32_0_reg32_xor_1(void)725*c9233655SEduard Zingerman __naked void reg32_0_reg32_xor_1(void)
726*c9233655SEduard Zingerman {
727*c9233655SEduard Zingerman 	asm volatile ("					\
728*c9233655SEduard Zingerman 	r1 = 0;						\
729*c9233655SEduard Zingerman 	*(u64*)(r10 - 8) = r1;				\
730*c9233655SEduard Zingerman 	r2 = r10;					\
731*c9233655SEduard Zingerman 	r2 += -8;					\
732*c9233655SEduard Zingerman 	r1 = %[map_hash_8b] ll;				\
733*c9233655SEduard Zingerman 	call %[bpf_map_lookup_elem];			\
734*c9233655SEduard Zingerman 	if r0 != 0 goto l0_%=;				\
735*c9233655SEduard Zingerman 	exit;						\
736*c9233655SEduard Zingerman l0_%=:	w1 = 0;						\
737*c9233655SEduard Zingerman 	w1 ^= 1;					\
738*c9233655SEduard Zingerman 	if w1 != 0 goto l1_%=;				\
739*c9233655SEduard Zingerman 	r0 = *(u64*)(r0 + 8);				\
740*c9233655SEduard Zingerman l1_%=:	r0 = 0;						\
741*c9233655SEduard Zingerman 	exit;						\
742*c9233655SEduard Zingerman "	:
743*c9233655SEduard Zingerman 	: __imm(bpf_map_lookup_elem),
744*c9233655SEduard Zingerman 	  __imm_addr(map_hash_8b)
745*c9233655SEduard Zingerman 	: __clobber_all);
746*c9233655SEduard Zingerman }
747*c9233655SEduard Zingerman 
748*c9233655SEduard Zingerman SEC("socket")
749*c9233655SEduard Zingerman __description("bounds check for reg = 2, reg xor 3")
750*c9233655SEduard Zingerman __success __failure_unpriv
751*c9233655SEduard Zingerman __msg_unpriv("R0 min value is outside of the allowed memory range")
752*c9233655SEduard Zingerman __retval(0)
reg_2_reg_xor_3(void)753*c9233655SEduard Zingerman __naked void reg_2_reg_xor_3(void)
754*c9233655SEduard Zingerman {
755*c9233655SEduard Zingerman 	asm volatile ("					\
756*c9233655SEduard Zingerman 	r1 = 0;						\
757*c9233655SEduard Zingerman 	*(u64*)(r10 - 8) = r1;				\
758*c9233655SEduard Zingerman 	r2 = r10;					\
759*c9233655SEduard Zingerman 	r2 += -8;					\
760*c9233655SEduard Zingerman 	r1 = %[map_hash_8b] ll;				\
761*c9233655SEduard Zingerman 	call %[bpf_map_lookup_elem];			\
762*c9233655SEduard Zingerman 	if r0 != 0 goto l0_%=;				\
763*c9233655SEduard Zingerman 	exit;						\
764*c9233655SEduard Zingerman l0_%=:	r1 = 2;						\
765*c9233655SEduard Zingerman 	r1 ^= 3;					\
766*c9233655SEduard Zingerman 	if r1 > 0 goto l1_%=;				\
767*c9233655SEduard Zingerman 	r0 = *(u64*)(r0 + 8);				\
768*c9233655SEduard Zingerman l1_%=:	r0 = 0;						\
769*c9233655SEduard Zingerman 	exit;						\
770*c9233655SEduard Zingerman "	:
771*c9233655SEduard Zingerman 	: __imm(bpf_map_lookup_elem),
772*c9233655SEduard Zingerman 	  __imm_addr(map_hash_8b)
773*c9233655SEduard Zingerman 	: __clobber_all);
774*c9233655SEduard Zingerman }
775*c9233655SEduard Zingerman 
776*c9233655SEduard Zingerman SEC("socket")
777*c9233655SEduard Zingerman __description("bounds check for reg = any, reg xor 3")
778*c9233655SEduard Zingerman __failure __msg("invalid access to map value")
779*c9233655SEduard Zingerman __msg_unpriv("invalid access to map value")
reg_any_reg_xor_3(void)780*c9233655SEduard Zingerman __naked void reg_any_reg_xor_3(void)
781*c9233655SEduard Zingerman {
782*c9233655SEduard Zingerman 	asm volatile ("					\
783*c9233655SEduard Zingerman 	r1 = 0;						\
784*c9233655SEduard Zingerman 	*(u64*)(r10 - 8) = r1;				\
785*c9233655SEduard Zingerman 	r2 = r10;					\
786*c9233655SEduard Zingerman 	r2 += -8;					\
787*c9233655SEduard Zingerman 	r1 = %[map_hash_8b] ll;				\
788*c9233655SEduard Zingerman 	call %[bpf_map_lookup_elem];			\
789*c9233655SEduard Zingerman 	if r0 != 0 goto l0_%=;				\
790*c9233655SEduard Zingerman 	exit;						\
791*c9233655SEduard Zingerman l0_%=:	r1 = *(u64*)(r0 + 0);				\
792*c9233655SEduard Zingerman 	r1 ^= 3;					\
793*c9233655SEduard Zingerman 	if r1 != 0 goto l1_%=;				\
794*c9233655SEduard Zingerman 	r0 = *(u64*)(r0 + 8);				\
795*c9233655SEduard Zingerman l1_%=:	r0 = 0;						\
796*c9233655SEduard Zingerman 	exit;						\
797*c9233655SEduard Zingerman "	:
798*c9233655SEduard Zingerman 	: __imm(bpf_map_lookup_elem),
799*c9233655SEduard Zingerman 	  __imm_addr(map_hash_8b)
800*c9233655SEduard Zingerman 	: __clobber_all);
801*c9233655SEduard Zingerman }
802*c9233655SEduard Zingerman 
803*c9233655SEduard Zingerman SEC("socket")
804*c9233655SEduard Zingerman __description("bounds check for reg32 = any, reg32 xor 3")
805*c9233655SEduard Zingerman __failure __msg("invalid access to map value")
806*c9233655SEduard Zingerman __msg_unpriv("invalid access to map value")
reg32_any_reg32_xor_3(void)807*c9233655SEduard Zingerman __naked void reg32_any_reg32_xor_3(void)
808*c9233655SEduard Zingerman {
809*c9233655SEduard Zingerman 	asm volatile ("					\
810*c9233655SEduard Zingerman 	r1 = 0;						\
811*c9233655SEduard Zingerman 	*(u64*)(r10 - 8) = r1;				\
812*c9233655SEduard Zingerman 	r2 = r10;					\
813*c9233655SEduard Zingerman 	r2 += -8;					\
814*c9233655SEduard Zingerman 	r1 = %[map_hash_8b] ll;				\
815*c9233655SEduard Zingerman 	call %[bpf_map_lookup_elem];			\
816*c9233655SEduard Zingerman 	if r0 != 0 goto l0_%=;				\
817*c9233655SEduard Zingerman 	exit;						\
818*c9233655SEduard Zingerman l0_%=:	r1 = *(u64*)(r0 + 0);				\
819*c9233655SEduard Zingerman 	w1 ^= 3;					\
820*c9233655SEduard Zingerman 	if w1 != 0 goto l1_%=;				\
821*c9233655SEduard Zingerman 	r0 = *(u64*)(r0 + 8);				\
822*c9233655SEduard Zingerman l1_%=:	r0 = 0;						\
823*c9233655SEduard Zingerman 	exit;						\
824*c9233655SEduard Zingerman "	:
825*c9233655SEduard Zingerman 	: __imm(bpf_map_lookup_elem),
826*c9233655SEduard Zingerman 	  __imm_addr(map_hash_8b)
827*c9233655SEduard Zingerman 	: __clobber_all);
828*c9233655SEduard Zingerman }
829*c9233655SEduard Zingerman 
830*c9233655SEduard Zingerman SEC("socket")
831*c9233655SEduard Zingerman __description("bounds check for reg > 0, reg xor 3")
832*c9233655SEduard Zingerman __success __failure_unpriv
833*c9233655SEduard Zingerman __msg_unpriv("R0 min value is outside of the allowed memory range")
834*c9233655SEduard Zingerman __retval(0)
reg_0_reg_xor_3(void)835*c9233655SEduard Zingerman __naked void reg_0_reg_xor_3(void)
836*c9233655SEduard Zingerman {
837*c9233655SEduard Zingerman 	asm volatile ("					\
838*c9233655SEduard Zingerman 	r1 = 0;						\
839*c9233655SEduard Zingerman 	*(u64*)(r10 - 8) = r1;				\
840*c9233655SEduard Zingerman 	r2 = r10;					\
841*c9233655SEduard Zingerman 	r2 += -8;					\
842*c9233655SEduard Zingerman 	r1 = %[map_hash_8b] ll;				\
843*c9233655SEduard Zingerman 	call %[bpf_map_lookup_elem];			\
844*c9233655SEduard Zingerman 	if r0 != 0 goto l0_%=;				\
845*c9233655SEduard Zingerman 	exit;						\
846*c9233655SEduard Zingerman l0_%=:	r1 = *(u64*)(r0 + 0);				\
847*c9233655SEduard Zingerman 	if r1 <= 0 goto l1_%=;				\
848*c9233655SEduard Zingerman 	r1 ^= 3;					\
849*c9233655SEduard Zingerman 	if r1 >= 0 goto l1_%=;				\
850*c9233655SEduard Zingerman 	r0 = *(u64*)(r0 + 8);				\
851*c9233655SEduard Zingerman l1_%=:	r0 = 0;						\
852*c9233655SEduard Zingerman 	exit;						\
853*c9233655SEduard Zingerman "	:
854*c9233655SEduard Zingerman 	: __imm(bpf_map_lookup_elem),
855*c9233655SEduard Zingerman 	  __imm_addr(map_hash_8b)
856*c9233655SEduard Zingerman 	: __clobber_all);
857*c9233655SEduard Zingerman }
858*c9233655SEduard Zingerman 
859*c9233655SEduard Zingerman SEC("socket")
860*c9233655SEduard Zingerman __description("bounds check for reg32 > 0, reg32 xor 3")
861*c9233655SEduard Zingerman __success __failure_unpriv
862*c9233655SEduard Zingerman __msg_unpriv("R0 min value is outside of the allowed memory range")
863*c9233655SEduard Zingerman __retval(0)
reg32_0_reg32_xor_3(void)864*c9233655SEduard Zingerman __naked void reg32_0_reg32_xor_3(void)
865*c9233655SEduard Zingerman {
866*c9233655SEduard Zingerman 	asm volatile ("					\
867*c9233655SEduard Zingerman 	r1 = 0;						\
868*c9233655SEduard Zingerman 	*(u64*)(r10 - 8) = r1;				\
869*c9233655SEduard Zingerman 	r2 = r10;					\
870*c9233655SEduard Zingerman 	r2 += -8;					\
871*c9233655SEduard Zingerman 	r1 = %[map_hash_8b] ll;				\
872*c9233655SEduard Zingerman 	call %[bpf_map_lookup_elem];			\
873*c9233655SEduard Zingerman 	if r0 != 0 goto l0_%=;				\
874*c9233655SEduard Zingerman 	exit;						\
875*c9233655SEduard Zingerman l0_%=:	r1 = *(u64*)(r0 + 0);				\
876*c9233655SEduard Zingerman 	if w1 <= 0 goto l1_%=;				\
877*c9233655SEduard Zingerman 	w1 ^= 3;					\
878*c9233655SEduard Zingerman 	if w1 >= 0 goto l1_%=;				\
879*c9233655SEduard Zingerman 	r0 = *(u64*)(r0 + 8);				\
880*c9233655SEduard Zingerman l1_%=:	r0 = 0;						\
881*c9233655SEduard Zingerman 	exit;						\
882*c9233655SEduard Zingerman "	:
883*c9233655SEduard Zingerman 	: __imm(bpf_map_lookup_elem),
884*c9233655SEduard Zingerman 	  __imm_addr(map_hash_8b)
885*c9233655SEduard Zingerman 	: __clobber_all);
886*c9233655SEduard Zingerman }
887*c9233655SEduard Zingerman 
888*c9233655SEduard Zingerman SEC("socket")
889*c9233655SEduard Zingerman __description("bounds checks after 32-bit truncation. test 1")
890*c9233655SEduard Zingerman __success __failure_unpriv __msg_unpriv("R0 leaks addr")
891*c9233655SEduard Zingerman __retval(0)
_32_bit_truncation_test_1(void)892*c9233655SEduard Zingerman __naked void _32_bit_truncation_test_1(void)
893*c9233655SEduard Zingerman {
894*c9233655SEduard Zingerman 	asm volatile ("					\
895*c9233655SEduard Zingerman 	r1 = 0;						\
896*c9233655SEduard Zingerman 	*(u64*)(r10 - 8) = r1;				\
897*c9233655SEduard Zingerman 	r2 = r10;					\
898*c9233655SEduard Zingerman 	r2 += -8;					\
899*c9233655SEduard Zingerman 	r1 = %[map_hash_8b] ll;				\
900*c9233655SEduard Zingerman 	call %[bpf_map_lookup_elem];			\
901*c9233655SEduard Zingerman 	if r0 == 0 goto l0_%=;				\
902*c9233655SEduard Zingerman 	r1 = *(u32*)(r0 + 0);				\
903*c9233655SEduard Zingerman 	/* This used to reduce the max bound to 0x7fffffff */\
904*c9233655SEduard Zingerman 	if r1 == 0 goto l1_%=;				\
905*c9233655SEduard Zingerman 	if r1 > 0x7fffffff goto l0_%=;			\
906*c9233655SEduard Zingerman l1_%=:	r0 = 0;						\
907*c9233655SEduard Zingerman l0_%=:	exit;						\
908*c9233655SEduard Zingerman "	:
909*c9233655SEduard Zingerman 	: __imm(bpf_map_lookup_elem),
910*c9233655SEduard Zingerman 	  __imm_addr(map_hash_8b)
911*c9233655SEduard Zingerman 	: __clobber_all);
912*c9233655SEduard Zingerman }
913*c9233655SEduard Zingerman 
914*c9233655SEduard Zingerman SEC("socket")
915*c9233655SEduard Zingerman __description("bounds checks after 32-bit truncation. test 2")
916*c9233655SEduard Zingerman __success __failure_unpriv __msg_unpriv("R0 leaks addr")
917*c9233655SEduard Zingerman __retval(0)
_32_bit_truncation_test_2(void)918*c9233655SEduard Zingerman __naked void _32_bit_truncation_test_2(void)
919*c9233655SEduard Zingerman {
920*c9233655SEduard Zingerman 	asm volatile ("					\
921*c9233655SEduard Zingerman 	r1 = 0;						\
922*c9233655SEduard Zingerman 	*(u64*)(r10 - 8) = r1;				\
923*c9233655SEduard Zingerman 	r2 = r10;					\
924*c9233655SEduard Zingerman 	r2 += -8;					\
925*c9233655SEduard Zingerman 	r1 = %[map_hash_8b] ll;				\
926*c9233655SEduard Zingerman 	call %[bpf_map_lookup_elem];			\
927*c9233655SEduard Zingerman 	if r0 == 0 goto l0_%=;				\
928*c9233655SEduard Zingerman 	r1 = *(u32*)(r0 + 0);				\
929*c9233655SEduard Zingerman 	if r1 s< 1 goto l1_%=;				\
930*c9233655SEduard Zingerman 	if w1 s< 0 goto l0_%=;				\
931*c9233655SEduard Zingerman l1_%=:	r0 = 0;						\
932*c9233655SEduard Zingerman l0_%=:	exit;						\
933*c9233655SEduard Zingerman "	:
934*c9233655SEduard Zingerman 	: __imm(bpf_map_lookup_elem),
935*c9233655SEduard Zingerman 	  __imm_addr(map_hash_8b)
936*c9233655SEduard Zingerman 	: __clobber_all);
937*c9233655SEduard Zingerman }
938*c9233655SEduard Zingerman 
939*c9233655SEduard Zingerman SEC("xdp")
940*c9233655SEduard Zingerman __description("bound check with JMP_JLT for crossing 64-bit signed boundary")
941*c9233655SEduard Zingerman __success __retval(0)
crossing_64_bit_signed_boundary_1(void)942*c9233655SEduard Zingerman __naked void crossing_64_bit_signed_boundary_1(void)
943*c9233655SEduard Zingerman {
944*c9233655SEduard Zingerman 	asm volatile ("					\
945*c9233655SEduard Zingerman 	r2 = *(u32*)(r1 + %[xdp_md_data]);		\
946*c9233655SEduard Zingerman 	r3 = *(u32*)(r1 + %[xdp_md_data_end]);		\
947*c9233655SEduard Zingerman 	r1 = r2;					\
948*c9233655SEduard Zingerman 	r1 += 1;					\
949*c9233655SEduard Zingerman 	if r1 > r3 goto l0_%=;				\
950*c9233655SEduard Zingerman 	r1 = *(u8*)(r2 + 0);				\
951*c9233655SEduard Zingerman 	r0 = 0x7fffffffffffff10 ll;			\
952*c9233655SEduard Zingerman 	r1 += r0;					\
953*c9233655SEduard Zingerman 	r0 = 0x8000000000000000 ll;			\
954*c9233655SEduard Zingerman l1_%=:	r0 += 1;					\
955*c9233655SEduard Zingerman 	/* r1 unsigned range is [0x7fffffffffffff10, 0x800000000000000f] */\
956*c9233655SEduard Zingerman 	if r0 < r1 goto l1_%=;				\
957*c9233655SEduard Zingerman l0_%=:	r0 = 0;						\
958*c9233655SEduard Zingerman 	exit;						\
959*c9233655SEduard Zingerman "	:
960*c9233655SEduard Zingerman 	: __imm_const(xdp_md_data, offsetof(struct xdp_md, data)),
961*c9233655SEduard Zingerman 	  __imm_const(xdp_md_data_end, offsetof(struct xdp_md, data_end))
962*c9233655SEduard Zingerman 	: __clobber_all);
963*c9233655SEduard Zingerman }
964*c9233655SEduard Zingerman 
965*c9233655SEduard Zingerman SEC("xdp")
966*c9233655SEduard Zingerman __description("bound check with JMP_JSLT for crossing 64-bit signed boundary")
967*c9233655SEduard Zingerman __success __retval(0)
crossing_64_bit_signed_boundary_2(void)968*c9233655SEduard Zingerman __naked void crossing_64_bit_signed_boundary_2(void)
969*c9233655SEduard Zingerman {
970*c9233655SEduard Zingerman 	asm volatile ("					\
971*c9233655SEduard Zingerman 	r2 = *(u32*)(r1 + %[xdp_md_data]);		\
972*c9233655SEduard Zingerman 	r3 = *(u32*)(r1 + %[xdp_md_data_end]);		\
973*c9233655SEduard Zingerman 	r1 = r2;					\
974*c9233655SEduard Zingerman 	r1 += 1;					\
975*c9233655SEduard Zingerman 	if r1 > r3 goto l0_%=;				\
976*c9233655SEduard Zingerman 	r1 = *(u8*)(r2 + 0);				\
977*c9233655SEduard Zingerman 	r0 = 0x7fffffffffffff10 ll;			\
978*c9233655SEduard Zingerman 	r1 += r0;					\
979*c9233655SEduard Zingerman 	r2 = 0x8000000000000fff ll;			\
980*c9233655SEduard Zingerman 	r0 = 0x8000000000000000 ll;			\
981*c9233655SEduard Zingerman l1_%=:	r0 += 1;					\
982*c9233655SEduard Zingerman 	if r0 s> r2 goto l0_%=;				\
983*c9233655SEduard Zingerman 	/* r1 signed range is [S64_MIN, S64_MAX] */	\
984*c9233655SEduard Zingerman 	if r0 s< r1 goto l1_%=;				\
985*c9233655SEduard Zingerman 	r0 = 1;						\
986*c9233655SEduard Zingerman 	exit;						\
987*c9233655SEduard Zingerman l0_%=:	r0 = 0;						\
988*c9233655SEduard Zingerman 	exit;						\
989*c9233655SEduard Zingerman "	:
990*c9233655SEduard Zingerman 	: __imm_const(xdp_md_data, offsetof(struct xdp_md, data)),
991*c9233655SEduard Zingerman 	  __imm_const(xdp_md_data_end, offsetof(struct xdp_md, data_end))
992*c9233655SEduard Zingerman 	: __clobber_all);
993*c9233655SEduard Zingerman }
994*c9233655SEduard Zingerman 
995*c9233655SEduard Zingerman SEC("xdp")
996*c9233655SEduard Zingerman __description("bound check for loop upper bound greater than U32_MAX")
997*c9233655SEduard Zingerman __success __retval(0)
bound_greater_than_u32_max(void)998*c9233655SEduard Zingerman __naked void bound_greater_than_u32_max(void)
999*c9233655SEduard Zingerman {
1000*c9233655SEduard Zingerman 	asm volatile ("					\
1001*c9233655SEduard Zingerman 	r2 = *(u32*)(r1 + %[xdp_md_data]);		\
1002*c9233655SEduard Zingerman 	r3 = *(u32*)(r1 + %[xdp_md_data_end]);		\
1003*c9233655SEduard Zingerman 	r1 = r2;					\
1004*c9233655SEduard Zingerman 	r1 += 1;					\
1005*c9233655SEduard Zingerman 	if r1 > r3 goto l0_%=;				\
1006*c9233655SEduard Zingerman 	r1 = *(u8*)(r2 + 0);				\
1007*c9233655SEduard Zingerman 	r0 = 0x100000000 ll;				\
1008*c9233655SEduard Zingerman 	r1 += r0;					\
1009*c9233655SEduard Zingerman 	r0 = 0x100000000 ll;				\
1010*c9233655SEduard Zingerman l1_%=:	r0 += 1;					\
1011*c9233655SEduard Zingerman 	if r0 < r1 goto l1_%=;				\
1012*c9233655SEduard Zingerman l0_%=:	r0 = 0;						\
1013*c9233655SEduard Zingerman 	exit;						\
1014*c9233655SEduard Zingerman "	:
1015*c9233655SEduard Zingerman 	: __imm_const(xdp_md_data, offsetof(struct xdp_md, data)),
1016*c9233655SEduard Zingerman 	  __imm_const(xdp_md_data_end, offsetof(struct xdp_md, data_end))
1017*c9233655SEduard Zingerman 	: __clobber_all);
1018*c9233655SEduard Zingerman }
1019*c9233655SEduard Zingerman 
1020*c9233655SEduard Zingerman SEC("xdp")
1021*c9233655SEduard Zingerman __description("bound check with JMP32_JLT for crossing 32-bit signed boundary")
1022*c9233655SEduard Zingerman __success __retval(0)
crossing_32_bit_signed_boundary_1(void)1023*c9233655SEduard Zingerman __naked void crossing_32_bit_signed_boundary_1(void)
1024*c9233655SEduard Zingerman {
1025*c9233655SEduard Zingerman 	asm volatile ("					\
1026*c9233655SEduard Zingerman 	r2 = *(u32*)(r1 + %[xdp_md_data]);		\
1027*c9233655SEduard Zingerman 	r3 = *(u32*)(r1 + %[xdp_md_data_end]);		\
1028*c9233655SEduard Zingerman 	r1 = r2;					\
1029*c9233655SEduard Zingerman 	r1 += 1;					\
1030*c9233655SEduard Zingerman 	if r1 > r3 goto l0_%=;				\
1031*c9233655SEduard Zingerman 	r1 = *(u8*)(r2 + 0);				\
1032*c9233655SEduard Zingerman 	w0 = 0x7fffff10;				\
1033*c9233655SEduard Zingerman 	w1 += w0;					\
1034*c9233655SEduard Zingerman 	w0 = 0x80000000;				\
1035*c9233655SEduard Zingerman l1_%=:	w0 += 1;					\
1036*c9233655SEduard Zingerman 	/* r1 unsigned range is [0, 0x8000000f] */	\
1037*c9233655SEduard Zingerman 	if w0 < w1 goto l1_%=;				\
1038*c9233655SEduard Zingerman l0_%=:	r0 = 0;						\
1039*c9233655SEduard Zingerman 	exit;						\
1040*c9233655SEduard Zingerman "	:
1041*c9233655SEduard Zingerman 	: __imm_const(xdp_md_data, offsetof(struct xdp_md, data)),
1042*c9233655SEduard Zingerman 	  __imm_const(xdp_md_data_end, offsetof(struct xdp_md, data_end))
1043*c9233655SEduard Zingerman 	: __clobber_all);
1044*c9233655SEduard Zingerman }
1045*c9233655SEduard Zingerman 
1046*c9233655SEduard Zingerman SEC("xdp")
1047*c9233655SEduard Zingerman __description("bound check with JMP32_JSLT for crossing 32-bit signed boundary")
1048*c9233655SEduard Zingerman __success __retval(0)
crossing_32_bit_signed_boundary_2(void)1049*c9233655SEduard Zingerman __naked void crossing_32_bit_signed_boundary_2(void)
1050*c9233655SEduard Zingerman {
1051*c9233655SEduard Zingerman 	asm volatile ("					\
1052*c9233655SEduard Zingerman 	r2 = *(u32*)(r1 + %[xdp_md_data]);		\
1053*c9233655SEduard Zingerman 	r3 = *(u32*)(r1 + %[xdp_md_data_end]);		\
1054*c9233655SEduard Zingerman 	r1 = r2;					\
1055*c9233655SEduard Zingerman 	r1 += 1;					\
1056*c9233655SEduard Zingerman 	if r1 > r3 goto l0_%=;				\
1057*c9233655SEduard Zingerman 	r1 = *(u8*)(r2 + 0);				\
1058*c9233655SEduard Zingerman 	w0 = 0x7fffff10;				\
1059*c9233655SEduard Zingerman 	w1 += w0;					\
1060*c9233655SEduard Zingerman 	w2 = 0x80000fff;				\
1061*c9233655SEduard Zingerman 	w0 = 0x80000000;				\
1062*c9233655SEduard Zingerman l1_%=:	w0 += 1;					\
1063*c9233655SEduard Zingerman 	if w0 s> w2 goto l0_%=;				\
1064*c9233655SEduard Zingerman 	/* r1 signed range is [S32_MIN, S32_MAX] */	\
1065*c9233655SEduard Zingerman 	if w0 s< w1 goto l1_%=;				\
1066*c9233655SEduard Zingerman 	r0 = 1;						\
1067*c9233655SEduard Zingerman 	exit;						\
1068*c9233655SEduard Zingerman l0_%=:	r0 = 0;						\
1069*c9233655SEduard Zingerman 	exit;						\
1070*c9233655SEduard Zingerman "	:
1071*c9233655SEduard Zingerman 	: __imm_const(xdp_md_data, offsetof(struct xdp_md, data)),
1072*c9233655SEduard Zingerman 	  __imm_const(xdp_md_data_end, offsetof(struct xdp_md, data_end))
1073*c9233655SEduard Zingerman 	: __clobber_all);
1074*c9233655SEduard Zingerman }
1075*c9233655SEduard Zingerman 
1076*c9233655SEduard Zingerman char _license[] SEC("license") = "GPL";
1077