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