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