1  // SPDX-License-Identifier: GPL-2.0
2  
3  #include <linux/bpf.h>
4  #include <bpf/bpf_helpers.h>
5  #include "bpf_misc.h"
6  
7  #if (defined(__TARGET_ARCH_arm64) || defined(__TARGET_ARCH_x86) || \
8  	(defined(__TARGET_ARCH_riscv) && __riscv_xlen == 64) || \
9  	defined(__TARGET_ARCH_arm) || defined(__TARGET_ARCH_s390) || \
10  	defined(__TARGET_ARCH_loongarch)) && \
11  	__clang_major__ >= 18
12  
13  SEC("socket")
14  __description("MOV32SX, S8")
15  __success __success_unpriv __retval(0x23)
mov32sx_s8(void)16  __naked void mov32sx_s8(void)
17  {
18  	asm volatile ("					\
19  	w0 = 0xff23;					\
20  	w0 = (s8)w0;					\
21  	exit;						\
22  "	::: __clobber_all);
23  }
24  
25  SEC("socket")
26  __description("MOV32SX, S16")
27  __success __success_unpriv __retval(0xFFFFff23)
mov32sx_s16(void)28  __naked void mov32sx_s16(void)
29  {
30  	asm volatile ("					\
31  	w0 = 0xff23;					\
32  	w0 = (s16)w0;					\
33  	exit;						\
34  "	::: __clobber_all);
35  }
36  
37  SEC("socket")
38  __description("MOV64SX, S8")
39  __success __success_unpriv __retval(-2)
mov64sx_s8(void)40  __naked void mov64sx_s8(void)
41  {
42  	asm volatile ("					\
43  	r0 = 0x1fe;					\
44  	r0 = (s8)r0;					\
45  	exit;						\
46  "	::: __clobber_all);
47  }
48  
49  SEC("socket")
50  __description("MOV64SX, S16")
51  __success __success_unpriv __retval(0xf23)
mov64sx_s16(void)52  __naked void mov64sx_s16(void)
53  {
54  	asm volatile ("					\
55  	r0 = 0xf0f23;					\
56  	r0 = (s16)r0;					\
57  	exit;						\
58  "	::: __clobber_all);
59  }
60  
61  SEC("socket")
62  __description("MOV64SX, S32")
63  __success __success_unpriv __retval(-1)
mov64sx_s32(void)64  __naked void mov64sx_s32(void)
65  {
66  	asm volatile ("					\
67  	r0 = 0xfffffffe;				\
68  	r0 = (s32)r0;					\
69  	r0 >>= 1;					\
70  	exit;						\
71  "	::: __clobber_all);
72  }
73  
74  SEC("socket")
75  __description("MOV32SX, S8, range_check")
76  __success __success_unpriv __retval(1)
mov32sx_s8_range(void)77  __naked void mov32sx_s8_range(void)
78  {
79  	asm volatile ("					\
80  	call %[bpf_get_prandom_u32];			\
81  	w1 = (s8)w0;					\
82  	/* w1 with s8 range */				\
83  	if w1 s> 0x7f goto l0_%=;			\
84  	if w1 s< -0x80 goto l0_%=;			\
85  	r0 = 1;						\
86  l1_%=:							\
87  	exit;						\
88  l0_%=:							\
89  	r0 = 2;						\
90  	goto l1_%=;					\
91  "	:
92  	: __imm(bpf_get_prandom_u32)
93  	: __clobber_all);
94  }
95  
96  SEC("socket")
97  __description("MOV32SX, S16, range_check")
98  __success __success_unpriv __retval(1)
mov32sx_s16_range(void)99  __naked void mov32sx_s16_range(void)
100  {
101  	asm volatile ("					\
102  	call %[bpf_get_prandom_u32];			\
103  	w1 = (s16)w0;					\
104  	/* w1 with s16 range */				\
105  	if w1 s> 0x7fff goto l0_%=;			\
106  	if w1 s< -0x80ff goto l0_%=;			\
107  	r0 = 1;						\
108  l1_%=:							\
109  	exit;						\
110  l0_%=:							\
111  	r0 = 2;						\
112  	goto l1_%=;					\
113  "	:
114  	: __imm(bpf_get_prandom_u32)
115  	: __clobber_all);
116  }
117  
118  SEC("socket")
119  __description("MOV32SX, S16, range_check 2")
120  __success __success_unpriv __retval(1)
mov32sx_s16_range_2(void)121  __naked void mov32sx_s16_range_2(void)
122  {
123  	asm volatile ("					\
124  	r1 = 65535;					\
125  	w2 = (s16)w1;					\
126  	r2 >>= 1;					\
127  	if r2 != 0x7fffFFFF goto l0_%=;			\
128  	r0 = 1;						\
129  l1_%=:							\
130  	exit;						\
131  l0_%=:							\
132  	r0 = 0;						\
133  	goto l1_%=;					\
134  "	:
135  	: __imm(bpf_get_prandom_u32)
136  	: __clobber_all);
137  }
138  
139  SEC("socket")
140  __description("MOV64SX, S8, range_check")
141  __success __success_unpriv __retval(1)
mov64sx_s8_range(void)142  __naked void mov64sx_s8_range(void)
143  {
144  	asm volatile ("					\
145  	call %[bpf_get_prandom_u32];			\
146  	r1 = (s8)r0;					\
147  	/* r1 with s8 range */				\
148  	if r1 s> 0x7f goto l0_%=;			\
149  	if r1 s< -0x80 goto l0_%=;			\
150  	r0 = 1;						\
151  l1_%=:							\
152  	exit;						\
153  l0_%=:							\
154  	r0 = 2;						\
155  	goto l1_%=;					\
156  "	:
157  	: __imm(bpf_get_prandom_u32)
158  	: __clobber_all);
159  }
160  
161  SEC("socket")
162  __description("MOV64SX, S16, range_check")
163  __success __success_unpriv __retval(1)
mov64sx_s16_range(void)164  __naked void mov64sx_s16_range(void)
165  {
166  	asm volatile ("					\
167  	call %[bpf_get_prandom_u32];			\
168  	r1 = (s16)r0;					\
169  	/* r1 with s16 range */				\
170  	if r1 s> 0x7fff goto l0_%=;			\
171  	if r1 s< -0x8000 goto l0_%=;			\
172  	r0 = 1;						\
173  l1_%=:							\
174  	exit;						\
175  l0_%=:							\
176  	r0 = 2;						\
177  	goto l1_%=;					\
178  "	:
179  	: __imm(bpf_get_prandom_u32)
180  	: __clobber_all);
181  }
182  
183  SEC("socket")
184  __description("MOV64SX, S32, range_check")
185  __success __success_unpriv __retval(1)
mov64sx_s32_range(void)186  __naked void mov64sx_s32_range(void)
187  {
188  	asm volatile ("					\
189  	call %[bpf_get_prandom_u32];			\
190  	r1 = (s32)r0;					\
191  	/* r1 with s32 range */				\
192  	if r1 s> 0x7fffffff goto l0_%=;			\
193  	if r1 s< -0x80000000 goto l0_%=;		\
194  	r0 = 1;						\
195  l1_%=:							\
196  	exit;						\
197  l0_%=:							\
198  	r0 = 2;						\
199  	goto l1_%=;					\
200  "	:
201  	: __imm(bpf_get_prandom_u32)
202  	: __clobber_all);
203  }
204  
205  SEC("socket")
206  __description("MOV64SX, S16, R10 Sign Extension")
207  __failure __msg("R1 type=scalar expected=fp, pkt, pkt_meta, map_key, map_value, mem, ringbuf_mem, buf, trusted_ptr_")
208  __failure_unpriv __msg_unpriv("R10 sign-extension part of pointer")
mov64sx_s16_r10(void)209  __naked void mov64sx_s16_r10(void)
210  {
211  	asm volatile ("					\
212  	r1 = 553656332;					\
213  	*(u32 *)(r10 - 8) = r1; 			\
214  	r1 = (s16)r10;					\
215  	r1 += -8;					\
216  	r2 = 3;						\
217  	if r2 <= r1 goto l0_%=;				\
218  l0_%=:							\
219  	call %[bpf_trace_printk];			\
220  	r0 = 0;						\
221  	exit;						\
222  "	:
223  	: __imm(bpf_trace_printk)
224  	: __clobber_all);
225  }
226  
227  SEC("socket")
228  __description("MOV32SX, S8, var_off u32_max")
229  __failure __msg("infinite loop detected")
230  __failure_unpriv __msg_unpriv("back-edge from insn 2 to 0")
mov64sx_s32_varoff_1(void)231  __naked void mov64sx_s32_varoff_1(void)
232  {
233  	asm volatile ("					\
234  l0_%=:							\
235  	r3 = *(u8 *)(r10 -387);				\
236  	w7 = (s8)w3;					\
237  	if w7 >= 0x2533823b goto l0_%=;			\
238  	w0 = 0;						\
239  	exit;						\
240  "	:
241  	:
242  	: __clobber_all);
243  }
244  
245  SEC("socket")
246  __description("MOV32SX, S8, var_off not u32_max, positive after s8 extension")
247  __success __retval(0)
248  __failure_unpriv __msg_unpriv("frame pointer is read only")
mov64sx_s32_varoff_2(void)249  __naked void mov64sx_s32_varoff_2(void)
250  {
251  	asm volatile ("					\
252  	call %[bpf_get_prandom_u32];			\
253  	r3 = r0;					\
254  	r3 &= 0xf;					\
255  	w7 = (s8)w3;					\
256  	if w7 s>= 16 goto l0_%=;			\
257  	w0 = 0;						\
258  	exit;						\
259  l0_%=:							\
260  	r10 = 1;					\
261  	exit;						\
262  "	:
263  	: __imm(bpf_get_prandom_u32)
264  	: __clobber_all);
265  }
266  
267  SEC("socket")
268  __description("MOV32SX, S8, var_off not u32_max, negative after s8 extension")
269  __success __retval(0)
270  __failure_unpriv __msg_unpriv("frame pointer is read only")
mov64sx_s32_varoff_3(void)271  __naked void mov64sx_s32_varoff_3(void)
272  {
273  	asm volatile ("					\
274  	call %[bpf_get_prandom_u32];			\
275  	r3 = r0;					\
276  	r3 &= 0xf;					\
277  	r3 |= 0x80;					\
278  	w7 = (s8)w3;					\
279  	if w7 s>= -5 goto l0_%=;			\
280  	w0 = 0;						\
281  	exit;						\
282  l0_%=:							\
283  	r10 = 1;					\
284  	exit;						\
285  "	:
286  	: __imm(bpf_get_prandom_u32)
287  	: __clobber_all);
288  }
289  
290  SEC("socket")
291  __description("MOV64SX, S8, unsigned range_check")
292  __success __retval(0)
mov64sx_s8_range_check(void)293  __naked void mov64sx_s8_range_check(void)
294  {
295  	asm volatile ("					\
296  	call %[bpf_get_prandom_u32];			\
297  	r0 &= 0x1;					\
298  	r0 += 0xfe;					\
299  	r0 = (s8)r0;					\
300  	if r0 < 0xfffffffffffffffe goto label_%=;	\
301  	r0 = 0;						\
302  	exit;						\
303  label_%=:						\
304  	exit;						\
305  "	:
306  	: __imm(bpf_get_prandom_u32)
307  	: __clobber_all);
308  }
309  
310  SEC("socket")
311  __description("MOV32SX, S8, unsigned range_check")
312  __success __retval(0)
mov32sx_s8_range_check(void)313  __naked void mov32sx_s8_range_check(void)
314  {
315  	asm volatile ("                                 \
316  	call %[bpf_get_prandom_u32];                    \
317  	w0 &= 0x1;                                      \
318  	w0 += 0xfe;                                     \
319  	w0 = (s8)w0;                                    \
320  	if w0 < 0xfffffffe goto label_%=;               \
321  	r0 = 0;                                         \
322  	exit;                                           \
323  label_%=: 	                                        \
324  	exit;                                           \
325  	"      :
326  	: __imm(bpf_get_prandom_u32)
327  	: __clobber_all);
328  }
329  
330  #else
331  
332  SEC("socket")
333  __description("cpuv4 is not supported by compiler or jit, use a dummy test")
334  __success
dummy_test(void)335  int dummy_test(void)
336  {
337  	return 0;
338  }
339  
340  #endif
341  
342  char _license[] SEC("license") = "GPL";
343