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
21SEC("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
38SEC("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
68SEC("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
85SEC("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
109SEC("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
126SEC("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
150SEC("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
167SEC("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
191SEC("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
208SEC("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
232SEC("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
250SEC("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
274SEC("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
292SEC("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
316SEC("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
334SEC("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
358SEC("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
375SEC("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
392SEC("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
416SEC("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
433SEC("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
450SEC("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
468SEC("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
492SEC("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
510SEC("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
534SEC("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
553SEC("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
572SEC("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
591SEC("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
610SEC("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
631SEC("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
652SEC("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
673char _license[] SEC("license") = "GPL";
674