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) 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) 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) 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) 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) 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) 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) 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) 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) 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) 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) 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") 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") 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 __success_unpriv 249 #ifdef SPEC_V1 250 __xlated_unpriv("w0 = 0") 251 __xlated_unpriv("exit") 252 __xlated_unpriv("nospec") /* inserted to prevent `frame pointer is read only` */ 253 __xlated_unpriv("goto pc-1") 254 #endif 255 __naked void mov64sx_s32_varoff_2(void) 256 { 257 asm volatile (" \ 258 call %[bpf_get_prandom_u32]; \ 259 r3 = r0; \ 260 r3 &= 0xf; \ 261 w7 = (s8)w3; \ 262 if w7 s>= 16 goto l0_%=; \ 263 w0 = 0; \ 264 exit; \ 265 l0_%=: \ 266 r10 = 1; \ 267 exit; \ 268 " : 269 : __imm(bpf_get_prandom_u32) 270 : __clobber_all); 271 } 272 273 SEC("socket") 274 __description("MOV32SX, S8, var_off not u32_max, negative after s8 extension") 275 __success __retval(0) 276 __success_unpriv 277 #ifdef SPEC_V1 278 __xlated_unpriv("w0 = 0") 279 __xlated_unpriv("exit") 280 __xlated_unpriv("nospec") /* inserted to prevent `frame pointer is read only` */ 281 __xlated_unpriv("goto pc-1") 282 #endif 283 __naked void mov64sx_s32_varoff_3(void) 284 { 285 asm volatile (" \ 286 call %[bpf_get_prandom_u32]; \ 287 r3 = r0; \ 288 r3 &= 0xf; \ 289 r3 |= 0x80; \ 290 w7 = (s8)w3; \ 291 if w7 s>= -5 goto l0_%=; \ 292 w0 = 0; \ 293 exit; \ 294 l0_%=: \ 295 r10 = 1; \ 296 exit; \ 297 " : 298 : __imm(bpf_get_prandom_u32) 299 : __clobber_all); 300 } 301 302 SEC("socket") 303 __description("MOV64SX, S8, unsigned range_check") 304 __success __retval(0) 305 __naked void mov64sx_s8_range_check(void) 306 { 307 asm volatile (" \ 308 call %[bpf_get_prandom_u32]; \ 309 r0 &= 0x1; \ 310 r0 += 0xfe; \ 311 r0 = (s8)r0; \ 312 if r0 < 0xfffffffffffffffe goto label_%=; \ 313 r0 = 0; \ 314 exit; \ 315 label_%=: \ 316 exit; \ 317 " : 318 : __imm(bpf_get_prandom_u32) 319 : __clobber_all); 320 } 321 322 SEC("socket") 323 __description("MOV32SX, S8, unsigned range_check") 324 __success __retval(0) 325 __naked void mov32sx_s8_range_check(void) 326 { 327 asm volatile (" \ 328 call %[bpf_get_prandom_u32]; \ 329 w0 &= 0x1; \ 330 w0 += 0xfe; \ 331 w0 = (s8)w0; \ 332 if w0 < 0xfffffffe goto label_%=; \ 333 r0 = 0; \ 334 exit; \ 335 label_%=: \ 336 exit; \ 337 " : 338 : __imm(bpf_get_prandom_u32) 339 : __clobber_all); 340 } 341 342 #else 343 344 SEC("socket") 345 __description("cpuv4 is not supported by compiler or jit, use a dummy test") 346 __success 347 int dummy_test(void) 348 { 349 return 0; 350 } 351 352 #endif 353 354 char _license[] SEC("license") = "GPL"; 355