xref: /linux/tools/testing/selftests/bpf/progs/verifier_bounds.c (revision 0a91336e287ca2557fead5221d2c79e0effd034e)
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