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)) && __clang_major__ >= 18
9 
10 SEC("socket")
11 __description("MOV32SX, S8")
12 __success __success_unpriv __retval(0x23)
13 __naked void mov32sx_s8(void)
14 {
15 	asm volatile ("					\
16 	w0 = 0xff23;					\
17 	w0 = (s8)w0;					\
18 	exit;						\
19 "	::: __clobber_all);
20 }
21 
22 SEC("socket")
23 __description("MOV32SX, S16")
24 __success __success_unpriv __retval(0xFFFFff23)
25 __naked void mov32sx_s16(void)
26 {
27 	asm volatile ("					\
28 	w0 = 0xff23;					\
29 	w0 = (s16)w0;					\
30 	exit;						\
31 "	::: __clobber_all);
32 }
33 
34 SEC("socket")
35 __description("MOV64SX, S8")
36 __success __success_unpriv __retval(-2)
37 __naked void mov64sx_s8(void)
38 {
39 	asm volatile ("					\
40 	r0 = 0x1fe;					\
41 	r0 = (s8)r0;					\
42 	exit;						\
43 "	::: __clobber_all);
44 }
45 
46 SEC("socket")
47 __description("MOV64SX, S16")
48 __success __success_unpriv __retval(0xf23)
49 __naked void mov64sx_s16(void)
50 {
51 	asm volatile ("					\
52 	r0 = 0xf0f23;					\
53 	r0 = (s16)r0;					\
54 	exit;						\
55 "	::: __clobber_all);
56 }
57 
58 SEC("socket")
59 __description("MOV64SX, S32")
60 __success __success_unpriv __retval(-1)
61 __naked void mov64sx_s32(void)
62 {
63 	asm volatile ("					\
64 	r0 = 0xfffffffe;				\
65 	r0 = (s32)r0;					\
66 	r0 >>= 1;					\
67 	exit;						\
68 "	::: __clobber_all);
69 }
70 
71 SEC("socket")
72 __description("MOV32SX, S8, range_check")
73 __success __success_unpriv __retval(1)
74 __naked void mov32sx_s8_range(void)
75 {
76 	asm volatile ("					\
77 	call %[bpf_get_prandom_u32];			\
78 	w1 = (s8)w0;					\
79 	/* w1 with s8 range */				\
80 	if w1 s> 0x7f goto l0_%=;			\
81 	if w1 s< -0x80 goto l0_%=;			\
82 	r0 = 1;						\
83 l1_%=:							\
84 	exit;						\
85 l0_%=:							\
86 	r0 = 2;						\
87 	goto l1_%=;					\
88 "	:
89 	: __imm(bpf_get_prandom_u32)
90 	: __clobber_all);
91 }
92 
93 SEC("socket")
94 __description("MOV32SX, S16, range_check")
95 __success __success_unpriv __retval(1)
96 __naked void mov32sx_s16_range(void)
97 {
98 	asm volatile ("					\
99 	call %[bpf_get_prandom_u32];			\
100 	w1 = (s16)w0;					\
101 	/* w1 with s16 range */				\
102 	if w1 s> 0x7fff goto l0_%=;			\
103 	if w1 s< -0x80ff goto l0_%=;			\
104 	r0 = 1;						\
105 l1_%=:							\
106 	exit;						\
107 l0_%=:							\
108 	r0 = 2;						\
109 	goto l1_%=;					\
110 "	:
111 	: __imm(bpf_get_prandom_u32)
112 	: __clobber_all);
113 }
114 
115 SEC("socket")
116 __description("MOV32SX, S16, range_check 2")
117 __success __success_unpriv __retval(1)
118 __naked void mov32sx_s16_range_2(void)
119 {
120 	asm volatile ("					\
121 	r1 = 65535;					\
122 	w2 = (s16)w1;					\
123 	r2 >>= 1;					\
124 	if r2 != 0x7fffFFFF goto l0_%=;			\
125 	r0 = 1;						\
126 l1_%=:							\
127 	exit;						\
128 l0_%=:							\
129 	r0 = 0;						\
130 	goto l1_%=;					\
131 "	:
132 	: __imm(bpf_get_prandom_u32)
133 	: __clobber_all);
134 }
135 
136 SEC("socket")
137 __description("MOV64SX, S8, range_check")
138 __success __success_unpriv __retval(1)
139 __naked void mov64sx_s8_range(void)
140 {
141 	asm volatile ("					\
142 	call %[bpf_get_prandom_u32];			\
143 	r1 = (s8)r0;					\
144 	/* r1 with s8 range */				\
145 	if r1 s> 0x7f goto l0_%=;			\
146 	if r1 s< -0x80 goto l0_%=;			\
147 	r0 = 1;						\
148 l1_%=:							\
149 	exit;						\
150 l0_%=:							\
151 	r0 = 2;						\
152 	goto l1_%=;					\
153 "	:
154 	: __imm(bpf_get_prandom_u32)
155 	: __clobber_all);
156 }
157 
158 SEC("socket")
159 __description("MOV64SX, S16, range_check")
160 __success __success_unpriv __retval(1)
161 __naked void mov64sx_s16_range(void)
162 {
163 	asm volatile ("					\
164 	call %[bpf_get_prandom_u32];			\
165 	r1 = (s16)r0;					\
166 	/* r1 with s16 range */				\
167 	if r1 s> 0x7fff goto l0_%=;			\
168 	if r1 s< -0x8000 goto l0_%=;			\
169 	r0 = 1;						\
170 l1_%=:							\
171 	exit;						\
172 l0_%=:							\
173 	r0 = 2;						\
174 	goto l1_%=;					\
175 "	:
176 	: __imm(bpf_get_prandom_u32)
177 	: __clobber_all);
178 }
179 
180 SEC("socket")
181 __description("MOV64SX, S32, range_check")
182 __success __success_unpriv __retval(1)
183 __naked void mov64sx_s32_range(void)
184 {
185 	asm volatile ("					\
186 	call %[bpf_get_prandom_u32];			\
187 	r1 = (s32)r0;					\
188 	/* r1 with s32 range */				\
189 	if r1 s> 0x7fffffff goto l0_%=;			\
190 	if r1 s< -0x80000000 goto l0_%=;		\
191 	r0 = 1;						\
192 l1_%=:							\
193 	exit;						\
194 l0_%=:							\
195 	r0 = 2;						\
196 	goto l1_%=;					\
197 "	:
198 	: __imm(bpf_get_prandom_u32)
199 	: __clobber_all);
200 }
201 
202 SEC("socket")
203 __description("MOV64SX, S16, R10 Sign Extension")
204 __failure __msg("R1 type=scalar expected=fp, pkt, pkt_meta, map_key, map_value, mem, ringbuf_mem, buf, trusted_ptr_")
205 __failure_unpriv __msg_unpriv("R10 sign-extension part of pointer")
206 __naked void mov64sx_s16_r10(void)
207 {
208 	asm volatile ("					\
209 	r1 = 553656332;					\
210 	*(u32 *)(r10 - 8) = r1; 			\
211 	r1 = (s16)r10;					\
212 	r1 += -8;					\
213 	r2 = 3;						\
214 	if r2 <= r1 goto l0_%=;				\
215 l0_%=:							\
216 	call %[bpf_trace_printk];			\
217 	r0 = 0;						\
218 	exit;						\
219 "	:
220 	: __imm(bpf_trace_printk)
221 	: __clobber_all);
222 }
223 
224 #else
225 
226 SEC("socket")
227 __description("cpuv4 is not supported by compiler or jit, use a dummy test")
228 __success
229 int dummy_test(void)
230 {
231 	return 0;
232 }
233 
234 #endif
235 
236 char _license[] SEC("license") = "GPL";
237