1 // SPDX-License-Identifier: GPL-2.0
2 /* Converted from tools/testing/selftests/bpf/verifier/subreg.c */
3 
4 #include <linux/bpf.h>
5 #include <bpf/bpf_helpers.h>
6 #include "bpf_misc.h"
7 
8 /* This file contains sub-register zero extension checks for insns defining
9  * sub-registers, meaning:
10  *   - All insns under BPF_ALU class. Their BPF_ALU32 variants or narrow width
11  *     forms (BPF_END) could define sub-registers.
12  *   - Narrow direct loads, BPF_B/H/W | BPF_LDX.
13  *   - BPF_LD is not exposed to JIT back-ends, so no need for testing.
14  *
15  * "get_prandom_u32" is used to initialize low 32-bit of some registers to
16  * prevent potential optimizations done by verifier or JIT back-ends which could
17  * optimize register back into constant when range info shows one register is a
18  * constant.
19  */
20 
21 SEC("socket")
22 __description("add32 reg zero extend check")
23 __success __success_unpriv __retval(0)
24 __naked void add32_reg_zero_extend_check(void)
25 {
26 	asm volatile ("					\
27 	call %[bpf_get_prandom_u32];			\
28 	r1 = r0;					\
29 	r0 = 0x100000000 ll;				\
30 	w0 += w1;					\
31 	r0 >>= 32;					\
32 	exit;						\
33 "	:
34 	: __imm(bpf_get_prandom_u32)
35 	: __clobber_all);
36 }
37 
38 SEC("socket")
39 __description("add32 imm zero extend check")
40 __success __success_unpriv __retval(0)
41 __naked void add32_imm_zero_extend_check(void)
42 {
43 	asm volatile ("					\
44 	call %[bpf_get_prandom_u32];			\
45 	r1 = 0x1000000000 ll;				\
46 	r0 |= r1;					\
47 	/* An insn could have no effect on the low 32-bit, for example:\
48 	 *   a = a + 0					\
49 	 *   a = a | 0					\
50 	 *   a = a & -1					\
51 	 * But, they should still zero high 32-bit.	\
52 	 */						\
53 	w0 += 0;					\
54 	r0 >>= 32;					\
55 	r6 = r0;					\
56 	call %[bpf_get_prandom_u32];			\
57 	r1 = 0x1000000000 ll;				\
58 	r0 |= r1;					\
59 	w0 += -2;					\
60 	r0 >>= 32;					\
61 	r0 |= r6;					\
62 	exit;						\
63 "	:
64 	: __imm(bpf_get_prandom_u32)
65 	: __clobber_all);
66 }
67 
68 SEC("socket")
69 __description("sub32 reg zero extend check")
70 __success __success_unpriv __retval(0)
71 __naked void sub32_reg_zero_extend_check(void)
72 {
73 	asm volatile ("					\
74 	call %[bpf_get_prandom_u32];			\
75 	r1 = r0;					\
76 	r0 = 0x1ffffffff ll;				\
77 	w0 -= w1;					\
78 	r0 >>= 32;					\
79 	exit;						\
80 "	:
81 	: __imm(bpf_get_prandom_u32)
82 	: __clobber_all);
83 }
84 
85 SEC("socket")
86 __description("sub32 imm zero extend check")
87 __success __success_unpriv __retval(0)
88 __naked void sub32_imm_zero_extend_check(void)
89 {
90 	asm volatile ("					\
91 	call %[bpf_get_prandom_u32];			\
92 	r1 = 0x1000000000 ll;				\
93 	r0 |= r1;					\
94 	w0 -= 0;					\
95 	r0 >>= 32;					\
96 	r6 = r0;					\
97 	call %[bpf_get_prandom_u32];			\
98 	r1 = 0x1000000000 ll;				\
99 	r0 |= r1;					\
100 	w0 -= 1;					\
101 	r0 >>= 32;					\
102 	r0 |= r6;					\
103 	exit;						\
104 "	:
105 	: __imm(bpf_get_prandom_u32)
106 	: __clobber_all);
107 }
108 
109 SEC("socket")
110 __description("mul32 reg zero extend check")
111 __success __success_unpriv __retval(0)
112 __naked void mul32_reg_zero_extend_check(void)
113 {
114 	asm volatile ("					\
115 	call %[bpf_get_prandom_u32];			\
116 	r1 = r0;					\
117 	r0 = 0x100000001 ll;				\
118 	w0 *= w1;					\
119 	r0 >>= 32;					\
120 	exit;						\
121 "	:
122 	: __imm(bpf_get_prandom_u32)
123 	: __clobber_all);
124 }
125 
126 SEC("socket")
127 __description("mul32 imm zero extend check")
128 __success __success_unpriv __retval(0)
129 __naked void mul32_imm_zero_extend_check(void)
130 {
131 	asm volatile ("					\
132 	call %[bpf_get_prandom_u32];			\
133 	r1 = 0x1000000000 ll;				\
134 	r0 |= r1;					\
135 	w0 *= 1;					\
136 	r0 >>= 32;					\
137 	r6 = r0;					\
138 	call %[bpf_get_prandom_u32];			\
139 	r1 = 0x1000000000 ll;				\
140 	r0 |= r1;					\
141 	w0 *= -1;					\
142 	r0 >>= 32;					\
143 	r0 |= r6;					\
144 	exit;						\
145 "	:
146 	: __imm(bpf_get_prandom_u32)
147 	: __clobber_all);
148 }
149 
150 SEC("socket")
151 __description("div32 reg zero extend check")
152 __success __success_unpriv __retval(0)
153 __naked void div32_reg_zero_extend_check(void)
154 {
155 	asm volatile ("					\
156 	call %[bpf_get_prandom_u32];			\
157 	r1 = r0;					\
158 	r0 = -1;					\
159 	w0 /= w1;					\
160 	r0 >>= 32;					\
161 	exit;						\
162 "	:
163 	: __imm(bpf_get_prandom_u32)
164 	: __clobber_all);
165 }
166 
167 SEC("socket")
168 __description("div32 imm zero extend check")
169 __success __success_unpriv __retval(0)
170 __naked void div32_imm_zero_extend_check(void)
171 {
172 	asm volatile ("					\
173 	call %[bpf_get_prandom_u32];			\
174 	r1 = 0x1000000000 ll;				\
175 	r0 |= r1;					\
176 	w0 /= 1;					\
177 	r0 >>= 32;					\
178 	r6 = r0;					\
179 	call %[bpf_get_prandom_u32];			\
180 	r1 = 0x1000000000 ll;				\
181 	r0 |= r1;					\
182 	w0 /= 2;					\
183 	r0 >>= 32;					\
184 	r0 |= r6;					\
185 	exit;						\
186 "	:
187 	: __imm(bpf_get_prandom_u32)
188 	: __clobber_all);
189 }
190 
191 SEC("socket")
192 __description("or32 reg zero extend check")
193 __success __success_unpriv __retval(0)
194 __naked void or32_reg_zero_extend_check(void)
195 {
196 	asm volatile ("					\
197 	call %[bpf_get_prandom_u32];			\
198 	r1 = r0;					\
199 	r0 = 0x100000001 ll;				\
200 	w0 |= w1;					\
201 	r0 >>= 32;					\
202 	exit;						\
203 "	:
204 	: __imm(bpf_get_prandom_u32)
205 	: __clobber_all);
206 }
207 
208 SEC("socket")
209 __description("or32 imm zero extend check")
210 __success __success_unpriv __retval(0)
211 __naked void or32_imm_zero_extend_check(void)
212 {
213 	asm volatile ("					\
214 	call %[bpf_get_prandom_u32];			\
215 	r1 = 0x1000000000 ll;				\
216 	r0 |= r1;					\
217 	w0 |= 0;					\
218 	r0 >>= 32;					\
219 	r6 = r0;					\
220 	call %[bpf_get_prandom_u32];			\
221 	r1 = 0x1000000000 ll;				\
222 	r0 |= r1;					\
223 	w0 |= 1;					\
224 	r0 >>= 32;					\
225 	r0 |= r6;					\
226 	exit;						\
227 "	:
228 	: __imm(bpf_get_prandom_u32)
229 	: __clobber_all);
230 }
231 
232 SEC("socket")
233 __description("and32 reg zero extend check")
234 __success __success_unpriv __retval(0)
235 __naked void and32_reg_zero_extend_check(void)
236 {
237 	asm volatile ("					\
238 	call %[bpf_get_prandom_u32];			\
239 	r1 = 0x100000000 ll;				\
240 	r1 |= r0;					\
241 	r0 = 0x1ffffffff ll;				\
242 	w0 &= w1;					\
243 	r0 >>= 32;					\
244 	exit;						\
245 "	:
246 	: __imm(bpf_get_prandom_u32)
247 	: __clobber_all);
248 }
249 
250 SEC("socket")
251 __description("and32 imm zero extend check")
252 __success __success_unpriv __retval(0)
253 __naked void and32_imm_zero_extend_check(void)
254 {
255 	asm volatile ("					\
256 	call %[bpf_get_prandom_u32];			\
257 	r1 = 0x1000000000 ll;				\
258 	r0 |= r1;					\
259 	w0 &= -1;					\
260 	r0 >>= 32;					\
261 	r6 = r0;					\
262 	call %[bpf_get_prandom_u32];			\
263 	r1 = 0x1000000000 ll;				\
264 	r0 |= r1;					\
265 	w0 &= -2;					\
266 	r0 >>= 32;					\
267 	r0 |= r6;					\
268 	exit;						\
269 "	:
270 	: __imm(bpf_get_prandom_u32)
271 	: __clobber_all);
272 }
273 
274 SEC("socket")
275 __description("lsh32 reg zero extend check")
276 __success __success_unpriv __retval(0)
277 __naked void lsh32_reg_zero_extend_check(void)
278 {
279 	asm volatile ("					\
280 	call %[bpf_get_prandom_u32];			\
281 	r1 = 0x100000000 ll;				\
282 	r0 |= r1;					\
283 	r1 = 1;						\
284 	w0 <<= w1;					\
285 	r0 >>= 32;					\
286 	exit;						\
287 "	:
288 	: __imm(bpf_get_prandom_u32)
289 	: __clobber_all);
290 }
291 
292 SEC("socket")
293 __description("lsh32 imm zero extend check")
294 __success __success_unpriv __retval(0)
295 __naked void lsh32_imm_zero_extend_check(void)
296 {
297 	asm volatile ("					\
298 	call %[bpf_get_prandom_u32];			\
299 	r1 = 0x1000000000 ll;				\
300 	r0 |= r1;					\
301 	w0 <<= 0;					\
302 	r0 >>= 32;					\
303 	r6 = r0;					\
304 	call %[bpf_get_prandom_u32];			\
305 	r1 = 0x1000000000 ll;				\
306 	r0 |= r1;					\
307 	w0 <<= 1;					\
308 	r0 >>= 32;					\
309 	r0 |= r6;					\
310 	exit;						\
311 "	:
312 	: __imm(bpf_get_prandom_u32)
313 	: __clobber_all);
314 }
315 
316 SEC("socket")
317 __description("rsh32 reg zero extend check")
318 __success __success_unpriv __retval(0)
319 __naked void rsh32_reg_zero_extend_check(void)
320 {
321 	asm volatile ("					\
322 	call %[bpf_get_prandom_u32];			\
323 	r1 = 0x1000000000 ll;				\
324 	r0 |= r1;					\
325 	r1 = 1;						\
326 	w0 >>= w1;					\
327 	r0 >>= 32;					\
328 	exit;						\
329 "	:
330 	: __imm(bpf_get_prandom_u32)
331 	: __clobber_all);
332 }
333 
334 SEC("socket")
335 __description("rsh32 imm zero extend check")
336 __success __success_unpriv __retval(0)
337 __naked void rsh32_imm_zero_extend_check(void)
338 {
339 	asm volatile ("					\
340 	call %[bpf_get_prandom_u32];			\
341 	r1 = 0x1000000000 ll;				\
342 	r0 |= r1;					\
343 	w0 >>= 0;					\
344 	r0 >>= 32;					\
345 	r6 = r0;					\
346 	call %[bpf_get_prandom_u32];			\
347 	r1 = 0x1000000000 ll;				\
348 	r0 |= r1;					\
349 	w0 >>= 1;					\
350 	r0 >>= 32;					\
351 	r0 |= r6;					\
352 	exit;						\
353 "	:
354 	: __imm(bpf_get_prandom_u32)
355 	: __clobber_all);
356 }
357 
358 SEC("socket")
359 __description("neg32 reg zero extend check")
360 __success __success_unpriv __retval(0)
361 __naked void neg32_reg_zero_extend_check(void)
362 {
363 	asm volatile ("					\
364 	call %[bpf_get_prandom_u32];			\
365 	r1 = 0x1000000000 ll;				\
366 	r0 |= r1;					\
367 	w0 = -w0;					\
368 	r0 >>= 32;					\
369 	exit;						\
370 "	:
371 	: __imm(bpf_get_prandom_u32)
372 	: __clobber_all);
373 }
374 
375 SEC("socket")
376 __description("mod32 reg zero extend check")
377 __success __success_unpriv __retval(0)
378 __naked void mod32_reg_zero_extend_check(void)
379 {
380 	asm volatile ("					\
381 	call %[bpf_get_prandom_u32];			\
382 	r1 = r0;					\
383 	r0 = -1;					\
384 	w0 %%= w1;					\
385 	r0 >>= 32;					\
386 	exit;						\
387 "	:
388 	: __imm(bpf_get_prandom_u32)
389 	: __clobber_all);
390 }
391 
392 SEC("socket")
393 __description("mod32 imm zero extend check")
394 __success __success_unpriv __retval(0)
395 __naked void mod32_imm_zero_extend_check(void)
396 {
397 	asm volatile ("					\
398 	call %[bpf_get_prandom_u32];			\
399 	r1 = 0x1000000000 ll;				\
400 	r0 |= r1;					\
401 	w0 %%= 1;					\
402 	r0 >>= 32;					\
403 	r6 = r0;					\
404 	call %[bpf_get_prandom_u32];			\
405 	r1 = 0x1000000000 ll;				\
406 	r0 |= r1;					\
407 	w0 %%= 2;					\
408 	r0 >>= 32;					\
409 	r0 |= r6;					\
410 	exit;						\
411 "	:
412 	: __imm(bpf_get_prandom_u32)
413 	: __clobber_all);
414 }
415 
416 SEC("socket")
417 __description("xor32 reg zero extend check")
418 __success __success_unpriv __retval(0)
419 __naked void xor32_reg_zero_extend_check(void)
420 {
421 	asm volatile ("					\
422 	call %[bpf_get_prandom_u32];			\
423 	r1 = r0;					\
424 	r0 = 0x100000000 ll;				\
425 	w0 ^= w1;					\
426 	r0 >>= 32;					\
427 	exit;						\
428 "	:
429 	: __imm(bpf_get_prandom_u32)
430 	: __clobber_all);
431 }
432 
433 SEC("socket")
434 __description("xor32 imm zero extend check")
435 __success __success_unpriv __retval(0)
436 __naked void xor32_imm_zero_extend_check(void)
437 {
438 	asm volatile ("					\
439 	call %[bpf_get_prandom_u32];			\
440 	r1 = 0x1000000000 ll;				\
441 	r0 |= r1;					\
442 	w0 ^= 1;					\
443 	r0 >>= 32;					\
444 	exit;						\
445 "	:
446 	: __imm(bpf_get_prandom_u32)
447 	: __clobber_all);
448 }
449 
450 SEC("socket")
451 __description("mov32 reg zero extend check")
452 __success __success_unpriv __retval(0)
453 __naked void mov32_reg_zero_extend_check(void)
454 {
455 	asm volatile ("					\
456 	call %[bpf_get_prandom_u32];			\
457 	r1 = 0x100000000 ll;				\
458 	r1 |= r0;					\
459 	r0 = 0x100000000 ll;				\
460 	w0 = w1;					\
461 	r0 >>= 32;					\
462 	exit;						\
463 "	:
464 	: __imm(bpf_get_prandom_u32)
465 	: __clobber_all);
466 }
467 
468 SEC("socket")
469 __description("mov32 imm zero extend check")
470 __success __success_unpriv __retval(0)
471 __naked void mov32_imm_zero_extend_check(void)
472 {
473 	asm volatile ("					\
474 	call %[bpf_get_prandom_u32];			\
475 	r1 = 0x1000000000 ll;				\
476 	r0 |= r1;					\
477 	w0 = 0;						\
478 	r0 >>= 32;					\
479 	r6 = r0;					\
480 	call %[bpf_get_prandom_u32];			\
481 	r1 = 0x1000000000 ll;				\
482 	r0 |= r1;					\
483 	w0 = 1;						\
484 	r0 >>= 32;					\
485 	r0 |= r6;					\
486 	exit;						\
487 "	:
488 	: __imm(bpf_get_prandom_u32)
489 	: __clobber_all);
490 }
491 
492 SEC("socket")
493 __description("arsh32 reg zero extend check")
494 __success __success_unpriv __retval(0)
495 __naked void arsh32_reg_zero_extend_check(void)
496 {
497 	asm volatile ("					\
498 	call %[bpf_get_prandom_u32];			\
499 	r1 = 0x1000000000 ll;				\
500 	r0 |= r1;					\
501 	r1 = 1;						\
502 	w0 s>>= w1;					\
503 	r0 >>= 32;					\
504 	exit;						\
505 "	:
506 	: __imm(bpf_get_prandom_u32)
507 	: __clobber_all);
508 }
509 
510 SEC("socket")
511 __description("arsh32 imm zero extend check")
512 __success __success_unpriv __retval(0)
513 __naked void arsh32_imm_zero_extend_check(void)
514 {
515 	asm volatile ("					\
516 	call %[bpf_get_prandom_u32];			\
517 	r1 = 0x1000000000 ll;				\
518 	r0 |= r1;					\
519 	w0 s>>= 0;					\
520 	r0 >>= 32;					\
521 	r6 = r0;					\
522 	call %[bpf_get_prandom_u32];			\
523 	r1 = 0x1000000000 ll;				\
524 	r0 |= r1;					\
525 	w0 s>>= 1;					\
526 	r0 >>= 32;					\
527 	r0 |= r6;					\
528 	exit;						\
529 "	:
530 	: __imm(bpf_get_prandom_u32)
531 	: __clobber_all);
532 }
533 
534 SEC("socket")
535 __description("end16 (to_le) reg zero extend check")
536 __success __success_unpriv __retval(0)
537 __naked void le_reg_zero_extend_check_1(void)
538 {
539 	asm volatile ("					\
540 	call %[bpf_get_prandom_u32];			\
541 	r6 = r0;					\
542 	r6 <<= 32;					\
543 	call %[bpf_get_prandom_u32];			\
544 	r0 |= r6;					\
545 	r0 = le16 r0;					\
546 	r0 >>= 32;					\
547 	exit;						\
548 "	:
549 	: __imm(bpf_get_prandom_u32)
550 	: __clobber_all);
551 }
552 
553 SEC("socket")
554 __description("end32 (to_le) reg zero extend check")
555 __success __success_unpriv __retval(0)
556 __naked void le_reg_zero_extend_check_2(void)
557 {
558 	asm volatile ("					\
559 	call %[bpf_get_prandom_u32];			\
560 	r6 = r0;					\
561 	r6 <<= 32;					\
562 	call %[bpf_get_prandom_u32];			\
563 	r0 |= r6;					\
564 	r0 = le32 r0;					\
565 	r0 >>= 32;					\
566 	exit;						\
567 "	:
568 	: __imm(bpf_get_prandom_u32)
569 	: __clobber_all);
570 }
571 
572 SEC("socket")
573 __description("end16 (to_be) reg zero extend check")
574 __success __success_unpriv __retval(0)
575 __naked void be_reg_zero_extend_check_1(void)
576 {
577 	asm volatile ("					\
578 	call %[bpf_get_prandom_u32];			\
579 	r6 = r0;					\
580 	r6 <<= 32;					\
581 	call %[bpf_get_prandom_u32];			\
582 	r0 |= r6;					\
583 	r0 = be16 r0;					\
584 	r0 >>= 32;					\
585 	exit;						\
586 "	:
587 	: __imm(bpf_get_prandom_u32)
588 	: __clobber_all);
589 }
590 
591 SEC("socket")
592 __description("end32 (to_be) reg zero extend check")
593 __success __success_unpriv __retval(0)
594 __naked void be_reg_zero_extend_check_2(void)
595 {
596 	asm volatile ("					\
597 	call %[bpf_get_prandom_u32];			\
598 	r6 = r0;					\
599 	r6 <<= 32;					\
600 	call %[bpf_get_prandom_u32];			\
601 	r0 |= r6;					\
602 	r0 = be32 r0;					\
603 	r0 >>= 32;					\
604 	exit;						\
605 "	:
606 	: __imm(bpf_get_prandom_u32)
607 	: __clobber_all);
608 }
609 
610 SEC("socket")
611 __description("ldx_b zero extend check")
612 __success __success_unpriv __retval(0)
613 __naked void ldx_b_zero_extend_check(void)
614 {
615 	asm volatile ("					\
616 	r6 = r10;					\
617 	r6 += -4;					\
618 	r7 = 0xfaceb00c;				\
619 	*(u32*)(r6 + 0) = r7;				\
620 	call %[bpf_get_prandom_u32];			\
621 	r1 = 0x1000000000 ll;				\
622 	r0 |= r1;					\
623 	r0 = *(u8*)(r6 + 0);				\
624 	r0 >>= 32;					\
625 	exit;						\
626 "	:
627 	: __imm(bpf_get_prandom_u32)
628 	: __clobber_all);
629 }
630 
631 SEC("socket")
632 __description("ldx_h zero extend check")
633 __success __success_unpriv __retval(0)
634 __naked void ldx_h_zero_extend_check(void)
635 {
636 	asm volatile ("					\
637 	r6 = r10;					\
638 	r6 += -4;					\
639 	r7 = 0xfaceb00c;				\
640 	*(u32*)(r6 + 0) = r7;				\
641 	call %[bpf_get_prandom_u32];			\
642 	r1 = 0x1000000000 ll;				\
643 	r0 |= r1;					\
644 	r0 = *(u16*)(r6 + 0);				\
645 	r0 >>= 32;					\
646 	exit;						\
647 "	:
648 	: __imm(bpf_get_prandom_u32)
649 	: __clobber_all);
650 }
651 
652 SEC("socket")
653 __description("ldx_w zero extend check")
654 __success __success_unpriv __retval(0)
655 __naked void ldx_w_zero_extend_check(void)
656 {
657 	asm volatile ("					\
658 	r6 = r10;					\
659 	r6 += -4;					\
660 	r7 = 0xfaceb00c;				\
661 	*(u32*)(r6 + 0) = r7;				\
662 	call %[bpf_get_prandom_u32];			\
663 	r1 = 0x1000000000 ll;				\
664 	r0 |= r1;					\
665 	r0 = *(u32*)(r6 + 0);				\
666 	r0 >>= 32;					\
667 	exit;						\
668 "	:
669 	: __imm(bpf_get_prandom_u32)
670 	: __clobber_all);
671 }
672 
673 char _license[] SEC("license") = "GPL";
674