1c9233655SEduard Zingerman // SPDX-License-Identifier: GPL-2.0
2c9233655SEduard Zingerman /* Converted from tools/testing/selftests/bpf/verifier/bounds.c */
3c9233655SEduard Zingerman
4c9233655SEduard Zingerman #include <linux/bpf.h>
5d81526a6SPaul Chaignon #include <../../../include/linux/filter.h>
6c9233655SEduard Zingerman #include <bpf/bpf_helpers.h>
7c9233655SEduard Zingerman #include "bpf_misc.h"
8c9233655SEduard Zingerman
9c9233655SEduard Zingerman struct {
10c9233655SEduard Zingerman __uint(type, BPF_MAP_TYPE_HASH);
11c9233655SEduard Zingerman __uint(max_entries, 1);
12c9233655SEduard Zingerman __type(key, long long);
13c9233655SEduard Zingerman __type(value, long long);
14c9233655SEduard Zingerman } map_hash_8b SEC(".maps");
15c9233655SEduard Zingerman
16c9233655SEduard Zingerman SEC("socket")
17c9233655SEduard Zingerman __description("subtraction bounds (map value) variant 1")
18c9233655SEduard Zingerman __failure __msg("R0 max value is outside of the allowed memory range")
19c9233655SEduard Zingerman __failure_unpriv
bounds_map_value_variant_1(void)20c9233655SEduard Zingerman __naked void bounds_map_value_variant_1(void)
21c9233655SEduard Zingerman {
22c9233655SEduard Zingerman asm volatile (" \
23c9233655SEduard Zingerman r1 = 0; \
24c9233655SEduard Zingerman *(u64*)(r10 - 8) = r1; \
25c9233655SEduard Zingerman r2 = r10; \
26c9233655SEduard Zingerman r2 += -8; \
27c9233655SEduard Zingerman r1 = %[map_hash_8b] ll; \
28c9233655SEduard Zingerman call %[bpf_map_lookup_elem]; \
29c9233655SEduard Zingerman if r0 == 0 goto l0_%=; \
30c9233655SEduard Zingerman r1 = *(u8*)(r0 + 0); \
31c9233655SEduard Zingerman if r1 > 0xff goto l0_%=; \
32c9233655SEduard Zingerman r3 = *(u8*)(r0 + 1); \
33c9233655SEduard Zingerman if r3 > 0xff goto l0_%=; \
34c9233655SEduard Zingerman r1 -= r3; \
35c9233655SEduard Zingerman r1 >>= 56; \
36c9233655SEduard Zingerman r0 += r1; \
37c9233655SEduard Zingerman r0 = *(u8*)(r0 + 0); \
38c9233655SEduard Zingerman exit; \
39c9233655SEduard Zingerman l0_%=: r0 = 0; \
40c9233655SEduard Zingerman exit; \
41c9233655SEduard Zingerman " :
42c9233655SEduard Zingerman : __imm(bpf_map_lookup_elem),
43c9233655SEduard Zingerman __imm_addr(map_hash_8b)
44c9233655SEduard Zingerman : __clobber_all);
45c9233655SEduard Zingerman }
46c9233655SEduard Zingerman
47c9233655SEduard Zingerman SEC("socket")
48c9233655SEduard Zingerman __description("subtraction bounds (map value) variant 2")
49c9233655SEduard Zingerman __failure
50c9233655SEduard Zingerman __msg("R0 min value is negative, either use unsigned index or do a if (index >=0) check.")
51c9233655SEduard Zingerman __msg_unpriv("R1 has unknown scalar with mixed signed bounds")
bounds_map_value_variant_2(void)52c9233655SEduard Zingerman __naked void bounds_map_value_variant_2(void)
53c9233655SEduard Zingerman {
54c9233655SEduard Zingerman asm volatile (" \
55c9233655SEduard Zingerman r1 = 0; \
56c9233655SEduard Zingerman *(u64*)(r10 - 8) = r1; \
57c9233655SEduard Zingerman r2 = r10; \
58c9233655SEduard Zingerman r2 += -8; \
59c9233655SEduard Zingerman r1 = %[map_hash_8b] ll; \
60c9233655SEduard Zingerman call %[bpf_map_lookup_elem]; \
61c9233655SEduard Zingerman if r0 == 0 goto l0_%=; \
62c9233655SEduard Zingerman r1 = *(u8*)(r0 + 0); \
63c9233655SEduard Zingerman if r1 > 0xff goto l0_%=; \
64c9233655SEduard Zingerman r3 = *(u8*)(r0 + 1); \
65c9233655SEduard Zingerman if r3 > 0xff goto l0_%=; \
66c9233655SEduard Zingerman r1 -= r3; \
67c9233655SEduard Zingerman r0 += r1; \
68c9233655SEduard Zingerman r0 = *(u8*)(r0 + 0); \
69c9233655SEduard Zingerman exit; \
70c9233655SEduard Zingerman l0_%=: r0 = 0; \
71c9233655SEduard Zingerman exit; \
72c9233655SEduard Zingerman " :
73c9233655SEduard Zingerman : __imm(bpf_map_lookup_elem),
74c9233655SEduard Zingerman __imm_addr(map_hash_8b)
75c9233655SEduard Zingerman : __clobber_all);
76c9233655SEduard Zingerman }
77c9233655SEduard Zingerman
78c9233655SEduard Zingerman SEC("socket")
79c9233655SEduard Zingerman __description("check subtraction on pointers for unpriv")
80c9233655SEduard Zingerman __success __failure_unpriv __msg_unpriv("R9 pointer -= pointer prohibited")
81c9233655SEduard Zingerman __retval(0)
subtraction_on_pointers_for_unpriv(void)82c9233655SEduard Zingerman __naked void subtraction_on_pointers_for_unpriv(void)
83c9233655SEduard Zingerman {
84c9233655SEduard Zingerman asm volatile (" \
85c9233655SEduard Zingerman r0 = 0; \
86c9233655SEduard Zingerman r1 = %[map_hash_8b] ll; \
87c9233655SEduard Zingerman r2 = r10; \
88c9233655SEduard Zingerman r2 += -8; \
89c9233655SEduard Zingerman r6 = 9; \
90c9233655SEduard Zingerman *(u64*)(r2 + 0) = r6; \
91c9233655SEduard Zingerman call %[bpf_map_lookup_elem]; \
92c9233655SEduard Zingerman r9 = r10; \
93c9233655SEduard Zingerman r9 -= r0; \
94c9233655SEduard Zingerman r1 = %[map_hash_8b] ll; \
95c9233655SEduard Zingerman r2 = r10; \
96c9233655SEduard Zingerman r2 += -8; \
97c9233655SEduard Zingerman r6 = 0; \
98c9233655SEduard Zingerman *(u64*)(r2 + 0) = r6; \
99c9233655SEduard Zingerman call %[bpf_map_lookup_elem]; \
100c9233655SEduard Zingerman if r0 != 0 goto l0_%=; \
101c9233655SEduard Zingerman exit; \
102c9233655SEduard Zingerman l0_%=: *(u64*)(r0 + 0) = r9; \
103c9233655SEduard Zingerman r0 = 0; \
104c9233655SEduard Zingerman exit; \
105c9233655SEduard Zingerman " :
106c9233655SEduard Zingerman : __imm(bpf_map_lookup_elem),
107c9233655SEduard Zingerman __imm_addr(map_hash_8b)
108c9233655SEduard Zingerman : __clobber_all);
109c9233655SEduard Zingerman }
110c9233655SEduard Zingerman
111c9233655SEduard Zingerman SEC("socket")
112c9233655SEduard Zingerman __description("bounds check based on zero-extended MOV")
113c9233655SEduard Zingerman __success __success_unpriv __retval(0)
based_on_zero_extended_mov(void)114c9233655SEduard Zingerman __naked void based_on_zero_extended_mov(void)
115c9233655SEduard Zingerman {
116c9233655SEduard Zingerman asm volatile (" \
117c9233655SEduard Zingerman r1 = 0; \
118c9233655SEduard Zingerman *(u64*)(r10 - 8) = r1; \
119c9233655SEduard Zingerman r2 = r10; \
120c9233655SEduard Zingerman r2 += -8; \
121c9233655SEduard Zingerman r1 = %[map_hash_8b] ll; \
122c9233655SEduard Zingerman call %[bpf_map_lookup_elem]; \
123c9233655SEduard Zingerman if r0 == 0 goto l0_%=; \
124c9233655SEduard Zingerman /* r2 = 0x0000'0000'ffff'ffff */ \
125c9233655SEduard Zingerman w2 = 0xffffffff; \
126c9233655SEduard Zingerman /* r2 = 0 */ \
127c9233655SEduard Zingerman r2 >>= 32; \
128c9233655SEduard Zingerman /* no-op */ \
129c9233655SEduard Zingerman r0 += r2; \
130c9233655SEduard Zingerman /* access at offset 0 */ \
131c9233655SEduard Zingerman r0 = *(u8*)(r0 + 0); \
132c9233655SEduard Zingerman l0_%=: /* exit */ \
133c9233655SEduard Zingerman r0 = 0; \
134c9233655SEduard Zingerman exit; \
135c9233655SEduard Zingerman " :
136c9233655SEduard Zingerman : __imm(bpf_map_lookup_elem),
137c9233655SEduard Zingerman __imm_addr(map_hash_8b)
138c9233655SEduard Zingerman : __clobber_all);
139c9233655SEduard Zingerman }
140c9233655SEduard Zingerman
141c9233655SEduard Zingerman SEC("socket")
142c9233655SEduard Zingerman __description("bounds check based on sign-extended MOV. test1")
143c9233655SEduard Zingerman __failure __msg("map_value pointer and 4294967295")
144c9233655SEduard Zingerman __failure_unpriv
on_sign_extended_mov_test1(void)145c9233655SEduard Zingerman __naked void on_sign_extended_mov_test1(void)
146c9233655SEduard Zingerman {
147c9233655SEduard Zingerman asm volatile (" \
148c9233655SEduard Zingerman r1 = 0; \
149c9233655SEduard Zingerman *(u64*)(r10 - 8) = r1; \
150c9233655SEduard Zingerman r2 = r10; \
151c9233655SEduard Zingerman r2 += -8; \
152c9233655SEduard Zingerman r1 = %[map_hash_8b] ll; \
153c9233655SEduard Zingerman call %[bpf_map_lookup_elem]; \
154c9233655SEduard Zingerman if r0 == 0 goto l0_%=; \
155c9233655SEduard Zingerman /* r2 = 0xffff'ffff'ffff'ffff */ \
156c9233655SEduard Zingerman r2 = 0xffffffff; \
157c9233655SEduard Zingerman /* r2 = 0xffff'ffff */ \
158c9233655SEduard Zingerman r2 >>= 32; \
159c9233655SEduard Zingerman /* r0 = <oob pointer> */ \
160c9233655SEduard Zingerman r0 += r2; \
161c9233655SEduard Zingerman /* access to OOB pointer */ \
162c9233655SEduard Zingerman r0 = *(u8*)(r0 + 0); \
163c9233655SEduard Zingerman l0_%=: /* exit */ \
164c9233655SEduard Zingerman r0 = 0; \
165c9233655SEduard Zingerman exit; \
166c9233655SEduard Zingerman " :
167c9233655SEduard Zingerman : __imm(bpf_map_lookup_elem),
168c9233655SEduard Zingerman __imm_addr(map_hash_8b)
169c9233655SEduard Zingerman : __clobber_all);
170c9233655SEduard Zingerman }
171c9233655SEduard Zingerman
172c9233655SEduard Zingerman SEC("socket")
173c9233655SEduard Zingerman __description("bounds check based on sign-extended MOV. test2")
174c9233655SEduard Zingerman __failure __msg("R0 min value is outside of the allowed memory range")
175c9233655SEduard Zingerman __failure_unpriv
on_sign_extended_mov_test2(void)176c9233655SEduard Zingerman __naked void on_sign_extended_mov_test2(void)
177c9233655SEduard Zingerman {
178c9233655SEduard Zingerman asm volatile (" \
179c9233655SEduard Zingerman r1 = 0; \
180c9233655SEduard Zingerman *(u64*)(r10 - 8) = r1; \
181c9233655SEduard Zingerman r2 = r10; \
182c9233655SEduard Zingerman r2 += -8; \
183c9233655SEduard Zingerman r1 = %[map_hash_8b] ll; \
184c9233655SEduard Zingerman call %[bpf_map_lookup_elem]; \
185c9233655SEduard Zingerman if r0 == 0 goto l0_%=; \
186c9233655SEduard Zingerman /* r2 = 0xffff'ffff'ffff'ffff */ \
187c9233655SEduard Zingerman r2 = 0xffffffff; \
188c9233655SEduard Zingerman /* r2 = 0xfff'ffff */ \
189c9233655SEduard Zingerman r2 >>= 36; \
190c9233655SEduard Zingerman /* r0 = <oob pointer> */ \
191c9233655SEduard Zingerman r0 += r2; \
192c9233655SEduard Zingerman /* access to OOB pointer */ \
193c9233655SEduard Zingerman r0 = *(u8*)(r0 + 0); \
194c9233655SEduard Zingerman l0_%=: /* exit */ \
195c9233655SEduard Zingerman r0 = 0; \
196c9233655SEduard Zingerman exit; \
197c9233655SEduard Zingerman " :
198c9233655SEduard Zingerman : __imm(bpf_map_lookup_elem),
199c9233655SEduard Zingerman __imm_addr(map_hash_8b)
200c9233655SEduard Zingerman : __clobber_all);
201c9233655SEduard Zingerman }
202c9233655SEduard Zingerman
203c9233655SEduard Zingerman SEC("tc")
204c9233655SEduard Zingerman __description("bounds check based on reg_off + var_off + insn_off. test1")
205c9233655SEduard Zingerman __failure __msg("value_size=8 off=1073741825")
var_off_insn_off_test1(void)206c9233655SEduard Zingerman __naked void var_off_insn_off_test1(void)
207c9233655SEduard Zingerman {
208c9233655SEduard Zingerman asm volatile (" \
209c9233655SEduard Zingerman r6 = *(u32*)(r1 + %[__sk_buff_mark]); \
210c9233655SEduard Zingerman r1 = 0; \
211c9233655SEduard Zingerman *(u64*)(r10 - 8) = r1; \
212c9233655SEduard Zingerman r2 = r10; \
213c9233655SEduard Zingerman r2 += -8; \
214c9233655SEduard Zingerman r1 = %[map_hash_8b] ll; \
215c9233655SEduard Zingerman call %[bpf_map_lookup_elem]; \
216c9233655SEduard Zingerman if r0 == 0 goto l0_%=; \
217c9233655SEduard Zingerman r6 &= 1; \
218c9233655SEduard Zingerman r6 += %[__imm_0]; \
219c9233655SEduard Zingerman r0 += r6; \
220c9233655SEduard Zingerman r0 += %[__imm_0]; \
221c9233655SEduard Zingerman l0_%=: r0 = *(u8*)(r0 + 3); \
222c9233655SEduard Zingerman r0 = 0; \
223c9233655SEduard Zingerman exit; \
224c9233655SEduard Zingerman " :
225c9233655SEduard Zingerman : __imm(bpf_map_lookup_elem),
226c9233655SEduard Zingerman __imm_addr(map_hash_8b),
227c9233655SEduard Zingerman __imm_const(__imm_0, (1 << 29) - 1),
228c9233655SEduard Zingerman __imm_const(__sk_buff_mark, offsetof(struct __sk_buff, mark))
229c9233655SEduard Zingerman : __clobber_all);
230c9233655SEduard Zingerman }
231c9233655SEduard Zingerman
232c9233655SEduard Zingerman SEC("tc")
233c9233655SEduard Zingerman __description("bounds check based on reg_off + var_off + insn_off. test2")
234c9233655SEduard Zingerman __failure __msg("value 1073741823")
var_off_insn_off_test2(void)235c9233655SEduard Zingerman __naked void var_off_insn_off_test2(void)
236c9233655SEduard Zingerman {
237c9233655SEduard Zingerman asm volatile (" \
238c9233655SEduard Zingerman r6 = *(u32*)(r1 + %[__sk_buff_mark]); \
239c9233655SEduard Zingerman r1 = 0; \
240c9233655SEduard Zingerman *(u64*)(r10 - 8) = r1; \
241c9233655SEduard Zingerman r2 = r10; \
242c9233655SEduard Zingerman r2 += -8; \
243c9233655SEduard Zingerman r1 = %[map_hash_8b] ll; \
244c9233655SEduard Zingerman call %[bpf_map_lookup_elem]; \
245c9233655SEduard Zingerman if r0 == 0 goto l0_%=; \
246c9233655SEduard Zingerman r6 &= 1; \
247c9233655SEduard Zingerman r6 += %[__imm_0]; \
248c9233655SEduard Zingerman r0 += r6; \
249c9233655SEduard Zingerman r0 += %[__imm_1]; \
250c9233655SEduard Zingerman l0_%=: r0 = *(u8*)(r0 + 3); \
251c9233655SEduard Zingerman r0 = 0; \
252c9233655SEduard Zingerman exit; \
253c9233655SEduard Zingerman " :
254c9233655SEduard Zingerman : __imm(bpf_map_lookup_elem),
255c9233655SEduard Zingerman __imm_addr(map_hash_8b),
256c9233655SEduard Zingerman __imm_const(__imm_0, (1 << 30) - 1),
257c9233655SEduard Zingerman __imm_const(__imm_1, (1 << 29) - 1),
258c9233655SEduard Zingerman __imm_const(__sk_buff_mark, offsetof(struct __sk_buff, mark))
259c9233655SEduard Zingerman : __clobber_all);
260c9233655SEduard Zingerman }
261c9233655SEduard Zingerman
262c9233655SEduard Zingerman SEC("socket")
263c9233655SEduard Zingerman __description("bounds check after truncation of non-boundary-crossing range")
264c9233655SEduard Zingerman __success __success_unpriv __retval(0)
of_non_boundary_crossing_range(void)265c9233655SEduard Zingerman __naked void of_non_boundary_crossing_range(void)
266c9233655SEduard Zingerman {
267c9233655SEduard Zingerman asm volatile (" \
268c9233655SEduard Zingerman r1 = 0; \
269c9233655SEduard Zingerman *(u64*)(r10 - 8) = r1; \
270c9233655SEduard Zingerman r2 = r10; \
271c9233655SEduard Zingerman r2 += -8; \
272c9233655SEduard Zingerman r1 = %[map_hash_8b] ll; \
273c9233655SEduard Zingerman call %[bpf_map_lookup_elem]; \
274c9233655SEduard Zingerman if r0 == 0 goto l0_%=; \
275c9233655SEduard Zingerman /* r1 = [0x00, 0xff] */ \
276c9233655SEduard Zingerman r1 = *(u8*)(r0 + 0); \
277c9233655SEduard Zingerman r2 = 1; \
278c9233655SEduard Zingerman /* r2 = 0x10'0000'0000 */ \
279c9233655SEduard Zingerman r2 <<= 36; \
280c9233655SEduard Zingerman /* r1 = [0x10'0000'0000, 0x10'0000'00ff] */ \
281c9233655SEduard Zingerman r1 += r2; \
282c9233655SEduard Zingerman /* r1 = [0x10'7fff'ffff, 0x10'8000'00fe] */ \
283c9233655SEduard Zingerman r1 += 0x7fffffff; \
284c9233655SEduard Zingerman /* r1 = [0x00, 0xff] */ \
285c9233655SEduard Zingerman w1 -= 0x7fffffff; \
286c9233655SEduard Zingerman /* r1 = 0 */ \
287c9233655SEduard Zingerman r1 >>= 8; \
288c9233655SEduard Zingerman /* no-op */ \
289c9233655SEduard Zingerman r0 += r1; \
290c9233655SEduard Zingerman /* access at offset 0 */ \
291c9233655SEduard Zingerman r0 = *(u8*)(r0 + 0); \
292c9233655SEduard Zingerman l0_%=: /* exit */ \
293c9233655SEduard Zingerman r0 = 0; \
294c9233655SEduard Zingerman exit; \
295c9233655SEduard Zingerman " :
296c9233655SEduard Zingerman : __imm(bpf_map_lookup_elem),
297c9233655SEduard Zingerman __imm_addr(map_hash_8b)
298c9233655SEduard Zingerman : __clobber_all);
299c9233655SEduard Zingerman }
300c9233655SEduard Zingerman
301c9233655SEduard Zingerman SEC("socket")
302c9233655SEduard Zingerman __description("bounds check after truncation of boundary-crossing range (1)")
303c9233655SEduard Zingerman __failure
304c9233655SEduard Zingerman /* not actually fully unbounded, but the bound is very high */
305c9233655SEduard Zingerman __msg("value -4294967168 makes map_value pointer be out of bounds")
306c9233655SEduard Zingerman __failure_unpriv
of_boundary_crossing_range_1(void)307c9233655SEduard Zingerman __naked void of_boundary_crossing_range_1(void)
308c9233655SEduard Zingerman {
309c9233655SEduard Zingerman asm volatile (" \
310c9233655SEduard Zingerman r1 = 0; \
311c9233655SEduard Zingerman *(u64*)(r10 - 8) = r1; \
312c9233655SEduard Zingerman r2 = r10; \
313c9233655SEduard Zingerman r2 += -8; \
314c9233655SEduard Zingerman r1 = %[map_hash_8b] ll; \
315c9233655SEduard Zingerman call %[bpf_map_lookup_elem]; \
316c9233655SEduard Zingerman if r0 == 0 goto l0_%=; \
317c9233655SEduard Zingerman /* r1 = [0x00, 0xff] */ \
318c9233655SEduard Zingerman r1 = *(u8*)(r0 + 0); \
319c9233655SEduard Zingerman r1 += %[__imm_0]; \
320c9233655SEduard Zingerman /* r1 = [0xffff'ff80, 0x1'0000'007f] */ \
321c9233655SEduard Zingerman r1 += %[__imm_0]; \
322c9233655SEduard Zingerman /* r1 = [0xffff'ff80, 0xffff'ffff] or \
323c9233655SEduard Zingerman * [0x0000'0000, 0x0000'007f] \
324c9233655SEduard Zingerman */ \
325c9233655SEduard Zingerman w1 += 0; \
326c9233655SEduard Zingerman r1 -= %[__imm_0]; \
327c9233655SEduard Zingerman /* r1 = [0x00, 0xff] or \
328c9233655SEduard Zingerman * [0xffff'ffff'0000'0080, 0xffff'ffff'ffff'ffff]\
329c9233655SEduard Zingerman */ \
330c9233655SEduard Zingerman r1 -= %[__imm_0]; \
331c9233655SEduard Zingerman /* error on OOB pointer computation */ \
332c9233655SEduard Zingerman r0 += r1; \
333c9233655SEduard Zingerman /* exit */ \
334c9233655SEduard Zingerman r0 = 0; \
335c9233655SEduard Zingerman l0_%=: exit; \
336c9233655SEduard Zingerman " :
337c9233655SEduard Zingerman : __imm(bpf_map_lookup_elem),
338c9233655SEduard Zingerman __imm_addr(map_hash_8b),
339c9233655SEduard Zingerman __imm_const(__imm_0, 0xffffff80 >> 1)
340c9233655SEduard Zingerman : __clobber_all);
341c9233655SEduard Zingerman }
342c9233655SEduard Zingerman
343c9233655SEduard Zingerman SEC("socket")
344c9233655SEduard Zingerman __description("bounds check after truncation of boundary-crossing range (2)")
345c9233655SEduard Zingerman __failure __msg("value -4294967168 makes map_value pointer be out of bounds")
346c9233655SEduard Zingerman __failure_unpriv
of_boundary_crossing_range_2(void)347c9233655SEduard Zingerman __naked void of_boundary_crossing_range_2(void)
348c9233655SEduard Zingerman {
349c9233655SEduard Zingerman asm volatile (" \
350c9233655SEduard Zingerman r1 = 0; \
351c9233655SEduard Zingerman *(u64*)(r10 - 8) = r1; \
352c9233655SEduard Zingerman r2 = r10; \
353c9233655SEduard Zingerman r2 += -8; \
354c9233655SEduard Zingerman r1 = %[map_hash_8b] ll; \
355c9233655SEduard Zingerman call %[bpf_map_lookup_elem]; \
356c9233655SEduard Zingerman if r0 == 0 goto l0_%=; \
357c9233655SEduard Zingerman /* r1 = [0x00, 0xff] */ \
358c9233655SEduard Zingerman r1 = *(u8*)(r0 + 0); \
359c9233655SEduard Zingerman r1 += %[__imm_0]; \
360c9233655SEduard Zingerman /* r1 = [0xffff'ff80, 0x1'0000'007f] */ \
361c9233655SEduard Zingerman r1 += %[__imm_0]; \
362c9233655SEduard Zingerman /* r1 = [0xffff'ff80, 0xffff'ffff] or \
363c9233655SEduard Zingerman * [0x0000'0000, 0x0000'007f] \
364c9233655SEduard Zingerman * difference to previous test: truncation via MOV32\
365c9233655SEduard Zingerman * instead of ALU32. \
366c9233655SEduard Zingerman */ \
367c9233655SEduard Zingerman w1 = w1; \
368c9233655SEduard Zingerman r1 -= %[__imm_0]; \
369c9233655SEduard Zingerman /* r1 = [0x00, 0xff] or \
370c9233655SEduard Zingerman * [0xffff'ffff'0000'0080, 0xffff'ffff'ffff'ffff]\
371c9233655SEduard Zingerman */ \
372c9233655SEduard Zingerman r1 -= %[__imm_0]; \
373c9233655SEduard Zingerman /* error on OOB pointer computation */ \
374c9233655SEduard Zingerman r0 += r1; \
375c9233655SEduard Zingerman /* exit */ \
376c9233655SEduard Zingerman r0 = 0; \
377c9233655SEduard Zingerman l0_%=: exit; \
378c9233655SEduard Zingerman " :
379c9233655SEduard Zingerman : __imm(bpf_map_lookup_elem),
380c9233655SEduard Zingerman __imm_addr(map_hash_8b),
381c9233655SEduard Zingerman __imm_const(__imm_0, 0xffffff80 >> 1)
382c9233655SEduard Zingerman : __clobber_all);
383c9233655SEduard Zingerman }
384c9233655SEduard Zingerman
385c9233655SEduard Zingerman SEC("socket")
386c9233655SEduard Zingerman __description("bounds check after wrapping 32-bit addition")
387c9233655SEduard Zingerman __success __success_unpriv __retval(0)
after_wrapping_32_bit_addition(void)388c9233655SEduard Zingerman __naked void after_wrapping_32_bit_addition(void)
389c9233655SEduard Zingerman {
390c9233655SEduard Zingerman asm volatile (" \
391c9233655SEduard Zingerman r1 = 0; \
392c9233655SEduard Zingerman *(u64*)(r10 - 8) = r1; \
393c9233655SEduard Zingerman r2 = r10; \
394c9233655SEduard Zingerman r2 += -8; \
395c9233655SEduard Zingerman r1 = %[map_hash_8b] ll; \
396c9233655SEduard Zingerman call %[bpf_map_lookup_elem]; \
397c9233655SEduard Zingerman if r0 == 0 goto l0_%=; \
398c9233655SEduard Zingerman /* r1 = 0x7fff'ffff */ \
399c9233655SEduard Zingerman r1 = 0x7fffffff; \
400c9233655SEduard Zingerman /* r1 = 0xffff'fffe */ \
401c9233655SEduard Zingerman r1 += 0x7fffffff; \
402c9233655SEduard Zingerman /* r1 = 0 */ \
403c9233655SEduard Zingerman w1 += 2; \
404c9233655SEduard Zingerman /* no-op */ \
405c9233655SEduard Zingerman r0 += r1; \
406c9233655SEduard Zingerman /* access at offset 0 */ \
407c9233655SEduard Zingerman r0 = *(u8*)(r0 + 0); \
408c9233655SEduard Zingerman l0_%=: /* exit */ \
409c9233655SEduard Zingerman r0 = 0; \
410c9233655SEduard Zingerman exit; \
411c9233655SEduard Zingerman " :
412c9233655SEduard Zingerman : __imm(bpf_map_lookup_elem),
413c9233655SEduard Zingerman __imm_addr(map_hash_8b)
414c9233655SEduard Zingerman : __clobber_all);
415c9233655SEduard Zingerman }
416c9233655SEduard Zingerman
417c9233655SEduard Zingerman SEC("socket")
418c9233655SEduard Zingerman __description("bounds check after shift with oversized count operand")
419c9233655SEduard Zingerman __failure __msg("R0 max value is outside of the allowed memory range")
420c9233655SEduard Zingerman __failure_unpriv
shift_with_oversized_count_operand(void)421c9233655SEduard Zingerman __naked void shift_with_oversized_count_operand(void)
422c9233655SEduard Zingerman {
423c9233655SEduard Zingerman asm volatile (" \
424c9233655SEduard Zingerman r1 = 0; \
425c9233655SEduard Zingerman *(u64*)(r10 - 8) = r1; \
426c9233655SEduard Zingerman r2 = r10; \
427c9233655SEduard Zingerman r2 += -8; \
428c9233655SEduard Zingerman r1 = %[map_hash_8b] ll; \
429c9233655SEduard Zingerman call %[bpf_map_lookup_elem]; \
430c9233655SEduard Zingerman if r0 == 0 goto l0_%=; \
431c9233655SEduard Zingerman r2 = 32; \
432c9233655SEduard Zingerman r1 = 1; \
433c9233655SEduard Zingerman /* r1 = (u32)1 << (u32)32 = ? */ \
434c9233655SEduard Zingerman w1 <<= w2; \
435c9233655SEduard Zingerman /* r1 = [0x0000, 0xffff] */ \
436c9233655SEduard Zingerman r1 &= 0xffff; \
437c9233655SEduard Zingerman /* computes unknown pointer, potentially OOB */ \
438c9233655SEduard Zingerman r0 += r1; \
439c9233655SEduard Zingerman /* potentially OOB access */ \
440c9233655SEduard Zingerman r0 = *(u8*)(r0 + 0); \
441c9233655SEduard Zingerman l0_%=: /* exit */ \
442c9233655SEduard Zingerman r0 = 0; \
443c9233655SEduard Zingerman exit; \
444c9233655SEduard Zingerman " :
445c9233655SEduard Zingerman : __imm(bpf_map_lookup_elem),
446c9233655SEduard Zingerman __imm_addr(map_hash_8b)
447c9233655SEduard Zingerman : __clobber_all);
448c9233655SEduard Zingerman }
449c9233655SEduard Zingerman
450c9233655SEduard Zingerman SEC("socket")
451c9233655SEduard Zingerman __description("bounds check after right shift of maybe-negative number")
452c9233655SEduard Zingerman __failure __msg("R0 unbounded memory access")
453c9233655SEduard Zingerman __failure_unpriv
shift_of_maybe_negative_number(void)454c9233655SEduard Zingerman __naked void shift_of_maybe_negative_number(void)
455c9233655SEduard Zingerman {
456c9233655SEduard Zingerman asm volatile (" \
457c9233655SEduard Zingerman r1 = 0; \
458c9233655SEduard Zingerman *(u64*)(r10 - 8) = r1; \
459c9233655SEduard Zingerman r2 = r10; \
460c9233655SEduard Zingerman r2 += -8; \
461c9233655SEduard Zingerman r1 = %[map_hash_8b] ll; \
462c9233655SEduard Zingerman call %[bpf_map_lookup_elem]; \
463c9233655SEduard Zingerman if r0 == 0 goto l0_%=; \
464c9233655SEduard Zingerman /* r1 = [0x00, 0xff] */ \
465c9233655SEduard Zingerman r1 = *(u8*)(r0 + 0); \
466c9233655SEduard Zingerman /* r1 = [-0x01, 0xfe] */ \
467c9233655SEduard Zingerman r1 -= 1; \
468c9233655SEduard Zingerman /* r1 = 0 or 0xff'ffff'ffff'ffff */ \
469c9233655SEduard Zingerman r1 >>= 8; \
470c9233655SEduard Zingerman /* r1 = 0 or 0xffff'ffff'ffff */ \
471c9233655SEduard Zingerman r1 >>= 8; \
472c9233655SEduard Zingerman /* computes unknown pointer, potentially OOB */ \
473c9233655SEduard Zingerman r0 += r1; \
474c9233655SEduard Zingerman /* potentially OOB access */ \
475c9233655SEduard Zingerman r0 = *(u8*)(r0 + 0); \
476c9233655SEduard Zingerman l0_%=: /* exit */ \
477c9233655SEduard Zingerman r0 = 0; \
478c9233655SEduard Zingerman exit; \
479c9233655SEduard Zingerman " :
480c9233655SEduard Zingerman : __imm(bpf_map_lookup_elem),
481c9233655SEduard Zingerman __imm_addr(map_hash_8b)
482c9233655SEduard Zingerman : __clobber_all);
483c9233655SEduard Zingerman }
484c9233655SEduard Zingerman
485c9233655SEduard Zingerman SEC("socket")
486c9233655SEduard Zingerman __description("bounds check after 32-bit right shift with 64-bit input")
487c9233655SEduard Zingerman __failure __msg("math between map_value pointer and 4294967294 is not allowed")
488c9233655SEduard Zingerman __failure_unpriv
shift_with_64_bit_input(void)489c9233655SEduard Zingerman __naked void shift_with_64_bit_input(void)
490c9233655SEduard Zingerman {
491c9233655SEduard Zingerman asm volatile (" \
492c9233655SEduard Zingerman r1 = 0; \
493c9233655SEduard Zingerman *(u64*)(r10 - 8) = r1; \
494c9233655SEduard Zingerman r2 = r10; \
495c9233655SEduard Zingerman r2 += -8; \
496c9233655SEduard Zingerman r1 = %[map_hash_8b] ll; \
497c9233655SEduard Zingerman call %[bpf_map_lookup_elem]; \
498c9233655SEduard Zingerman if r0 == 0 goto l0_%=; \
499c9233655SEduard Zingerman r1 = 2; \
500c9233655SEduard Zingerman /* r1 = 1<<32 */ \
501c9233655SEduard Zingerman r1 <<= 31; \
502c9233655SEduard Zingerman /* r1 = 0 (NOT 2!) */ \
503c9233655SEduard Zingerman w1 >>= 31; \
504c9233655SEduard Zingerman /* r1 = 0xffff'fffe (NOT 0!) */ \
505c9233655SEduard Zingerman w1 -= 2; \
506c9233655SEduard Zingerman /* error on computing OOB pointer */ \
507c9233655SEduard Zingerman r0 += r1; \
508c9233655SEduard Zingerman /* exit */ \
509c9233655SEduard Zingerman r0 = 0; \
510c9233655SEduard Zingerman l0_%=: exit; \
511c9233655SEduard Zingerman " :
512c9233655SEduard Zingerman : __imm(bpf_map_lookup_elem),
513c9233655SEduard Zingerman __imm_addr(map_hash_8b)
514c9233655SEduard Zingerman : __clobber_all);
515c9233655SEduard Zingerman }
516c9233655SEduard Zingerman
517c9233655SEduard Zingerman SEC("socket")
518c9233655SEduard Zingerman __description("bounds check map access with off+size signed 32bit overflow. test1")
519c9233655SEduard Zingerman __failure __msg("map_value pointer and 2147483646")
520c9233655SEduard Zingerman __failure_unpriv
size_signed_32bit_overflow_test1(void)521c9233655SEduard Zingerman __naked void size_signed_32bit_overflow_test1(void)
522c9233655SEduard Zingerman {
523c9233655SEduard Zingerman asm volatile (" \
524c9233655SEduard Zingerman r1 = 0; \
525c9233655SEduard Zingerman *(u64*)(r10 - 8) = r1; \
526c9233655SEduard Zingerman r2 = r10; \
527c9233655SEduard Zingerman r2 += -8; \
528c9233655SEduard Zingerman r1 = %[map_hash_8b] ll; \
529c9233655SEduard Zingerman call %[bpf_map_lookup_elem]; \
530c9233655SEduard Zingerman if r0 != 0 goto l0_%=; \
531c9233655SEduard Zingerman exit; \
532c9233655SEduard Zingerman l0_%=: r0 += 0x7ffffffe; \
533c9233655SEduard Zingerman r0 = *(u64*)(r0 + 0); \
534c9233655SEduard Zingerman goto l1_%=; \
535c9233655SEduard Zingerman l1_%=: exit; \
536c9233655SEduard Zingerman " :
537c9233655SEduard Zingerman : __imm(bpf_map_lookup_elem),
538c9233655SEduard Zingerman __imm_addr(map_hash_8b)
539c9233655SEduard Zingerman : __clobber_all);
540c9233655SEduard Zingerman }
541c9233655SEduard Zingerman
542c9233655SEduard Zingerman SEC("socket")
543c9233655SEduard Zingerman __description("bounds check map access with off+size signed 32bit overflow. test2")
544c9233655SEduard Zingerman __failure __msg("pointer offset 1073741822")
545c9233655SEduard Zingerman __msg_unpriv("R0 pointer arithmetic of map value goes out of range")
size_signed_32bit_overflow_test2(void)546c9233655SEduard Zingerman __naked void size_signed_32bit_overflow_test2(void)
547c9233655SEduard Zingerman {
548c9233655SEduard Zingerman asm volatile (" \
549c9233655SEduard Zingerman r1 = 0; \
550c9233655SEduard Zingerman *(u64*)(r10 - 8) = r1; \
551c9233655SEduard Zingerman r2 = r10; \
552c9233655SEduard Zingerman r2 += -8; \
553c9233655SEduard Zingerman r1 = %[map_hash_8b] ll; \
554c9233655SEduard Zingerman call %[bpf_map_lookup_elem]; \
555c9233655SEduard Zingerman if r0 != 0 goto l0_%=; \
556c9233655SEduard Zingerman exit; \
557c9233655SEduard Zingerman l0_%=: r0 += 0x1fffffff; \
558c9233655SEduard Zingerman r0 += 0x1fffffff; \
559c9233655SEduard Zingerman r0 += 0x1fffffff; \
560c9233655SEduard Zingerman r0 = *(u64*)(r0 + 0); \
561c9233655SEduard Zingerman goto l1_%=; \
562c9233655SEduard Zingerman l1_%=: exit; \
563c9233655SEduard Zingerman " :
564c9233655SEduard Zingerman : __imm(bpf_map_lookup_elem),
565c9233655SEduard Zingerman __imm_addr(map_hash_8b)
566c9233655SEduard Zingerman : __clobber_all);
567c9233655SEduard Zingerman }
568c9233655SEduard Zingerman
569c9233655SEduard Zingerman SEC("socket")
570c9233655SEduard Zingerman __description("bounds check map access with off+size signed 32bit overflow. test3")
571c9233655SEduard Zingerman __failure __msg("pointer offset -1073741822")
572c9233655SEduard Zingerman __msg_unpriv("R0 pointer arithmetic of map value goes out of range")
size_signed_32bit_overflow_test3(void)573c9233655SEduard Zingerman __naked void size_signed_32bit_overflow_test3(void)
574c9233655SEduard Zingerman {
575c9233655SEduard Zingerman asm volatile (" \
576c9233655SEduard Zingerman r1 = 0; \
577c9233655SEduard Zingerman *(u64*)(r10 - 8) = r1; \
578c9233655SEduard Zingerman r2 = r10; \
579c9233655SEduard Zingerman r2 += -8; \
580c9233655SEduard Zingerman r1 = %[map_hash_8b] ll; \
581c9233655SEduard Zingerman call %[bpf_map_lookup_elem]; \
582c9233655SEduard Zingerman if r0 != 0 goto l0_%=; \
583c9233655SEduard Zingerman exit; \
584c9233655SEduard Zingerman l0_%=: r0 -= 0x1fffffff; \
585c9233655SEduard Zingerman r0 -= 0x1fffffff; \
586c9233655SEduard Zingerman r0 = *(u64*)(r0 + 2); \
587c9233655SEduard Zingerman goto l1_%=; \
588c9233655SEduard Zingerman l1_%=: exit; \
589c9233655SEduard Zingerman " :
590c9233655SEduard Zingerman : __imm(bpf_map_lookup_elem),
591c9233655SEduard Zingerman __imm_addr(map_hash_8b)
592c9233655SEduard Zingerman : __clobber_all);
593c9233655SEduard Zingerman }
594c9233655SEduard Zingerman
595c9233655SEduard Zingerman SEC("socket")
596c9233655SEduard Zingerman __description("bounds check map access with off+size signed 32bit overflow. test4")
597c9233655SEduard Zingerman __failure __msg("map_value pointer and 1000000000000")
598c9233655SEduard Zingerman __failure_unpriv
size_signed_32bit_overflow_test4(void)599c9233655SEduard Zingerman __naked void size_signed_32bit_overflow_test4(void)
600c9233655SEduard Zingerman {
601c9233655SEduard Zingerman asm volatile (" \
602c9233655SEduard Zingerman r1 = 0; \
603c9233655SEduard Zingerman *(u64*)(r10 - 8) = r1; \
604c9233655SEduard Zingerman r2 = r10; \
605c9233655SEduard Zingerman r2 += -8; \
606c9233655SEduard Zingerman r1 = %[map_hash_8b] ll; \
607c9233655SEduard Zingerman call %[bpf_map_lookup_elem]; \
608c9233655SEduard Zingerman if r0 != 0 goto l0_%=; \
609c9233655SEduard Zingerman exit; \
610c9233655SEduard Zingerman l0_%=: r1 = 1000000; \
611c9233655SEduard Zingerman r1 *= 1000000; \
612c9233655SEduard Zingerman r0 += r1; \
613c9233655SEduard Zingerman r0 = *(u64*)(r0 + 2); \
614c9233655SEduard Zingerman goto l1_%=; \
615c9233655SEduard Zingerman l1_%=: exit; \
616c9233655SEduard Zingerman " :
617c9233655SEduard Zingerman : __imm(bpf_map_lookup_elem),
618c9233655SEduard Zingerman __imm_addr(map_hash_8b)
619c9233655SEduard Zingerman : __clobber_all);
620c9233655SEduard Zingerman }
621c9233655SEduard Zingerman
622c9233655SEduard Zingerman SEC("socket")
623c9233655SEduard Zingerman __description("bounds check mixed 32bit and 64bit arithmetic. test1")
624d6f1c85fSLuis Gerhorst __success __success_unpriv
625c9233655SEduard Zingerman __retval(0)
626d6f1c85fSLuis Gerhorst #ifdef SPEC_V1
627d6f1c85fSLuis Gerhorst __xlated_unpriv("goto pc+2")
628d6f1c85fSLuis Gerhorst __xlated_unpriv("nospec") /* inserted to prevent `R0 invalid mem access 'scalar'` */
629d6f1c85fSLuis Gerhorst __xlated_unpriv("goto pc-1") /* sanitized dead code */
630d6f1c85fSLuis Gerhorst __xlated_unpriv("exit")
631d6f1c85fSLuis Gerhorst #endif
_32bit_and_64bit_arithmetic_test1(void)632c9233655SEduard Zingerman __naked void _32bit_and_64bit_arithmetic_test1(void)
633c9233655SEduard Zingerman {
634c9233655SEduard Zingerman asm volatile (" \
635c9233655SEduard Zingerman r0 = 0; \
636c9233655SEduard Zingerman r1 = -1; \
637c9233655SEduard Zingerman r1 <<= 32; \
638c9233655SEduard Zingerman r1 += 1; \
639c9233655SEduard Zingerman /* r1 = 0xffffFFFF00000001 */ \
640c9233655SEduard Zingerman if w1 > 1 goto l0_%=; \
641c9233655SEduard Zingerman /* check ALU64 op keeps 32bit bounds */ \
642c9233655SEduard Zingerman r1 += 1; \
643c9233655SEduard Zingerman if w1 > 2 goto l0_%=; \
644c9233655SEduard Zingerman goto l1_%=; \
645c9233655SEduard Zingerman l0_%=: /* invalid ldx if bounds are lost above */ \
646c9233655SEduard Zingerman r0 = *(u64*)(r0 - 1); \
647c9233655SEduard Zingerman l1_%=: exit; \
648c9233655SEduard Zingerman " ::: __clobber_all);
649c9233655SEduard Zingerman }
650c9233655SEduard Zingerman
651c9233655SEduard Zingerman SEC("socket")
652c9233655SEduard Zingerman __description("bounds check mixed 32bit and 64bit arithmetic. test2")
653d6f1c85fSLuis Gerhorst __success __success_unpriv
654c9233655SEduard Zingerman __retval(0)
655d6f1c85fSLuis Gerhorst #ifdef SPEC_V1
656d6f1c85fSLuis Gerhorst __xlated_unpriv("goto pc+2")
657d6f1c85fSLuis Gerhorst __xlated_unpriv("nospec") /* inserted to prevent `R0 invalid mem access 'scalar'` */
658d6f1c85fSLuis Gerhorst __xlated_unpriv("goto pc-1") /* sanitized dead code */
659d6f1c85fSLuis Gerhorst __xlated_unpriv("exit")
660d6f1c85fSLuis Gerhorst #endif
_32bit_and_64bit_arithmetic_test2(void)661c9233655SEduard Zingerman __naked void _32bit_and_64bit_arithmetic_test2(void)
662c9233655SEduard Zingerman {
663c9233655SEduard Zingerman asm volatile (" \
664c9233655SEduard Zingerman r0 = 0; \
665c9233655SEduard Zingerman r1 = -1; \
666c9233655SEduard Zingerman r1 <<= 32; \
667c9233655SEduard Zingerman r1 += 1; \
668c9233655SEduard Zingerman /* r1 = 0xffffFFFF00000001 */ \
669c9233655SEduard Zingerman r2 = 3; \
670c9233655SEduard Zingerman /* r1 = 0x2 */ \
671c9233655SEduard Zingerman w1 += 1; \
672c9233655SEduard Zingerman /* check ALU32 op zero extends 64bit bounds */ \
673c9233655SEduard Zingerman if r1 > r2 goto l0_%=; \
674c9233655SEduard Zingerman goto l1_%=; \
675c9233655SEduard Zingerman l0_%=: /* invalid ldx if bounds are lost above */ \
676c9233655SEduard Zingerman r0 = *(u64*)(r0 - 1); \
677c9233655SEduard Zingerman l1_%=: exit; \
678c9233655SEduard Zingerman " ::: __clobber_all);
679c9233655SEduard Zingerman }
680c9233655SEduard Zingerman
681c9233655SEduard Zingerman SEC("tc")
682c9233655SEduard Zingerman __description("assigning 32bit bounds to 64bit for wA = 0, wB = wA")
__flag(BPF_F_ANY_ALIGNMENT)683c9233655SEduard Zingerman __success __retval(0) __flag(BPF_F_ANY_ALIGNMENT)
684c9233655SEduard Zingerman __naked void for_wa_0_wb_wa(void)
685c9233655SEduard Zingerman {
686c9233655SEduard Zingerman asm volatile (" \
687c9233655SEduard Zingerman r8 = *(u32*)(r1 + %[__sk_buff_data_end]); \
688c9233655SEduard Zingerman r7 = *(u32*)(r1 + %[__sk_buff_data]); \
689c9233655SEduard Zingerman w9 = 0; \
690c9233655SEduard Zingerman w2 = w9; \
691c9233655SEduard Zingerman r6 = r7; \
692c9233655SEduard Zingerman r6 += r2; \
693c9233655SEduard Zingerman r3 = r6; \
694c9233655SEduard Zingerman r3 += 8; \
695c9233655SEduard Zingerman if r3 > r8 goto l0_%=; \
696c9233655SEduard Zingerman r5 = *(u32*)(r6 + 0); \
697c9233655SEduard Zingerman l0_%=: r0 = 0; \
698c9233655SEduard Zingerman exit; \
699c9233655SEduard Zingerman " :
700c9233655SEduard Zingerman : __imm_const(__sk_buff_data, offsetof(struct __sk_buff, data)),
701c9233655SEduard Zingerman __imm_const(__sk_buff_data_end, offsetof(struct __sk_buff, data_end))
702c9233655SEduard Zingerman : __clobber_all);
703c9233655SEduard Zingerman }
704c9233655SEduard Zingerman
705c9233655SEduard Zingerman SEC("socket")
706c9233655SEduard Zingerman __description("bounds check for reg = 0, reg xor 1")
707d6f1c85fSLuis Gerhorst __success __success_unpriv
708c9233655SEduard Zingerman __retval(0)
709d6f1c85fSLuis Gerhorst #ifdef SPEC_V1
710d6f1c85fSLuis Gerhorst __xlated_unpriv("if r1 != 0x0 goto pc+2")
711d6f1c85fSLuis Gerhorst __xlated_unpriv("nospec") /* inserted to prevent `R0 min value is outside of the allowed memory range` */
712d6f1c85fSLuis Gerhorst __xlated_unpriv("goto pc-1") /* sanitized dead code */
713d6f1c85fSLuis Gerhorst __xlated_unpriv("r0 = 0")
714d6f1c85fSLuis Gerhorst #endif
reg_0_reg_xor_1(void)715c9233655SEduard Zingerman __naked void reg_0_reg_xor_1(void)
716c9233655SEduard Zingerman {
717c9233655SEduard Zingerman asm volatile (" \
718c9233655SEduard Zingerman r1 = 0; \
719c9233655SEduard Zingerman *(u64*)(r10 - 8) = r1; \
720c9233655SEduard Zingerman r2 = r10; \
721c9233655SEduard Zingerman r2 += -8; \
722c9233655SEduard Zingerman r1 = %[map_hash_8b] ll; \
723c9233655SEduard Zingerman call %[bpf_map_lookup_elem]; \
724c9233655SEduard Zingerman if r0 != 0 goto l0_%=; \
725c9233655SEduard Zingerman exit; \
726c9233655SEduard Zingerman l0_%=: r1 = 0; \
727c9233655SEduard Zingerman r1 ^= 1; \
728c9233655SEduard Zingerman if r1 != 0 goto l1_%=; \
729c9233655SEduard Zingerman r0 = *(u64*)(r0 + 8); \
730c9233655SEduard Zingerman l1_%=: r0 = 0; \
731c9233655SEduard Zingerman exit; \
732c9233655SEduard Zingerman " :
733c9233655SEduard Zingerman : __imm(bpf_map_lookup_elem),
734c9233655SEduard Zingerman __imm_addr(map_hash_8b)
735c9233655SEduard Zingerman : __clobber_all);
736c9233655SEduard Zingerman }
737c9233655SEduard Zingerman
738c9233655SEduard Zingerman SEC("socket")
739c9233655SEduard Zingerman __description("bounds check for reg32 = 0, reg32 xor 1")
740d6f1c85fSLuis Gerhorst __success __success_unpriv
741c9233655SEduard Zingerman __retval(0)
742d6f1c85fSLuis Gerhorst #ifdef SPEC_V1
743d6f1c85fSLuis Gerhorst __xlated_unpriv("if w1 != 0x0 goto pc+2")
744d6f1c85fSLuis Gerhorst __xlated_unpriv("nospec") /* inserted to prevent `R0 min value is outside of the allowed memory range` */
745d6f1c85fSLuis Gerhorst __xlated_unpriv("goto pc-1") /* sanitized dead code */
746d6f1c85fSLuis Gerhorst __xlated_unpriv("r0 = 0")
747d6f1c85fSLuis Gerhorst #endif
reg32_0_reg32_xor_1(void)748c9233655SEduard Zingerman __naked void reg32_0_reg32_xor_1(void)
749c9233655SEduard Zingerman {
750c9233655SEduard Zingerman asm volatile (" \
751c9233655SEduard Zingerman r1 = 0; \
752c9233655SEduard Zingerman *(u64*)(r10 - 8) = r1; \
753c9233655SEduard Zingerman r2 = r10; \
754c9233655SEduard Zingerman r2 += -8; \
755c9233655SEduard Zingerman r1 = %[map_hash_8b] ll; \
756c9233655SEduard Zingerman call %[bpf_map_lookup_elem]; \
757c9233655SEduard Zingerman if r0 != 0 goto l0_%=; \
758c9233655SEduard Zingerman exit; \
759c9233655SEduard Zingerman l0_%=: w1 = 0; \
760c9233655SEduard Zingerman w1 ^= 1; \
761c9233655SEduard Zingerman if w1 != 0 goto l1_%=; \
762c9233655SEduard Zingerman r0 = *(u64*)(r0 + 8); \
763c9233655SEduard Zingerman l1_%=: r0 = 0; \
764c9233655SEduard Zingerman exit; \
765c9233655SEduard Zingerman " :
766c9233655SEduard Zingerman : __imm(bpf_map_lookup_elem),
767c9233655SEduard Zingerman __imm_addr(map_hash_8b)
768c9233655SEduard Zingerman : __clobber_all);
769c9233655SEduard Zingerman }
770c9233655SEduard Zingerman
771c9233655SEduard Zingerman SEC("socket")
772c9233655SEduard Zingerman __description("bounds check for reg = 2, reg xor 3")
773d6f1c85fSLuis Gerhorst __success __success_unpriv
774c9233655SEduard Zingerman __retval(0)
775d6f1c85fSLuis Gerhorst #ifdef SPEC_V1
776d6f1c85fSLuis Gerhorst __xlated_unpriv("if r1 > 0x0 goto pc+2")
777d6f1c85fSLuis Gerhorst __xlated_unpriv("nospec") /* inserted to prevent `R0 min value is outside of the allowed memory range` */
778d6f1c85fSLuis Gerhorst __xlated_unpriv("goto pc-1") /* sanitized dead code */
779d6f1c85fSLuis Gerhorst __xlated_unpriv("r0 = 0")
780d6f1c85fSLuis Gerhorst #endif
reg_2_reg_xor_3(void)781c9233655SEduard Zingerman __naked void reg_2_reg_xor_3(void)
782c9233655SEduard Zingerman {
783c9233655SEduard Zingerman asm volatile (" \
784c9233655SEduard Zingerman r1 = 0; \
785c9233655SEduard Zingerman *(u64*)(r10 - 8) = r1; \
786c9233655SEduard Zingerman r2 = r10; \
787c9233655SEduard Zingerman r2 += -8; \
788c9233655SEduard Zingerman r1 = %[map_hash_8b] ll; \
789c9233655SEduard Zingerman call %[bpf_map_lookup_elem]; \
790c9233655SEduard Zingerman if r0 != 0 goto l0_%=; \
791c9233655SEduard Zingerman exit; \
792c9233655SEduard Zingerman l0_%=: r1 = 2; \
793c9233655SEduard Zingerman r1 ^= 3; \
794c9233655SEduard Zingerman if r1 > 0 goto l1_%=; \
795c9233655SEduard Zingerman r0 = *(u64*)(r0 + 8); \
796c9233655SEduard Zingerman l1_%=: r0 = 0; \
797c9233655SEduard Zingerman exit; \
798c9233655SEduard Zingerman " :
799c9233655SEduard Zingerman : __imm(bpf_map_lookup_elem),
800c9233655SEduard Zingerman __imm_addr(map_hash_8b)
801c9233655SEduard Zingerman : __clobber_all);
802c9233655SEduard Zingerman }
803c9233655SEduard Zingerman
804c9233655SEduard Zingerman SEC("socket")
805c9233655SEduard Zingerman __description("bounds check for reg = any, reg xor 3")
806c9233655SEduard Zingerman __failure __msg("invalid access to map value")
807c9233655SEduard Zingerman __msg_unpriv("invalid access to map value")
reg_any_reg_xor_3(void)808c9233655SEduard Zingerman __naked void reg_any_reg_xor_3(void)
809c9233655SEduard Zingerman {
810c9233655SEduard Zingerman asm volatile (" \
811c9233655SEduard Zingerman r1 = 0; \
812c9233655SEduard Zingerman *(u64*)(r10 - 8) = r1; \
813c9233655SEduard Zingerman r2 = r10; \
814c9233655SEduard Zingerman r2 += -8; \
815c9233655SEduard Zingerman r1 = %[map_hash_8b] ll; \
816c9233655SEduard Zingerman call %[bpf_map_lookup_elem]; \
817c9233655SEduard Zingerman if r0 != 0 goto l0_%=; \
818c9233655SEduard Zingerman exit; \
819c9233655SEduard Zingerman l0_%=: r1 = *(u64*)(r0 + 0); \
820c9233655SEduard Zingerman r1 ^= 3; \
821c9233655SEduard Zingerman if r1 != 0 goto l1_%=; \
822c9233655SEduard Zingerman r0 = *(u64*)(r0 + 8); \
823c9233655SEduard Zingerman l1_%=: r0 = 0; \
824c9233655SEduard Zingerman exit; \
825c9233655SEduard Zingerman " :
826c9233655SEduard Zingerman : __imm(bpf_map_lookup_elem),
827c9233655SEduard Zingerman __imm_addr(map_hash_8b)
828c9233655SEduard Zingerman : __clobber_all);
829c9233655SEduard Zingerman }
830c9233655SEduard Zingerman
831c9233655SEduard Zingerman SEC("socket")
832c9233655SEduard Zingerman __description("bounds check for reg32 = any, reg32 xor 3")
833c9233655SEduard Zingerman __failure __msg("invalid access to map value")
834c9233655SEduard Zingerman __msg_unpriv("invalid access to map value")
reg32_any_reg32_xor_3(void)835c9233655SEduard Zingerman __naked void reg32_any_reg32_xor_3(void)
836c9233655SEduard Zingerman {
837c9233655SEduard Zingerman asm volatile (" \
838c9233655SEduard Zingerman r1 = 0; \
839c9233655SEduard Zingerman *(u64*)(r10 - 8) = r1; \
840c9233655SEduard Zingerman r2 = r10; \
841c9233655SEduard Zingerman r2 += -8; \
842c9233655SEduard Zingerman r1 = %[map_hash_8b] ll; \
843c9233655SEduard Zingerman call %[bpf_map_lookup_elem]; \
844c9233655SEduard Zingerman if r0 != 0 goto l0_%=; \
845c9233655SEduard Zingerman exit; \
846c9233655SEduard Zingerman l0_%=: r1 = *(u64*)(r0 + 0); \
847c9233655SEduard Zingerman w1 ^= 3; \
848c9233655SEduard Zingerman if w1 != 0 goto l1_%=; \
849c9233655SEduard Zingerman r0 = *(u64*)(r0 + 8); \
850c9233655SEduard Zingerman l1_%=: r0 = 0; \
851c9233655SEduard Zingerman exit; \
852c9233655SEduard Zingerman " :
853c9233655SEduard Zingerman : __imm(bpf_map_lookup_elem),
854c9233655SEduard Zingerman __imm_addr(map_hash_8b)
855c9233655SEduard Zingerman : __clobber_all);
856c9233655SEduard Zingerman }
857c9233655SEduard Zingerman
858c9233655SEduard Zingerman SEC("socket")
859c9233655SEduard Zingerman __description("bounds check for reg > 0, reg xor 3")
860d6f1c85fSLuis Gerhorst __success __success_unpriv
861c9233655SEduard Zingerman __retval(0)
862d6f1c85fSLuis Gerhorst #ifdef SPEC_V1
863d6f1c85fSLuis Gerhorst __xlated_unpriv("if r1 >= 0x0 goto pc+2")
864d6f1c85fSLuis Gerhorst __xlated_unpriv("nospec") /* inserted to prevent `R0 min value is outside of the allowed memory range` */
865d6f1c85fSLuis Gerhorst __xlated_unpriv("goto pc-1") /* sanitized dead code */
866d6f1c85fSLuis Gerhorst __xlated_unpriv("r0 = 0")
867d6f1c85fSLuis Gerhorst #endif
reg_0_reg_xor_3(void)868c9233655SEduard Zingerman __naked void reg_0_reg_xor_3(void)
869c9233655SEduard Zingerman {
870c9233655SEduard Zingerman asm volatile (" \
871c9233655SEduard Zingerman r1 = 0; \
872c9233655SEduard Zingerman *(u64*)(r10 - 8) = r1; \
873c9233655SEduard Zingerman r2 = r10; \
874c9233655SEduard Zingerman r2 += -8; \
875c9233655SEduard Zingerman r1 = %[map_hash_8b] ll; \
876c9233655SEduard Zingerman call %[bpf_map_lookup_elem]; \
877c9233655SEduard Zingerman if r0 != 0 goto l0_%=; \
878c9233655SEduard Zingerman exit; \
879c9233655SEduard Zingerman l0_%=: r1 = *(u64*)(r0 + 0); \
880c9233655SEduard Zingerman if r1 <= 0 goto l1_%=; \
881c9233655SEduard Zingerman r1 ^= 3; \
882c9233655SEduard Zingerman if r1 >= 0 goto l1_%=; \
883c9233655SEduard Zingerman r0 = *(u64*)(r0 + 8); \
884c9233655SEduard Zingerman l1_%=: r0 = 0; \
885c9233655SEduard Zingerman exit; \
886c9233655SEduard Zingerman " :
887c9233655SEduard Zingerman : __imm(bpf_map_lookup_elem),
888c9233655SEduard Zingerman __imm_addr(map_hash_8b)
889c9233655SEduard Zingerman : __clobber_all);
890c9233655SEduard Zingerman }
891c9233655SEduard Zingerman
892c9233655SEduard Zingerman SEC("socket")
893c9233655SEduard Zingerman __description("bounds check for reg32 > 0, reg32 xor 3")
894d6f1c85fSLuis Gerhorst __success __success_unpriv
895c9233655SEduard Zingerman __retval(0)
896d6f1c85fSLuis Gerhorst #ifdef SPEC_V1
897d6f1c85fSLuis Gerhorst __xlated_unpriv("if w1 >= 0x0 goto pc+2")
898d6f1c85fSLuis Gerhorst __xlated_unpriv("nospec") /* inserted to prevent `R0 min value is outside of the allowed memory range` */
899d6f1c85fSLuis Gerhorst __xlated_unpriv("goto pc-1") /* sanitized dead code */
900d6f1c85fSLuis Gerhorst __xlated_unpriv("r0 = 0")
901d6f1c85fSLuis Gerhorst #endif
reg32_0_reg32_xor_3(void)902c9233655SEduard Zingerman __naked void reg32_0_reg32_xor_3(void)
903c9233655SEduard Zingerman {
904c9233655SEduard Zingerman asm volatile (" \
905c9233655SEduard Zingerman r1 = 0; \
906c9233655SEduard Zingerman *(u64*)(r10 - 8) = r1; \
907c9233655SEduard Zingerman r2 = r10; \
908c9233655SEduard Zingerman r2 += -8; \
909c9233655SEduard Zingerman r1 = %[map_hash_8b] ll; \
910c9233655SEduard Zingerman call %[bpf_map_lookup_elem]; \
911c9233655SEduard Zingerman if r0 != 0 goto l0_%=; \
912c9233655SEduard Zingerman exit; \
913c9233655SEduard Zingerman l0_%=: r1 = *(u64*)(r0 + 0); \
914c9233655SEduard Zingerman if w1 <= 0 goto l1_%=; \
915c9233655SEduard Zingerman w1 ^= 3; \
916c9233655SEduard Zingerman if w1 >= 0 goto l1_%=; \
917c9233655SEduard Zingerman r0 = *(u64*)(r0 + 8); \
918c9233655SEduard Zingerman l1_%=: r0 = 0; \
919c9233655SEduard Zingerman exit; \
920c9233655SEduard Zingerman " :
921c9233655SEduard Zingerman : __imm(bpf_map_lookup_elem),
922c9233655SEduard Zingerman __imm_addr(map_hash_8b)
923c9233655SEduard Zingerman : __clobber_all);
924c9233655SEduard Zingerman }
925c9233655SEduard Zingerman
926c9233655SEduard Zingerman SEC("socket")
9275ec9a7d1SCupertino Miranda __description("bounds check for non const xor src dst")
9285ec9a7d1SCupertino Miranda __success __log_level(2)
9295ec9a7d1SCupertino Miranda __msg("5: (af) r0 ^= r6 ; R0_w=scalar(smin=smin32=0,smax=umax=smax32=umax32=431,var_off=(0x0; 0x1af))")
non_const_xor_src_dst(void)9305ec9a7d1SCupertino Miranda __naked void non_const_xor_src_dst(void)
9315ec9a7d1SCupertino Miranda {
9325ec9a7d1SCupertino Miranda asm volatile (" \
9335ec9a7d1SCupertino Miranda call %[bpf_get_prandom_u32]; \
9345ec9a7d1SCupertino Miranda r6 = r0; \
9355ec9a7d1SCupertino Miranda call %[bpf_get_prandom_u32]; \
9365ec9a7d1SCupertino Miranda r6 &= 0xaf; \
9375ec9a7d1SCupertino Miranda r0 &= 0x1a0; \
9385ec9a7d1SCupertino Miranda r0 ^= r6; \
9395ec9a7d1SCupertino Miranda exit; \
9405ec9a7d1SCupertino Miranda " :
9415ec9a7d1SCupertino Miranda : __imm(bpf_map_lookup_elem),
9425ec9a7d1SCupertino Miranda __imm_addr(map_hash_8b),
9435ec9a7d1SCupertino Miranda __imm(bpf_get_prandom_u32)
9445ec9a7d1SCupertino Miranda : __clobber_all);
9455ec9a7d1SCupertino Miranda }
9465ec9a7d1SCupertino Miranda
9475ec9a7d1SCupertino Miranda SEC("socket")
9485ec9a7d1SCupertino Miranda __description("bounds check for non const or src dst")
9495ec9a7d1SCupertino Miranda __success __log_level(2)
9505ec9a7d1SCupertino Miranda __msg("5: (4f) r0 |= r6 ; R0_w=scalar(smin=smin32=0,smax=umax=smax32=umax32=431,var_off=(0x0; 0x1af))")
non_const_or_src_dst(void)9515ec9a7d1SCupertino Miranda __naked void non_const_or_src_dst(void)
9525ec9a7d1SCupertino Miranda {
9535ec9a7d1SCupertino Miranda asm volatile (" \
9545ec9a7d1SCupertino Miranda call %[bpf_get_prandom_u32]; \
9555ec9a7d1SCupertino Miranda r6 = r0; \
9565ec9a7d1SCupertino Miranda call %[bpf_get_prandom_u32]; \
9575ec9a7d1SCupertino Miranda r6 &= 0xaf; \
9585ec9a7d1SCupertino Miranda r0 &= 0x1a0; \
9595ec9a7d1SCupertino Miranda r0 |= r6; \
9605ec9a7d1SCupertino Miranda exit; \
9615ec9a7d1SCupertino Miranda " :
9625ec9a7d1SCupertino Miranda : __imm(bpf_map_lookup_elem),
9635ec9a7d1SCupertino Miranda __imm_addr(map_hash_8b),
9645ec9a7d1SCupertino Miranda __imm(bpf_get_prandom_u32)
9655ec9a7d1SCupertino Miranda : __clobber_all);
9665ec9a7d1SCupertino Miranda }
9675ec9a7d1SCupertino Miranda
9685ec9a7d1SCupertino Miranda SEC("socket")
96992956786SCupertino Miranda __description("bounds check for non const mul regs")
97092956786SCupertino Miranda __success __log_level(2)
97192956786SCupertino Miranda __msg("5: (2f) r0 *= r6 ; R0_w=scalar(smin=smin32=0,smax=umax=smax32=umax32=3825,var_off=(0x0; 0xfff))")
non_const_mul_regs(void)97292956786SCupertino Miranda __naked void non_const_mul_regs(void)
97392956786SCupertino Miranda {
97492956786SCupertino Miranda asm volatile (" \
97592956786SCupertino Miranda call %[bpf_get_prandom_u32]; \
97692956786SCupertino Miranda r6 = r0; \
97792956786SCupertino Miranda call %[bpf_get_prandom_u32]; \
97892956786SCupertino Miranda r6 &= 0xff; \
97992956786SCupertino Miranda r0 &= 0x0f; \
98092956786SCupertino Miranda r0 *= r6; \
98192956786SCupertino Miranda exit; \
98292956786SCupertino Miranda " :
98392956786SCupertino Miranda : __imm(bpf_map_lookup_elem),
98492956786SCupertino Miranda __imm_addr(map_hash_8b),
98592956786SCupertino Miranda __imm(bpf_get_prandom_u32)
98692956786SCupertino Miranda : __clobber_all);
98792956786SCupertino Miranda }
98892956786SCupertino Miranda
98992956786SCupertino Miranda SEC("socket")
990c9233655SEduard Zingerman __description("bounds checks after 32-bit truncation. test 1")
991c9233655SEduard Zingerman __success __failure_unpriv __msg_unpriv("R0 leaks addr")
992c9233655SEduard Zingerman __retval(0)
_32_bit_truncation_test_1(void)993c9233655SEduard Zingerman __naked void _32_bit_truncation_test_1(void)
994c9233655SEduard Zingerman {
995c9233655SEduard Zingerman asm volatile (" \
996c9233655SEduard Zingerman r1 = 0; \
997c9233655SEduard Zingerman *(u64*)(r10 - 8) = r1; \
998c9233655SEduard Zingerman r2 = r10; \
999c9233655SEduard Zingerman r2 += -8; \
1000c9233655SEduard Zingerman r1 = %[map_hash_8b] ll; \
1001c9233655SEduard Zingerman call %[bpf_map_lookup_elem]; \
1002c9233655SEduard Zingerman if r0 == 0 goto l0_%=; \
1003c9233655SEduard Zingerman r1 = *(u32*)(r0 + 0); \
1004c9233655SEduard Zingerman /* This used to reduce the max bound to 0x7fffffff */\
1005c9233655SEduard Zingerman if r1 == 0 goto l1_%=; \
1006c9233655SEduard Zingerman if r1 > 0x7fffffff goto l0_%=; \
1007c9233655SEduard Zingerman l1_%=: r0 = 0; \
1008c9233655SEduard Zingerman l0_%=: exit; \
1009c9233655SEduard Zingerman " :
1010c9233655SEduard Zingerman : __imm(bpf_map_lookup_elem),
1011c9233655SEduard Zingerman __imm_addr(map_hash_8b)
1012c9233655SEduard Zingerman : __clobber_all);
1013c9233655SEduard Zingerman }
1014c9233655SEduard Zingerman
1015c9233655SEduard Zingerman SEC("socket")
1016c9233655SEduard Zingerman __description("bounds checks after 32-bit truncation. test 2")
1017c9233655SEduard Zingerman __success __failure_unpriv __msg_unpriv("R0 leaks addr")
1018c9233655SEduard Zingerman __retval(0)
_32_bit_truncation_test_2(void)1019c9233655SEduard Zingerman __naked void _32_bit_truncation_test_2(void)
1020c9233655SEduard Zingerman {
1021c9233655SEduard Zingerman asm volatile (" \
1022c9233655SEduard Zingerman r1 = 0; \
1023c9233655SEduard Zingerman *(u64*)(r10 - 8) = r1; \
1024c9233655SEduard Zingerman r2 = r10; \
1025c9233655SEduard Zingerman r2 += -8; \
1026c9233655SEduard Zingerman r1 = %[map_hash_8b] ll; \
1027c9233655SEduard Zingerman call %[bpf_map_lookup_elem]; \
1028c9233655SEduard Zingerman if r0 == 0 goto l0_%=; \
1029c9233655SEduard Zingerman r1 = *(u32*)(r0 + 0); \
1030c9233655SEduard Zingerman if r1 s< 1 goto l1_%=; \
1031c9233655SEduard Zingerman if w1 s< 0 goto l0_%=; \
1032c9233655SEduard Zingerman l1_%=: r0 = 0; \
1033c9233655SEduard Zingerman l0_%=: exit; \
1034c9233655SEduard Zingerman " :
1035c9233655SEduard Zingerman : __imm(bpf_map_lookup_elem),
1036c9233655SEduard Zingerman __imm_addr(map_hash_8b)
1037c9233655SEduard Zingerman : __clobber_all);
1038c9233655SEduard Zingerman }
1039c9233655SEduard Zingerman
1040c9233655SEduard Zingerman SEC("xdp")
1041c9233655SEduard Zingerman __description("bound check with JMP_JLT for crossing 64-bit signed boundary")
1042c9233655SEduard Zingerman __success __retval(0)
crossing_64_bit_signed_boundary_1(void)1043c9233655SEduard Zingerman __naked void crossing_64_bit_signed_boundary_1(void)
1044c9233655SEduard Zingerman {
1045c9233655SEduard Zingerman asm volatile (" \
1046c9233655SEduard Zingerman r2 = *(u32*)(r1 + %[xdp_md_data]); \
1047c9233655SEduard Zingerman r3 = *(u32*)(r1 + %[xdp_md_data_end]); \
1048c9233655SEduard Zingerman r1 = r2; \
1049c9233655SEduard Zingerman r1 += 1; \
1050c9233655SEduard Zingerman if r1 > r3 goto l0_%=; \
1051c9233655SEduard Zingerman r1 = *(u8*)(r2 + 0); \
1052c9233655SEduard Zingerman r0 = 0x7fffffffffffff10 ll; \
1053c9233655SEduard Zingerman r1 += r0; \
1054c9233655SEduard Zingerman r0 = 0x8000000000000000 ll; \
1055c9233655SEduard Zingerman l1_%=: r0 += 1; \
1056c9233655SEduard Zingerman /* r1 unsigned range is [0x7fffffffffffff10, 0x800000000000000f] */\
1057c9233655SEduard Zingerman if r0 < r1 goto l1_%=; \
1058c9233655SEduard Zingerman l0_%=: r0 = 0; \
1059c9233655SEduard Zingerman exit; \
1060c9233655SEduard Zingerman " :
1061c9233655SEduard Zingerman : __imm_const(xdp_md_data, offsetof(struct xdp_md, data)),
1062c9233655SEduard Zingerman __imm_const(xdp_md_data_end, offsetof(struct xdp_md, data_end))
1063c9233655SEduard Zingerman : __clobber_all);
1064c9233655SEduard Zingerman }
1065c9233655SEduard Zingerman
1066c9233655SEduard Zingerman SEC("xdp")
1067c9233655SEduard Zingerman __description("bound check with JMP_JSLT for crossing 64-bit signed boundary")
1068c9233655SEduard Zingerman __success __retval(0)
__flag(BPF_F_TEST_REG_INVARIANTS)1069f96841bbSPaul Chaignon __flag(BPF_F_TEST_REG_INVARIANTS)
1070c9233655SEduard Zingerman __naked void crossing_64_bit_signed_boundary_2(void)
1071c9233655SEduard Zingerman {
1072c9233655SEduard Zingerman asm volatile (" \
1073c9233655SEduard Zingerman r2 = *(u32*)(r1 + %[xdp_md_data]); \
1074c9233655SEduard Zingerman r3 = *(u32*)(r1 + %[xdp_md_data_end]); \
1075c9233655SEduard Zingerman r1 = r2; \
1076c9233655SEduard Zingerman r1 += 1; \
1077c9233655SEduard Zingerman if r1 > r3 goto l0_%=; \
1078c9233655SEduard Zingerman r1 = *(u8*)(r2 + 0); \
1079c9233655SEduard Zingerman r0 = 0x7fffffffffffff10 ll; \
1080c9233655SEduard Zingerman r1 += r0; \
1081c9233655SEduard Zingerman r2 = 0x8000000000000fff ll; \
1082c9233655SEduard Zingerman r0 = 0x8000000000000000 ll; \
1083c9233655SEduard Zingerman l1_%=: r0 += 1; \
1084c9233655SEduard Zingerman if r0 s> r2 goto l0_%=; \
1085c9233655SEduard Zingerman /* r1 signed range is [S64_MIN, S64_MAX] */ \
1086c9233655SEduard Zingerman if r0 s< r1 goto l1_%=; \
1087c9233655SEduard Zingerman r0 = 1; \
1088c9233655SEduard Zingerman exit; \
1089c9233655SEduard Zingerman l0_%=: r0 = 0; \
1090c9233655SEduard Zingerman exit; \
1091c9233655SEduard Zingerman " :
1092c9233655SEduard Zingerman : __imm_const(xdp_md_data, offsetof(struct xdp_md, data)),
1093c9233655SEduard Zingerman __imm_const(xdp_md_data_end, offsetof(struct xdp_md, data_end))
1094c9233655SEduard Zingerman : __clobber_all);
1095c9233655SEduard Zingerman }
1096c9233655SEduard Zingerman
1097c9233655SEduard Zingerman SEC("xdp")
1098c9233655SEduard Zingerman __description("bound check for loop upper bound greater than U32_MAX")
1099c9233655SEduard Zingerman __success __retval(0)
bound_greater_than_u32_max(void)1100c9233655SEduard Zingerman __naked void bound_greater_than_u32_max(void)
1101c9233655SEduard Zingerman {
1102c9233655SEduard Zingerman asm volatile (" \
1103c9233655SEduard Zingerman r2 = *(u32*)(r1 + %[xdp_md_data]); \
1104c9233655SEduard Zingerman r3 = *(u32*)(r1 + %[xdp_md_data_end]); \
1105c9233655SEduard Zingerman r1 = r2; \
1106c9233655SEduard Zingerman r1 += 1; \
1107c9233655SEduard Zingerman if r1 > r3 goto l0_%=; \
1108c9233655SEduard Zingerman r1 = *(u8*)(r2 + 0); \
1109c9233655SEduard Zingerman r0 = 0x100000000 ll; \
1110c9233655SEduard Zingerman r1 += r0; \
1111c9233655SEduard Zingerman r0 = 0x100000000 ll; \
1112c9233655SEduard Zingerman l1_%=: r0 += 1; \
1113c9233655SEduard Zingerman if r0 < r1 goto l1_%=; \
1114c9233655SEduard Zingerman l0_%=: r0 = 0; \
1115c9233655SEduard Zingerman exit; \
1116c9233655SEduard Zingerman " :
1117c9233655SEduard Zingerman : __imm_const(xdp_md_data, offsetof(struct xdp_md, data)),
1118c9233655SEduard Zingerman __imm_const(xdp_md_data_end, offsetof(struct xdp_md, data_end))
1119c9233655SEduard Zingerman : __clobber_all);
1120c9233655SEduard Zingerman }
1121c9233655SEduard Zingerman
1122c9233655SEduard Zingerman SEC("xdp")
1123c9233655SEduard Zingerman __description("bound check with JMP32_JLT for crossing 32-bit signed boundary")
1124c9233655SEduard Zingerman __success __retval(0)
crossing_32_bit_signed_boundary_1(void)1125c9233655SEduard Zingerman __naked void crossing_32_bit_signed_boundary_1(void)
1126c9233655SEduard Zingerman {
1127c9233655SEduard Zingerman asm volatile (" \
1128c9233655SEduard Zingerman r2 = *(u32*)(r1 + %[xdp_md_data]); \
1129c9233655SEduard Zingerman r3 = *(u32*)(r1 + %[xdp_md_data_end]); \
1130c9233655SEduard Zingerman r1 = r2; \
1131c9233655SEduard Zingerman r1 += 1; \
1132c9233655SEduard Zingerman if r1 > r3 goto l0_%=; \
1133c9233655SEduard Zingerman r1 = *(u8*)(r2 + 0); \
1134c9233655SEduard Zingerman w0 = 0x7fffff10; \
1135c9233655SEduard Zingerman w1 += w0; \
1136c9233655SEduard Zingerman w0 = 0x80000000; \
1137c9233655SEduard Zingerman l1_%=: w0 += 1; \
1138c9233655SEduard Zingerman /* r1 unsigned range is [0, 0x8000000f] */ \
1139c9233655SEduard Zingerman if w0 < w1 goto l1_%=; \
1140c9233655SEduard Zingerman l0_%=: r0 = 0; \
1141c9233655SEduard Zingerman exit; \
1142c9233655SEduard Zingerman " :
1143c9233655SEduard Zingerman : __imm_const(xdp_md_data, offsetof(struct xdp_md, data)),
1144c9233655SEduard Zingerman __imm_const(xdp_md_data_end, offsetof(struct xdp_md, data_end))
1145c9233655SEduard Zingerman : __clobber_all);
1146c9233655SEduard Zingerman }
1147c9233655SEduard Zingerman
1148c9233655SEduard Zingerman SEC("xdp")
1149c9233655SEduard Zingerman __description("bound check with JMP32_JSLT for crossing 32-bit signed boundary")
1150c9233655SEduard Zingerman __success __retval(0)
1151ff8867afSAndrii Nakryiko __flag(!BPF_F_TEST_REG_INVARIANTS) /* known invariants violation */
crossing_32_bit_signed_boundary_2(void)1152c9233655SEduard Zingerman __naked void crossing_32_bit_signed_boundary_2(void)
1153c9233655SEduard Zingerman {
1154c9233655SEduard Zingerman asm volatile (" \
1155c9233655SEduard Zingerman r2 = *(u32*)(r1 + %[xdp_md_data]); \
1156c9233655SEduard Zingerman r3 = *(u32*)(r1 + %[xdp_md_data_end]); \
1157c9233655SEduard Zingerman r1 = r2; \
1158c9233655SEduard Zingerman r1 += 1; \
1159c9233655SEduard Zingerman if r1 > r3 goto l0_%=; \
1160c9233655SEduard Zingerman r1 = *(u8*)(r2 + 0); \
1161c9233655SEduard Zingerman w0 = 0x7fffff10; \
1162c9233655SEduard Zingerman w1 += w0; \
1163c9233655SEduard Zingerman w2 = 0x80000fff; \
1164c9233655SEduard Zingerman w0 = 0x80000000; \
1165c9233655SEduard Zingerman l1_%=: w0 += 1; \
1166c9233655SEduard Zingerman if w0 s> w2 goto l0_%=; \
1167c9233655SEduard Zingerman /* r1 signed range is [S32_MIN, S32_MAX] */ \
1168c9233655SEduard Zingerman if w0 s< w1 goto l1_%=; \
1169c9233655SEduard Zingerman r0 = 1; \
1170c9233655SEduard Zingerman exit; \
1171c9233655SEduard Zingerman l0_%=: r0 = 0; \
1172c9233655SEduard Zingerman exit; \
1173c9233655SEduard Zingerman " :
1174c9233655SEduard Zingerman : __imm_const(xdp_md_data, offsetof(struct xdp_md, data)),
1175c9233655SEduard Zingerman __imm_const(xdp_md_data_end, offsetof(struct xdp_md, data_end))
1176c9233655SEduard Zingerman : __clobber_all);
1177c9233655SEduard Zingerman }
1178c9233655SEduard Zingerman
1179463ea64eSMenglong Dong SEC("tc")
1180463ea64eSMenglong Dong __description("bounds check with JMP_NE for reg edge")
1181463ea64eSMenglong Dong __success __retval(0)
reg_not_equal_const(void)1182463ea64eSMenglong Dong __naked void reg_not_equal_const(void)
1183463ea64eSMenglong Dong {
1184463ea64eSMenglong Dong asm volatile (" \
1185463ea64eSMenglong Dong r6 = r1; \
1186463ea64eSMenglong Dong r1 = 0; \
1187463ea64eSMenglong Dong *(u64*)(r10 - 8) = r1; \
1188463ea64eSMenglong Dong call %[bpf_get_prandom_u32]; \
1189463ea64eSMenglong Dong r4 = r0; \
1190463ea64eSMenglong Dong r4 &= 7; \
1191463ea64eSMenglong Dong if r4 != 0 goto l0_%=; \
1192463ea64eSMenglong Dong r0 = 0; \
1193463ea64eSMenglong Dong exit; \
1194463ea64eSMenglong Dong l0_%=: r1 = r6; \
1195463ea64eSMenglong Dong r2 = 0; \
1196463ea64eSMenglong Dong r3 = r10; \
1197463ea64eSMenglong Dong r3 += -8; \
1198463ea64eSMenglong Dong r5 = 0; \
1199463ea64eSMenglong Dong /* The 4th argument of bpf_skb_store_bytes is defined as \
1200463ea64eSMenglong Dong * ARG_CONST_SIZE, so 0 is not allowed. The 'r4 != 0' \
1201463ea64eSMenglong Dong * is providing us this exclusion of zero from initial \
1202463ea64eSMenglong Dong * [0, 7] range. \
1203463ea64eSMenglong Dong */ \
1204463ea64eSMenglong Dong call %[bpf_skb_store_bytes]; \
1205463ea64eSMenglong Dong r0 = 0; \
1206463ea64eSMenglong Dong exit; \
1207463ea64eSMenglong Dong " :
1208463ea64eSMenglong Dong : __imm(bpf_get_prandom_u32),
1209463ea64eSMenglong Dong __imm(bpf_skb_store_bytes)
1210463ea64eSMenglong Dong : __clobber_all);
1211463ea64eSMenglong Dong }
1212463ea64eSMenglong Dong
1213463ea64eSMenglong Dong SEC("tc")
1214463ea64eSMenglong Dong __description("bounds check with JMP_EQ for reg edge")
1215463ea64eSMenglong Dong __success __retval(0)
reg_equal_const(void)1216463ea64eSMenglong Dong __naked void reg_equal_const(void)
1217463ea64eSMenglong Dong {
1218463ea64eSMenglong Dong asm volatile (" \
1219463ea64eSMenglong Dong r6 = r1; \
1220463ea64eSMenglong Dong r1 = 0; \
1221463ea64eSMenglong Dong *(u64*)(r10 - 8) = r1; \
1222463ea64eSMenglong Dong call %[bpf_get_prandom_u32]; \
1223463ea64eSMenglong Dong r4 = r0; \
1224463ea64eSMenglong Dong r4 &= 7; \
1225463ea64eSMenglong Dong if r4 == 0 goto l0_%=; \
1226463ea64eSMenglong Dong r1 = r6; \
1227463ea64eSMenglong Dong r2 = 0; \
1228463ea64eSMenglong Dong r3 = r10; \
1229463ea64eSMenglong Dong r3 += -8; \
1230463ea64eSMenglong Dong r5 = 0; \
1231463ea64eSMenglong Dong /* Just the same as what we do in reg_not_equal_const() */ \
1232463ea64eSMenglong Dong call %[bpf_skb_store_bytes]; \
1233463ea64eSMenglong Dong l0_%=: r0 = 0; \
1234463ea64eSMenglong Dong exit; \
1235463ea64eSMenglong Dong " :
1236463ea64eSMenglong Dong : __imm(bpf_get_prandom_u32),
1237463ea64eSMenglong Dong __imm(bpf_skb_store_bytes)
1238463ea64eSMenglong Dong : __clobber_all);
1239463ea64eSMenglong Dong }
1240463ea64eSMenglong Dong
124175137d9eSMatan Shachnai SEC("tc")
124275137d9eSMatan Shachnai __description("multiply mixed sign bounds. test 1")
124375137d9eSMatan Shachnai __success __log_level(2)
124475137d9eSMatan Shachnai __msg("r6 *= r7 {{.*}}; R6_w=scalar(smin=umin=0x1bc16d5cd4927ee1,smax=umax=0x1bc16d674ec80000,smax32=0x7ffffeff,umax32=0xfffffeff,var_off=(0x1bc16d4000000000; 0x3ffffffeff))")
mult_mixed0_sign(void)124575137d9eSMatan Shachnai __naked void mult_mixed0_sign(void)
124675137d9eSMatan Shachnai {
124775137d9eSMatan Shachnai asm volatile (
124875137d9eSMatan Shachnai "call %[bpf_get_prandom_u32];"
124975137d9eSMatan Shachnai "r6 = r0;"
125075137d9eSMatan Shachnai "call %[bpf_get_prandom_u32];"
125175137d9eSMatan Shachnai "r7 = r0;"
125275137d9eSMatan Shachnai "r6 &= 0xf;"
125375137d9eSMatan Shachnai "r6 -= 1000000000;"
125475137d9eSMatan Shachnai "r7 &= 0xf;"
125575137d9eSMatan Shachnai "r7 -= 2000000000;"
125675137d9eSMatan Shachnai "r6 *= r7;"
125775137d9eSMatan Shachnai "exit"
125875137d9eSMatan Shachnai :
125975137d9eSMatan Shachnai : __imm(bpf_get_prandom_u32),
126075137d9eSMatan Shachnai __imm(bpf_skb_store_bytes)
126175137d9eSMatan Shachnai : __clobber_all);
126275137d9eSMatan Shachnai }
126375137d9eSMatan Shachnai
126475137d9eSMatan Shachnai SEC("tc")
126575137d9eSMatan Shachnai __description("multiply mixed sign bounds. test 2")
126675137d9eSMatan Shachnai __success __log_level(2)
126775137d9eSMatan Shachnai __msg("r6 *= r7 {{.*}}; R6_w=scalar(smin=smin32=-100,smax=smax32=200)")
mult_mixed1_sign(void)126875137d9eSMatan Shachnai __naked void mult_mixed1_sign(void)
126975137d9eSMatan Shachnai {
127075137d9eSMatan Shachnai asm volatile (
127175137d9eSMatan Shachnai "call %[bpf_get_prandom_u32];"
127275137d9eSMatan Shachnai "r6 = r0;"
127375137d9eSMatan Shachnai "call %[bpf_get_prandom_u32];"
127475137d9eSMatan Shachnai "r7 = r0;"
127575137d9eSMatan Shachnai "r6 &= 0xf;"
127675137d9eSMatan Shachnai "r6 -= 0xa;"
127775137d9eSMatan Shachnai "r7 &= 0xf;"
127875137d9eSMatan Shachnai "r7 -= 0x14;"
127975137d9eSMatan Shachnai "r6 *= r7;"
128075137d9eSMatan Shachnai "exit"
128175137d9eSMatan Shachnai :
128275137d9eSMatan Shachnai : __imm(bpf_get_prandom_u32),
128375137d9eSMatan Shachnai __imm(bpf_skb_store_bytes)
128475137d9eSMatan Shachnai : __clobber_all);
128575137d9eSMatan Shachnai }
128675137d9eSMatan Shachnai
128775137d9eSMatan Shachnai SEC("tc")
128875137d9eSMatan Shachnai __description("multiply negative bounds")
128975137d9eSMatan Shachnai __success __log_level(2)
129075137d9eSMatan Shachnai __msg("r6 *= r7 {{.*}}; R6_w=scalar(smin=umin=smin32=umin32=0x3ff280b0,smax=umax=smax32=umax32=0x3fff0001,var_off=(0x3ff00000; 0xf81ff))")
mult_sign_bounds(void)129175137d9eSMatan Shachnai __naked void mult_sign_bounds(void)
129275137d9eSMatan Shachnai {
129375137d9eSMatan Shachnai asm volatile (
129475137d9eSMatan Shachnai "r8 = 0x7fff;"
129575137d9eSMatan Shachnai "call %[bpf_get_prandom_u32];"
129675137d9eSMatan Shachnai "r6 = r0;"
129775137d9eSMatan Shachnai "call %[bpf_get_prandom_u32];"
129875137d9eSMatan Shachnai "r7 = r0;"
129975137d9eSMatan Shachnai "r6 &= 0xa;"
130075137d9eSMatan Shachnai "r6 -= r8;"
130175137d9eSMatan Shachnai "r7 &= 0xf;"
130275137d9eSMatan Shachnai "r7 -= r8;"
130375137d9eSMatan Shachnai "r6 *= r7;"
130475137d9eSMatan Shachnai "exit"
130575137d9eSMatan Shachnai :
130675137d9eSMatan Shachnai : __imm(bpf_get_prandom_u32),
130775137d9eSMatan Shachnai __imm(bpf_skb_store_bytes)
130875137d9eSMatan Shachnai : __clobber_all);
130975137d9eSMatan Shachnai }
131075137d9eSMatan Shachnai
131175137d9eSMatan Shachnai SEC("tc")
131275137d9eSMatan Shachnai __description("multiply bounds that don't cross signed boundary")
131375137d9eSMatan Shachnai __success __log_level(2)
131475137d9eSMatan Shachnai __msg("r8 *= r6 {{.*}}; R6_w=scalar(smin=smin32=0,smax=umax=smax32=umax32=11,var_off=(0x0; 0xb)) R8_w=scalar(smin=0,smax=umax=0x7b96bb0a94a3a7cd,var_off=(0x0; 0x7fffffffffffffff))")
mult_no_sign_crossing(void)131575137d9eSMatan Shachnai __naked void mult_no_sign_crossing(void)
131675137d9eSMatan Shachnai {
131775137d9eSMatan Shachnai asm volatile (
131875137d9eSMatan Shachnai "r6 = 0xb;"
131975137d9eSMatan Shachnai "r8 = 0xb3c3f8c99262687 ll;"
132075137d9eSMatan Shachnai "call %[bpf_get_prandom_u32];"
132175137d9eSMatan Shachnai "r7 = r0;"
132275137d9eSMatan Shachnai "r6 &= r7;"
132375137d9eSMatan Shachnai "r8 *= r6;"
132475137d9eSMatan Shachnai "exit"
132575137d9eSMatan Shachnai :
132675137d9eSMatan Shachnai : __imm(bpf_get_prandom_u32),
132775137d9eSMatan Shachnai __imm(bpf_skb_store_bytes)
132875137d9eSMatan Shachnai : __clobber_all);
132975137d9eSMatan Shachnai }
133075137d9eSMatan Shachnai
133175137d9eSMatan Shachnai SEC("tc")
133275137d9eSMatan Shachnai __description("multiplication overflow, result in unbounded reg. test 1")
133375137d9eSMatan Shachnai __success __log_level(2)
133475137d9eSMatan Shachnai __msg("r6 *= r7 {{.*}}; R6_w=scalar()")
mult_unsign_ovf(void)133575137d9eSMatan Shachnai __naked void mult_unsign_ovf(void)
133675137d9eSMatan Shachnai {
133775137d9eSMatan Shachnai asm volatile (
133875137d9eSMatan Shachnai "r8 = 0x7ffffffffff ll;"
133975137d9eSMatan Shachnai "call %[bpf_get_prandom_u32];"
134075137d9eSMatan Shachnai "r6 = r0;"
134175137d9eSMatan Shachnai "call %[bpf_get_prandom_u32];"
134275137d9eSMatan Shachnai "r7 = r0;"
134375137d9eSMatan Shachnai "r6 &= 0x7fffffff;"
134475137d9eSMatan Shachnai "r7 &= r8;"
134575137d9eSMatan Shachnai "r6 *= r7;"
134675137d9eSMatan Shachnai "exit"
134775137d9eSMatan Shachnai :
134875137d9eSMatan Shachnai : __imm(bpf_get_prandom_u32),
134975137d9eSMatan Shachnai __imm(bpf_skb_store_bytes)
135075137d9eSMatan Shachnai : __clobber_all);
135175137d9eSMatan Shachnai }
135275137d9eSMatan Shachnai
135375137d9eSMatan Shachnai SEC("tc")
135475137d9eSMatan Shachnai __description("multiplication overflow, result in unbounded reg. test 2")
135575137d9eSMatan Shachnai __success __log_level(2)
135675137d9eSMatan Shachnai __msg("r6 *= r7 {{.*}}; R6_w=scalar()")
mult_sign_ovf(void)135775137d9eSMatan Shachnai __naked void mult_sign_ovf(void)
135875137d9eSMatan Shachnai {
135975137d9eSMatan Shachnai asm volatile (
136075137d9eSMatan Shachnai "r8 = 0x7ffffffff ll;"
136175137d9eSMatan Shachnai "call %[bpf_get_prandom_u32];"
136275137d9eSMatan Shachnai "r6 = r0;"
136375137d9eSMatan Shachnai "call %[bpf_get_prandom_u32];"
136475137d9eSMatan Shachnai "r7 = r0;"
136575137d9eSMatan Shachnai "r6 &= 0xa;"
136675137d9eSMatan Shachnai "r6 -= r8;"
136775137d9eSMatan Shachnai "r7 &= 0x7fffffff;"
136875137d9eSMatan Shachnai "r6 *= r7;"
136975137d9eSMatan Shachnai "exit"
137075137d9eSMatan Shachnai :
137175137d9eSMatan Shachnai : __imm(bpf_get_prandom_u32),
137275137d9eSMatan Shachnai __imm(bpf_skb_store_bytes)
137375137d9eSMatan Shachnai : __clobber_all);
137475137d9eSMatan Shachnai }
1375e1d79454SHarishankar Vishwanathan
1376e1d79454SHarishankar Vishwanathan SEC("socket")
1377e1d79454SHarishankar Vishwanathan __description("64-bit addition, all outcomes overflow")
1378e1d79454SHarishankar Vishwanathan __success __log_level(2)
1379e1d79454SHarishankar Vishwanathan __msg("5: (0f) r3 += r3 {{.*}} R3_w=scalar(umin=0x4000000000000000,umax=0xfffffffffffffffe)")
1380e1d79454SHarishankar Vishwanathan __retval(0)
add64_full_overflow(void)1381e1d79454SHarishankar Vishwanathan __naked void add64_full_overflow(void)
1382e1d79454SHarishankar Vishwanathan {
1383e1d79454SHarishankar Vishwanathan asm volatile (
1384e1d79454SHarishankar Vishwanathan "call %[bpf_get_prandom_u32];"
1385e1d79454SHarishankar Vishwanathan "r4 = r0;"
1386e1d79454SHarishankar Vishwanathan "r3 = 0xa000000000000000 ll;"
1387e1d79454SHarishankar Vishwanathan "r3 |= r4;"
1388e1d79454SHarishankar Vishwanathan "r3 += r3;"
1389e1d79454SHarishankar Vishwanathan "r0 = 0;"
1390e1d79454SHarishankar Vishwanathan "exit"
1391e1d79454SHarishankar Vishwanathan :
1392e1d79454SHarishankar Vishwanathan : __imm(bpf_get_prandom_u32)
1393e1d79454SHarishankar Vishwanathan : __clobber_all);
1394e1d79454SHarishankar Vishwanathan }
1395e1d79454SHarishankar Vishwanathan
1396e1d79454SHarishankar Vishwanathan SEC("socket")
1397e1d79454SHarishankar Vishwanathan __description("64-bit addition, partial overflow, result in unbounded reg")
1398e1d79454SHarishankar Vishwanathan __success __log_level(2)
1399e1d79454SHarishankar Vishwanathan __msg("4: (0f) r3 += r3 {{.*}} R3_w=scalar()")
1400e1d79454SHarishankar Vishwanathan __retval(0)
add64_partial_overflow(void)1401e1d79454SHarishankar Vishwanathan __naked void add64_partial_overflow(void)
1402e1d79454SHarishankar Vishwanathan {
1403e1d79454SHarishankar Vishwanathan asm volatile (
1404e1d79454SHarishankar Vishwanathan "call %[bpf_get_prandom_u32];"
1405e1d79454SHarishankar Vishwanathan "r4 = r0;"
1406e1d79454SHarishankar Vishwanathan "r3 = 2;"
1407e1d79454SHarishankar Vishwanathan "r3 |= r4;"
1408e1d79454SHarishankar Vishwanathan "r3 += r3;"
1409e1d79454SHarishankar Vishwanathan "r0 = 0;"
1410e1d79454SHarishankar Vishwanathan "exit"
1411e1d79454SHarishankar Vishwanathan :
1412e1d79454SHarishankar Vishwanathan : __imm(bpf_get_prandom_u32)
1413e1d79454SHarishankar Vishwanathan : __clobber_all);
1414e1d79454SHarishankar Vishwanathan }
1415e1d79454SHarishankar Vishwanathan
1416e1d79454SHarishankar Vishwanathan SEC("socket")
1417e1d79454SHarishankar Vishwanathan __description("32-bit addition overflow, all outcomes overflow")
1418e1d79454SHarishankar Vishwanathan __success __log_level(2)
1419e1d79454SHarishankar Vishwanathan __msg("4: (0c) w3 += w3 {{.*}} R3_w=scalar(smin=umin=umin32=0x40000000,smax=umax=umax32=0xfffffffe,var_off=(0x0; 0xffffffff))")
1420e1d79454SHarishankar Vishwanathan __retval(0)
add32_full_overflow(void)1421e1d79454SHarishankar Vishwanathan __naked void add32_full_overflow(void)
1422e1d79454SHarishankar Vishwanathan {
1423e1d79454SHarishankar Vishwanathan asm volatile (
1424e1d79454SHarishankar Vishwanathan "call %[bpf_get_prandom_u32];"
1425e1d79454SHarishankar Vishwanathan "w4 = w0;"
1426e1d79454SHarishankar Vishwanathan "w3 = 0xa0000000;"
1427e1d79454SHarishankar Vishwanathan "w3 |= w4;"
1428e1d79454SHarishankar Vishwanathan "w3 += w3;"
1429e1d79454SHarishankar Vishwanathan "r0 = 0;"
1430e1d79454SHarishankar Vishwanathan "exit"
1431e1d79454SHarishankar Vishwanathan :
1432e1d79454SHarishankar Vishwanathan : __imm(bpf_get_prandom_u32)
1433e1d79454SHarishankar Vishwanathan : __clobber_all);
1434e1d79454SHarishankar Vishwanathan }
1435e1d79454SHarishankar Vishwanathan
1436e1d79454SHarishankar Vishwanathan SEC("socket")
1437e1d79454SHarishankar Vishwanathan __description("32-bit addition, partial overflow, result in unbounded u32 bounds")
1438e1d79454SHarishankar Vishwanathan __success __log_level(2)
1439e1d79454SHarishankar Vishwanathan __msg("4: (0c) w3 += w3 {{.*}} R3_w=scalar(smin=0,smax=umax=0xffffffff,var_off=(0x0; 0xffffffff))")
1440e1d79454SHarishankar Vishwanathan __retval(0)
add32_partial_overflow(void)1441e1d79454SHarishankar Vishwanathan __naked void add32_partial_overflow(void)
1442e1d79454SHarishankar Vishwanathan {
1443e1d79454SHarishankar Vishwanathan asm volatile (
1444e1d79454SHarishankar Vishwanathan "call %[bpf_get_prandom_u32];"
1445e1d79454SHarishankar Vishwanathan "w4 = w0;"
1446e1d79454SHarishankar Vishwanathan "w3 = 2;"
1447e1d79454SHarishankar Vishwanathan "w3 |= w4;"
1448e1d79454SHarishankar Vishwanathan "w3 += w3;"
1449e1d79454SHarishankar Vishwanathan "r0 = 0;"
1450e1d79454SHarishankar Vishwanathan "exit"
1451e1d79454SHarishankar Vishwanathan :
1452e1d79454SHarishankar Vishwanathan : __imm(bpf_get_prandom_u32)
1453e1d79454SHarishankar Vishwanathan : __clobber_all);
1454e1d79454SHarishankar Vishwanathan }
1455e1d79454SHarishankar Vishwanathan
1456e1d79454SHarishankar Vishwanathan SEC("socket")
1457e1d79454SHarishankar Vishwanathan __description("64-bit subtraction, all outcomes underflow")
1458e1d79454SHarishankar Vishwanathan __success __log_level(2)
1459e1d79454SHarishankar Vishwanathan __msg("6: (1f) r3 -= r1 {{.*}} R3_w=scalar(umin=1,umax=0x8000000000000000)")
1460e1d79454SHarishankar Vishwanathan __retval(0)
sub64_full_overflow(void)1461e1d79454SHarishankar Vishwanathan __naked void sub64_full_overflow(void)
1462e1d79454SHarishankar Vishwanathan {
1463e1d79454SHarishankar Vishwanathan asm volatile (
1464e1d79454SHarishankar Vishwanathan "call %[bpf_get_prandom_u32];"
1465e1d79454SHarishankar Vishwanathan "r1 = r0;"
1466e1d79454SHarishankar Vishwanathan "r2 = 0x8000000000000000 ll;"
1467e1d79454SHarishankar Vishwanathan "r1 |= r2;"
1468e1d79454SHarishankar Vishwanathan "r3 = 0;"
1469e1d79454SHarishankar Vishwanathan "r3 -= r1;"
1470e1d79454SHarishankar Vishwanathan "r0 = 0;"
1471e1d79454SHarishankar Vishwanathan "exit"
1472e1d79454SHarishankar Vishwanathan :
1473e1d79454SHarishankar Vishwanathan : __imm(bpf_get_prandom_u32)
1474e1d79454SHarishankar Vishwanathan : __clobber_all);
1475e1d79454SHarishankar Vishwanathan }
1476e1d79454SHarishankar Vishwanathan
1477e1d79454SHarishankar Vishwanathan SEC("socket")
14781230be82SColin Ian King __description("64-bit subtraction, partial overflow, result in unbounded reg")
1479e1d79454SHarishankar Vishwanathan __success __log_level(2)
1480e1d79454SHarishankar Vishwanathan __msg("3: (1f) r3 -= r2 {{.*}} R3_w=scalar()")
1481e1d79454SHarishankar Vishwanathan __retval(0)
sub64_partial_overflow(void)1482e1d79454SHarishankar Vishwanathan __naked void sub64_partial_overflow(void)
1483e1d79454SHarishankar Vishwanathan {
1484e1d79454SHarishankar Vishwanathan asm volatile (
1485e1d79454SHarishankar Vishwanathan "call %[bpf_get_prandom_u32];"
1486e1d79454SHarishankar Vishwanathan "r3 = r0;"
1487e1d79454SHarishankar Vishwanathan "r2 = 1;"
1488e1d79454SHarishankar Vishwanathan "r3 -= r2;"
1489e1d79454SHarishankar Vishwanathan "r0 = 0;"
1490e1d79454SHarishankar Vishwanathan "exit"
1491e1d79454SHarishankar Vishwanathan :
1492e1d79454SHarishankar Vishwanathan : __imm(bpf_get_prandom_u32)
1493e1d79454SHarishankar Vishwanathan : __clobber_all);
1494e1d79454SHarishankar Vishwanathan }
1495e1d79454SHarishankar Vishwanathan
1496e1d79454SHarishankar Vishwanathan SEC("socket")
1497e1d79454SHarishankar Vishwanathan __description("32-bit subtraction overflow, all outcomes underflow")
1498e1d79454SHarishankar Vishwanathan __success __log_level(2)
1499e1d79454SHarishankar Vishwanathan __msg("5: (1c) w3 -= w1 {{.*}} R3_w=scalar(smin=umin=umin32=1,smax=umax=umax32=0x80000000,var_off=(0x0; 0xffffffff))")
1500e1d79454SHarishankar Vishwanathan __retval(0)
sub32_full_overflow(void)1501e1d79454SHarishankar Vishwanathan __naked void sub32_full_overflow(void)
1502e1d79454SHarishankar Vishwanathan {
1503e1d79454SHarishankar Vishwanathan asm volatile (
1504e1d79454SHarishankar Vishwanathan "call %[bpf_get_prandom_u32];"
1505e1d79454SHarishankar Vishwanathan "w1 = w0;"
1506e1d79454SHarishankar Vishwanathan "w2 = 0x80000000;"
1507e1d79454SHarishankar Vishwanathan "w1 |= w2;"
1508e1d79454SHarishankar Vishwanathan "w3 = 0;"
1509e1d79454SHarishankar Vishwanathan "w3 -= w1;"
1510e1d79454SHarishankar Vishwanathan "r0 = 0;"
1511e1d79454SHarishankar Vishwanathan "exit"
1512e1d79454SHarishankar Vishwanathan :
1513e1d79454SHarishankar Vishwanathan : __imm(bpf_get_prandom_u32)
1514e1d79454SHarishankar Vishwanathan : __clobber_all);
1515e1d79454SHarishankar Vishwanathan }
1516e1d79454SHarishankar Vishwanathan
1517e1d79454SHarishankar Vishwanathan SEC("socket")
15181230be82SColin Ian King __description("32-bit subtraction, partial overflow, result in unbounded u32 bounds")
1519e1d79454SHarishankar Vishwanathan __success __log_level(2)
1520e1d79454SHarishankar Vishwanathan __msg("3: (1c) w3 -= w2 {{.*}} R3_w=scalar(smin=0,smax=umax=0xffffffff,var_off=(0x0; 0xffffffff))")
1521e1d79454SHarishankar Vishwanathan __retval(0)
sub32_partial_overflow(void)1522e1d79454SHarishankar Vishwanathan __naked void sub32_partial_overflow(void)
1523e1d79454SHarishankar Vishwanathan {
1524e1d79454SHarishankar Vishwanathan asm volatile (
1525e1d79454SHarishankar Vishwanathan "call %[bpf_get_prandom_u32];"
1526e1d79454SHarishankar Vishwanathan "w3 = w0;"
1527e1d79454SHarishankar Vishwanathan "w2 = 1;"
1528e1d79454SHarishankar Vishwanathan "w3 -= w2;"
1529e1d79454SHarishankar Vishwanathan "r0 = 0;"
1530e1d79454SHarishankar Vishwanathan "exit"
1531e1d79454SHarishankar Vishwanathan :
1532e1d79454SHarishankar Vishwanathan : __imm(bpf_get_prandom_u32)
1533e1d79454SHarishankar Vishwanathan : __clobber_all);
1534e1d79454SHarishankar Vishwanathan }
1535e1d79454SHarishankar Vishwanathan
1536d81526a6SPaul Chaignon SEC("socket")
1537d81526a6SPaul Chaignon __description("dead branch on jset, does not result in invariants violation error")
1538d81526a6SPaul Chaignon __success __log_level(2)
__flag(BPF_F_TEST_REG_INVARIANTS)1539d81526a6SPaul Chaignon __retval(0) __flag(BPF_F_TEST_REG_INVARIANTS)
1540d81526a6SPaul Chaignon __naked void jset_range_analysis(void)
1541d81526a6SPaul Chaignon {
1542d81526a6SPaul Chaignon asm volatile (" \
1543d81526a6SPaul Chaignon call %[bpf_get_netns_cookie]; \
1544d81526a6SPaul Chaignon if r0 == 0 goto l0_%=; \
1545d81526a6SPaul Chaignon if r0 & 0xffffffff goto +0; \
1546d81526a6SPaul Chaignon l0_%=: r0 = 0; \
1547d81526a6SPaul Chaignon exit; \
1548d81526a6SPaul Chaignon " :
1549d81526a6SPaul Chaignon : __imm(bpf_get_netns_cookie)
1550d81526a6SPaul Chaignon : __clobber_all);
1551d81526a6SPaul Chaignon }
1552d81526a6SPaul Chaignon
155326e5e346SPaul Chaignon /* This test covers the bounds deduction on 64bits when the s64 and u64 ranges
155426e5e346SPaul Chaignon * overlap on the negative side. At instruction 7, the ranges look as follows:
155526e5e346SPaul Chaignon *
155626e5e346SPaul Chaignon * 0 umin=0xfffffcf1 umax=0xff..ff6e U64_MAX
155726e5e346SPaul Chaignon * | [xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx] |
155826e5e346SPaul Chaignon * |----------------------------|------------------------------|
155926e5e346SPaul Chaignon * |xxxxxxxxxx] [xxxxxxxxxxxx|
156026e5e346SPaul Chaignon * 0 smax=0xeffffeee smin=-655 -1
156126e5e346SPaul Chaignon *
156226e5e346SPaul Chaignon * We should therefore deduce the following new bounds:
156326e5e346SPaul Chaignon *
156426e5e346SPaul Chaignon * 0 u64=[0xff..ffd71;0xff..ff6e] U64_MAX
156526e5e346SPaul Chaignon * | [xxx] |
156626e5e346SPaul Chaignon * |----------------------------|------------------------------|
156726e5e346SPaul Chaignon * | [xxx] |
156826e5e346SPaul Chaignon * 0 s64=[-655;-146] -1
156926e5e346SPaul Chaignon *
157026e5e346SPaul Chaignon * Without the deduction cross sign boundary, we end up with an invariant
157126e5e346SPaul Chaignon * violation error.
157226e5e346SPaul Chaignon */
157326e5e346SPaul Chaignon SEC("socket")
157426e5e346SPaul Chaignon __description("bounds deduction cross sign boundary, negative overlap")
__flag(BPF_F_TEST_REG_INVARIANTS)157526e5e346SPaul Chaignon __success __log_level(2) __flag(BPF_F_TEST_REG_INVARIANTS)
1576*5dbb19b1SPaul Chaignon __msg("7: (1f) r0 -= r6 {{.*}} R0=scalar(smin=smin32=-655,smax=smax32=-146,umin=0xfffffffffffffd71,umax=0xffffffffffffff6e,umin32=0xfffffd71,umax32=0xffffff6e,var_off=(0xfffffffffffffc00; 0x3ff))")
157726e5e346SPaul Chaignon __retval(0)
157826e5e346SPaul Chaignon __naked void bounds_deduct_negative_overlap(void)
157926e5e346SPaul Chaignon {
158026e5e346SPaul Chaignon asm volatile(" \
158126e5e346SPaul Chaignon call %[bpf_get_prandom_u32]; \
158226e5e346SPaul Chaignon w3 = w0; \
158326e5e346SPaul Chaignon w6 = (s8)w0; \
158426e5e346SPaul Chaignon r0 = (s8)r0; \
158526e5e346SPaul Chaignon if w6 >= 0xf0000000 goto l0_%=; \
158626e5e346SPaul Chaignon r0 += r6; \
158726e5e346SPaul Chaignon r6 += 400; \
158826e5e346SPaul Chaignon r0 -= r6; \
158926e5e346SPaul Chaignon if r3 < r0 goto l0_%=; \
159026e5e346SPaul Chaignon l0_%=: r0 = 0; \
159126e5e346SPaul Chaignon exit; \
159226e5e346SPaul Chaignon " :
159326e5e346SPaul Chaignon : __imm(bpf_get_prandom_u32)
159426e5e346SPaul Chaignon : __clobber_all);
159526e5e346SPaul Chaignon }
159626e5e346SPaul Chaignon
159726e5e346SPaul Chaignon /* This test covers the bounds deduction on 64bits when the s64 and u64 ranges
159826e5e346SPaul Chaignon * overlap on the positive side. At instruction 3, the ranges look as follows:
159926e5e346SPaul Chaignon *
160026e5e346SPaul Chaignon * 0 umin=0 umax=0xffffffffffffff00 U64_MAX
160126e5e346SPaul Chaignon * [xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx] |
160226e5e346SPaul Chaignon * |----------------------------|------------------------------|
160326e5e346SPaul Chaignon * |xxxxxxxx] [xxxxxxxx|
160426e5e346SPaul Chaignon * 0 smax=127 smin=-128 -1
160526e5e346SPaul Chaignon *
160626e5e346SPaul Chaignon * We should therefore deduce the following new bounds:
160726e5e346SPaul Chaignon *
160826e5e346SPaul Chaignon * 0 u64=[0;127] U64_MAX
160926e5e346SPaul Chaignon * [xxxxxxxx] |
161026e5e346SPaul Chaignon * |----------------------------|------------------------------|
161126e5e346SPaul Chaignon * [xxxxxxxx] |
161226e5e346SPaul Chaignon * 0 s64=[0;127] -1
161326e5e346SPaul Chaignon *
161426e5e346SPaul Chaignon * Without the deduction cross sign boundary, the program is rejected due to
161526e5e346SPaul Chaignon * the frame pointer write.
161626e5e346SPaul Chaignon */
161726e5e346SPaul Chaignon SEC("socket")
161826e5e346SPaul Chaignon __description("bounds deduction cross sign boundary, positive overlap")
__flag(BPF_F_TEST_REG_INVARIANTS)161926e5e346SPaul Chaignon __success __log_level(2) __flag(BPF_F_TEST_REG_INVARIANTS)
162026e5e346SPaul Chaignon __msg("3: (2d) if r0 > r1 {{.*}} R0_w=scalar(smin=smin32=0,smax=umax=smax32=umax32=127,var_off=(0x0; 0x7f))")
162126e5e346SPaul Chaignon __retval(0)
162226e5e346SPaul Chaignon __naked void bounds_deduct_positive_overlap(void)
162326e5e346SPaul Chaignon {
162426e5e346SPaul Chaignon asm volatile(" \
162526e5e346SPaul Chaignon call %[bpf_get_prandom_u32]; \
162626e5e346SPaul Chaignon r0 = (s8)r0; \
162726e5e346SPaul Chaignon r1 = 0xffffffffffffff00; \
162826e5e346SPaul Chaignon if r0 > r1 goto l0_%=; \
162926e5e346SPaul Chaignon if r0 < 128 goto l0_%=; \
163026e5e346SPaul Chaignon r10 = 0; \
163126e5e346SPaul Chaignon l0_%=: r0 = 0; \
163226e5e346SPaul Chaignon exit; \
163326e5e346SPaul Chaignon " :
163426e5e346SPaul Chaignon : __imm(bpf_get_prandom_u32)
163526e5e346SPaul Chaignon : __clobber_all);
163626e5e346SPaul Chaignon }
163726e5e346SPaul Chaignon
163826e5e346SPaul Chaignon /* This test is the same as above, but the s64 and u64 ranges overlap in two
163926e5e346SPaul Chaignon * places. At instruction 3, the ranges look as follows:
164026e5e346SPaul Chaignon *
164126e5e346SPaul Chaignon * 0 umin=0 umax=0xffffffffffffff80 U64_MAX
164226e5e346SPaul Chaignon * [xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx] |
164326e5e346SPaul Chaignon * |----------------------------|------------------------------|
164426e5e346SPaul Chaignon * |xxxxxxxx] [xxxxxxxx|
164526e5e346SPaul Chaignon * 0 smax=127 smin=-128 -1
164626e5e346SPaul Chaignon *
164726e5e346SPaul Chaignon * 0xffffffffffffff80 = (u64)-128. We therefore can't deduce anything new and
164826e5e346SPaul Chaignon * the program should fail due to the frame pointer write.
164926e5e346SPaul Chaignon */
165026e5e346SPaul Chaignon SEC("socket")
165126e5e346SPaul Chaignon __description("bounds deduction cross sign boundary, two overlaps")
__flag(BPF_F_TEST_REG_INVARIANTS)165226e5e346SPaul Chaignon __failure __flag(BPF_F_TEST_REG_INVARIANTS)
165326e5e346SPaul Chaignon __msg("3: (2d) if r0 > r1 {{.*}} R0_w=scalar(smin=smin32=-128,smax=smax32=127,umax=0xffffffffffffff80)")
165426e5e346SPaul Chaignon __msg("frame pointer is read only")
165526e5e346SPaul Chaignon __naked void bounds_deduct_two_overlaps(void)
165626e5e346SPaul Chaignon {
165726e5e346SPaul Chaignon asm volatile(" \
165826e5e346SPaul Chaignon call %[bpf_get_prandom_u32]; \
165926e5e346SPaul Chaignon r0 = (s8)r0; \
166026e5e346SPaul Chaignon r1 = 0xffffffffffffff80; \
166126e5e346SPaul Chaignon if r0 > r1 goto l0_%=; \
166226e5e346SPaul Chaignon if r0 < 128 goto l0_%=; \
166326e5e346SPaul Chaignon r10 = 0; \
166426e5e346SPaul Chaignon l0_%=: r0 = 0; \
166526e5e346SPaul Chaignon exit; \
166626e5e346SPaul Chaignon " :
166726e5e346SPaul Chaignon : __imm(bpf_get_prandom_u32)
166826e5e346SPaul Chaignon : __clobber_all);
166926e5e346SPaul Chaignon }
167026e5e346SPaul Chaignon
1671c9233655SEduard Zingerman char _license[] SEC("license") = "GPL";
1672