xref: /linux/tools/testing/selftests/bpf/progs/verifier_align.c (revision 0fc8f6200d2313278fbf4539bbab74677c685531)
1f632de6eSEduard Zingerman // SPDX-License-Identifier: GPL-2.0
2f632de6eSEduard Zingerman /* Copyright (c) 2026 Meta Platforms, Inc. and affiliates. */
3f632de6eSEduard Zingerman /* Converted from tools/testing/selftests/bpf/prog_tests/align.c */
4f632de6eSEduard Zingerman 
5f632de6eSEduard Zingerman #include <linux/bpf.h>
6f632de6eSEduard Zingerman #include <bpf/bpf_helpers.h>
7f632de6eSEduard Zingerman #include "bpf_misc.h"
8f632de6eSEduard Zingerman 
9f632de6eSEduard Zingerman /* Four tests of known constants.  These aren't staggeringly
10f632de6eSEduard Zingerman  * interesting since we track exact values now.
11f632de6eSEduard Zingerman  */
12f632de6eSEduard Zingerman 
13f632de6eSEduard Zingerman SEC("tc")
14f632de6eSEduard Zingerman __success __log_level(2)
15f632de6eSEduard Zingerman __flag(BPF_F_ANY_ALIGNMENT)
16f632de6eSEduard Zingerman __msg("0: R1=ctx() R10=fp0")
17f632de6eSEduard Zingerman __msg("0: {{.*}} R3=2")
18f632de6eSEduard Zingerman __msg("1: {{.*}} R3=4")
19f632de6eSEduard Zingerman __msg("2: {{.*}} R3=8")
20f632de6eSEduard Zingerman __msg("3: {{.*}} R3=16")
21f632de6eSEduard Zingerman __msg("4: {{.*}} R3=32")
22f632de6eSEduard Zingerman __naked void mov(void)
23f632de6eSEduard Zingerman {
24f632de6eSEduard Zingerman 	asm volatile ("					\
25f632de6eSEduard Zingerman 	r3 = 2;						\
26f632de6eSEduard Zingerman 	r3 = 4;						\
27f632de6eSEduard Zingerman 	r3 = 8;						\
28f632de6eSEduard Zingerman 	r3 = 16;					\
29f632de6eSEduard Zingerman 	r3 = 32;					\
30f632de6eSEduard Zingerman 	r0 = 0;						\
31f632de6eSEduard Zingerman 	exit;						\
32f632de6eSEduard Zingerman "	::: __clobber_all);
33f632de6eSEduard Zingerman }
34f632de6eSEduard Zingerman 
35f632de6eSEduard Zingerman SEC("tc")
36f632de6eSEduard Zingerman __success __log_level(2)
37f632de6eSEduard Zingerman __flag(BPF_F_ANY_ALIGNMENT)
38f632de6eSEduard Zingerman __msg("0: R1=ctx() R10=fp0")
39f632de6eSEduard Zingerman __msg("0: {{.*}}R3=1")
40f632de6eSEduard Zingerman __msg("1: {{.*}}R3=2")
41f632de6eSEduard Zingerman __msg("2: {{.*}}R3=4")
42f632de6eSEduard Zingerman __msg("3: {{.*}}R3=8")
43f632de6eSEduard Zingerman __msg("4: {{.*}}R3=16")
44f632de6eSEduard Zingerman __msg("5: {{.*}}R3=1")
45f632de6eSEduard Zingerman __msg("6: {{.*}}R4=32")
46f632de6eSEduard Zingerman __msg("7: {{.*}}R4=16")
47f632de6eSEduard Zingerman __msg("8: {{.*}}R4=8")
48f632de6eSEduard Zingerman __msg("9: {{.*}}R4=4")
49f632de6eSEduard Zingerman __msg("10: {{.*}}R4=2")
50f632de6eSEduard Zingerman __naked void shift(void)
51f632de6eSEduard Zingerman {
52f632de6eSEduard Zingerman 	asm volatile ("					\
53f632de6eSEduard Zingerman 	r3 = 1;						\
54f632de6eSEduard Zingerman 	r3 <<= 1;					\
55f632de6eSEduard Zingerman 	r3 <<= 1;					\
56f632de6eSEduard Zingerman 	r3 <<= 1;					\
57f632de6eSEduard Zingerman 	r3 <<= 1;					\
58f632de6eSEduard Zingerman 	r3 >>= 4;					\
59f632de6eSEduard Zingerman 	r4 = 32;					\
60f632de6eSEduard Zingerman 	r4 >>= 1;					\
61f632de6eSEduard Zingerman 	r4 >>= 1;					\
62f632de6eSEduard Zingerman 	r4 >>= 1;					\
63f632de6eSEduard Zingerman 	r4 >>= 1;					\
64f632de6eSEduard Zingerman 	r0 = 0;						\
65f632de6eSEduard Zingerman 	exit;						\
66f632de6eSEduard Zingerman "	::: __clobber_all);
67f632de6eSEduard Zingerman }
68f632de6eSEduard Zingerman 
69f632de6eSEduard Zingerman SEC("tc")
70f632de6eSEduard Zingerman __success __log_level(2)
71f632de6eSEduard Zingerman __flag(BPF_F_ANY_ALIGNMENT)
72f632de6eSEduard Zingerman __msg("0: R1=ctx() R10=fp0")
73f632de6eSEduard Zingerman __msg("0: {{.*}}R3=4")
74f632de6eSEduard Zingerman __msg("1: {{.*}}R3=8")
75f632de6eSEduard Zingerman __msg("2: {{.*}}R3=10")
76f632de6eSEduard Zingerman __msg("3: {{.*}}R4=8")
77f632de6eSEduard Zingerman __msg("4: {{.*}}R4=12")
78f632de6eSEduard Zingerman __msg("5: {{.*}}R4=14")
79f632de6eSEduard Zingerman __naked void addsub(void)
80f632de6eSEduard Zingerman {
81f632de6eSEduard Zingerman 	asm volatile ("					\
82f632de6eSEduard Zingerman 	r3 = 4;						\
83f632de6eSEduard Zingerman 	r3 += 4;					\
84f632de6eSEduard Zingerman 	r3 += 2;					\
85f632de6eSEduard Zingerman 	r4 = 8;						\
86f632de6eSEduard Zingerman 	r4 += 4;					\
87f632de6eSEduard Zingerman 	r4 += 2;					\
88f632de6eSEduard Zingerman 	r0 = 0;						\
89f632de6eSEduard Zingerman 	exit;						\
90f632de6eSEduard Zingerman "	::: __clobber_all);
91f632de6eSEduard Zingerman }
92f632de6eSEduard Zingerman 
93f632de6eSEduard Zingerman SEC("tc")
94f632de6eSEduard Zingerman __success __log_level(2)
95f632de6eSEduard Zingerman __flag(BPF_F_ANY_ALIGNMENT)
96f632de6eSEduard Zingerman __msg("0: R1=ctx() R10=fp0")
97f632de6eSEduard Zingerman __msg("0: {{.*}}R3=7")
98f632de6eSEduard Zingerman __msg("1: {{.*}}R3=7")
99f632de6eSEduard Zingerman __msg("2: {{.*}}R3=14")
100f632de6eSEduard Zingerman __msg("3: {{.*}}R3=56")
101f632de6eSEduard Zingerman __naked void mul(void)
102f632de6eSEduard Zingerman {
103f632de6eSEduard Zingerman 	asm volatile ("					\
104f632de6eSEduard Zingerman 	r3 = 7;						\
105f632de6eSEduard Zingerman 	r3 *= 1;					\
106f632de6eSEduard Zingerman 	r3 *= 2;					\
107f632de6eSEduard Zingerman 	r3 *= 4;					\
108f632de6eSEduard Zingerman 	r0 = 0;						\
109f632de6eSEduard Zingerman 	exit;						\
110f632de6eSEduard Zingerman "	::: __clobber_all);
111f632de6eSEduard Zingerman }
112f632de6eSEduard Zingerman 
113f632de6eSEduard Zingerman /* Tests using unknown values */
114f632de6eSEduard Zingerman 
115f632de6eSEduard Zingerman #define PREP_PKT_POINTERS				\
116f632de6eSEduard Zingerman 	"r2 = *(u32*)(r1 + %[__sk_buff_data]);"		\
117f632de6eSEduard Zingerman 	"r3 = *(u32*)(r1 + %[__sk_buff_data_end]);"
118f632de6eSEduard Zingerman 
119f632de6eSEduard Zingerman #define __LOAD_UNKNOWN(DST_REG, LBL)			\
120f632de6eSEduard Zingerman 	"r2 = *(u32*)(r1 + %[__sk_buff_data]);"		\
121f632de6eSEduard Zingerman 	"r3 = *(u32*)(r1 + %[__sk_buff_data_end]);"	\
122f632de6eSEduard Zingerman 	"r0 = r2;"					\
123f632de6eSEduard Zingerman 	"r0 += 8;"					\
124f632de6eSEduard Zingerman 	"if r3 >= r0 goto " LBL ";"			\
125f632de6eSEduard Zingerman 	"exit;"						\
126f632de6eSEduard Zingerman LBL ":"							\
127f632de6eSEduard Zingerman 	DST_REG " = *(u8*)(r2 + 0);"
128f632de6eSEduard Zingerman 
129f632de6eSEduard Zingerman #define LOAD_UNKNOWN(DST_REG) __LOAD_UNKNOWN(DST_REG, "l99_%=")
130f632de6eSEduard Zingerman 
131f632de6eSEduard Zingerman SEC("tc")
132f632de6eSEduard Zingerman __success __log_level(2)
133f632de6eSEduard Zingerman __flag(BPF_F_ANY_ALIGNMENT)
134*b42eb55fSAlexei Starovoitov __msg("6: {{.*}} R2=pkt(r=8)")
135f632de6eSEduard Zingerman __msg("6: {{.*}} R3={{[^)]*}}var_off=(0x0; 0xff)")
136f632de6eSEduard Zingerman __msg("7: {{.*}} R3={{[^)]*}}var_off=(0x0; 0x1fe)")
137f632de6eSEduard Zingerman __msg("8: {{.*}} R3={{[^)]*}}var_off=(0x0; 0x3fc)")
138f632de6eSEduard Zingerman __msg("9: {{.*}} R3={{[^)]*}}var_off=(0x0; 0x7f8)")
139f632de6eSEduard Zingerman __msg("10: {{.*}} R3={{[^)]*}}var_off=(0x0; 0xff0)")
140f632de6eSEduard Zingerman __msg("12: {{.*}} R3=pkt_end()")
141f632de6eSEduard Zingerman __msg("17: {{.*}} R4={{[^)]*}}var_off=(0x0; 0xff)")
142f632de6eSEduard Zingerman __msg("18: {{.*}} R4={{[^)]*}}var_off=(0x0; 0x1fe0)")
143f632de6eSEduard Zingerman __msg("19: {{.*}} R4={{[^)]*}}var_off=(0x0; 0xff0)")
144f632de6eSEduard Zingerman __msg("20: {{.*}} R4={{[^)]*}}var_off=(0x0; 0x7f8)")
145f632de6eSEduard Zingerman __msg("21: {{.*}} R4={{[^)]*}}var_off=(0x0; 0x3fc)")
146f632de6eSEduard Zingerman __msg("22: {{.*}} R4={{[^)]*}}var_off=(0x0; 0x1fe)")
147f632de6eSEduard Zingerman __naked void unknown_shift(void)
148f632de6eSEduard Zingerman {
149f632de6eSEduard Zingerman 	asm volatile ("					\
150f632de6eSEduard Zingerman 	" __LOAD_UNKNOWN("r3", "l99_%=") "		\
151f632de6eSEduard Zingerman 	r3 <<= 1;					\
152f632de6eSEduard Zingerman 	r3 <<= 1;					\
153f632de6eSEduard Zingerman 	r3 <<= 1;					\
154f632de6eSEduard Zingerman 	r3 <<= 1;					\
155f632de6eSEduard Zingerman 	" __LOAD_UNKNOWN("r4", "l98_%=") "		\
156f632de6eSEduard Zingerman 	r4 <<= 5;					\
157f632de6eSEduard Zingerman 	r4 >>= 1;					\
158f632de6eSEduard Zingerman 	r4 >>= 1;					\
159f632de6eSEduard Zingerman 	r4 >>= 1;					\
160f632de6eSEduard Zingerman 	r4 >>= 1;					\
161f632de6eSEduard Zingerman 	r0 = 0;						\
162f632de6eSEduard Zingerman 	exit;						\
163f632de6eSEduard Zingerman "	:
164f632de6eSEduard Zingerman 	: __imm_const(__sk_buff_data, offsetof(struct __sk_buff, data)),
165f632de6eSEduard Zingerman 	  __imm_const(__sk_buff_data_end, offsetof(struct __sk_buff, data_end))
166f632de6eSEduard Zingerman 	: __clobber_all);
167f632de6eSEduard Zingerman }
168f632de6eSEduard Zingerman 
169f632de6eSEduard Zingerman SEC("tc")
170f632de6eSEduard Zingerman __success __log_level(2)
171f632de6eSEduard Zingerman __flag(BPF_F_ANY_ALIGNMENT)
172f632de6eSEduard Zingerman __msg("6: {{.*}} R3={{[^)]*}}var_off=(0x0; 0xff)")
173f632de6eSEduard Zingerman __msg("7: {{.*}} R4={{[^)]*}}var_off=(0x0; 0xff)")
174f632de6eSEduard Zingerman __msg("8: {{.*}} R4={{[^)]*}}var_off=(0x0; 0xff)")
175f632de6eSEduard Zingerman __msg("9: {{.*}} R4={{[^)]*}}var_off=(0x0; 0xff)")
176f632de6eSEduard Zingerman __msg("10: {{.*}} R4={{[^)]*}}var_off=(0x0; 0x1fe)")
177f632de6eSEduard Zingerman __msg("11: {{.*}} R4={{[^)]*}}var_off=(0x0; 0xff)")
178f632de6eSEduard Zingerman __msg("12: {{.*}} R4={{[^)]*}}var_off=(0x0; 0x3fc)")
179f632de6eSEduard Zingerman __msg("13: {{.*}} R4={{[^)]*}}var_off=(0x0; 0xff)")
180f632de6eSEduard Zingerman __msg("14: {{.*}} R4={{[^)]*}}var_off=(0x0; 0x7f8)")
181f632de6eSEduard Zingerman __msg("15: {{.*}} R4={{[^)]*}}var_off=(0x0; 0xff0)")
182f632de6eSEduard Zingerman __naked void unknown_mul(void)
183f632de6eSEduard Zingerman {
184f632de6eSEduard Zingerman 	asm volatile ("					\
185f632de6eSEduard Zingerman 	" LOAD_UNKNOWN("r3") "				\
186f632de6eSEduard Zingerman 	r4 = r3;					\
187f632de6eSEduard Zingerman 	r4 *= 1;					\
188f632de6eSEduard Zingerman 	r4 = r3;					\
189f632de6eSEduard Zingerman 	r4 *= 2;					\
190f632de6eSEduard Zingerman 	r4 = r3;					\
191f632de6eSEduard Zingerman 	r4 *= 4;					\
192f632de6eSEduard Zingerman 	r4 = r3;					\
193f632de6eSEduard Zingerman 	r4 *= 8;					\
194f632de6eSEduard Zingerman 	r4 *= 2;					\
195f632de6eSEduard Zingerman 	r0 = 0;						\
196f632de6eSEduard Zingerman 	exit;						\
197f632de6eSEduard Zingerman "	:
198f632de6eSEduard Zingerman 	: __imm_const(__sk_buff_data, offsetof(struct __sk_buff, data)),
199f632de6eSEduard Zingerman 	  __imm_const(__sk_buff_data_end, offsetof(struct __sk_buff, data_end))
200f632de6eSEduard Zingerman 	: __clobber_all);
201f632de6eSEduard Zingerman }
202f632de6eSEduard Zingerman 
203f632de6eSEduard Zingerman SEC("tc")
204f632de6eSEduard Zingerman __success __log_level(2)
205f632de6eSEduard Zingerman __msg("2: {{.*}} R5=pkt(r=0)")
206022ac075SEduard Zingerman __msg("4: {{.*}} R5=pkt(r=0,imm=14)")
207022ac075SEduard Zingerman __msg("5: {{.*}} R4=pkt(r=0,imm=14)")
208*b42eb55fSAlexei Starovoitov __msg("9: {{.*}} R5=pkt(r=18,imm=14)")
209022ac075SEduard Zingerman __msg("10: {{.*}} R4={{[^)]*}}var_off=(0x0; 0xff){{.*}} R5=pkt(r=18,imm=14)")
210f632de6eSEduard Zingerman __msg("13: {{.*}} R4={{[^)]*}}var_off=(0x0; 0xffff)")
211f632de6eSEduard Zingerman __msg("14: {{.*}} R4={{[^)]*}}var_off=(0x0; 0xffff)")
212f632de6eSEduard Zingerman __naked void packet_const_offset(void)
213f632de6eSEduard Zingerman {
214f632de6eSEduard Zingerman 	asm volatile ("					\
215f632de6eSEduard Zingerman 	" PREP_PKT_POINTERS "				\
216f632de6eSEduard Zingerman 	r5 = r2;					\
217f632de6eSEduard Zingerman 	r0 = 0;						\
218f632de6eSEduard Zingerman 	/* Skip over ethernet header.  */		\
219f632de6eSEduard Zingerman 	r5 += 14;					\
220f632de6eSEduard Zingerman 	r4 = r5;					\
221f632de6eSEduard Zingerman 	r4 += 4;					\
222f632de6eSEduard Zingerman 	if r3 >= r4 goto l0_%=;				\
223f632de6eSEduard Zingerman 	exit;						\
224f632de6eSEduard Zingerman l0_%=:	r4 = *(u8*)(r5 + 0);				\
225f632de6eSEduard Zingerman 	r4 = *(u8*)(r5 + 1);				\
226f632de6eSEduard Zingerman 	r4 = *(u8*)(r5 + 2);				\
227f632de6eSEduard Zingerman 	r4 = *(u8*)(r5 + 3);				\
228f632de6eSEduard Zingerman 	r4 = *(u16*)(r5 + 0);				\
229f632de6eSEduard Zingerman 	r4 = *(u16*)(r5 + 2);				\
230f632de6eSEduard Zingerman 	r4 = *(u32*)(r5 + 0);				\
231f632de6eSEduard Zingerman 	r0 = 0;						\
232f632de6eSEduard Zingerman 	exit;						\
233f632de6eSEduard Zingerman "	:
234f632de6eSEduard Zingerman 	: __imm_const(__sk_buff_data, offsetof(struct __sk_buff, data)),
235f632de6eSEduard Zingerman 	  __imm_const(__sk_buff_data_end, offsetof(struct __sk_buff, data_end))
236f632de6eSEduard Zingerman 	: __clobber_all);
237f632de6eSEduard Zingerman }
238f632de6eSEduard Zingerman 
239f632de6eSEduard Zingerman SEC("tc")
240f632de6eSEduard Zingerman __success __log_level(2)
241f632de6eSEduard Zingerman __flag(BPF_F_ANY_ALIGNMENT)
242f632de6eSEduard Zingerman /* Calculated offset in R6 has unknown value, but known
243f632de6eSEduard Zingerman  * alignment of 4.
244f632de6eSEduard Zingerman  */
245f632de6eSEduard Zingerman __msg("6: {{.*}} R2=pkt(r=8)")
246f632de6eSEduard Zingerman __msg("7: {{.*}} R6={{[^)]*}}var_off=(0x0; 0x3fc)")
247f632de6eSEduard Zingerman /* Offset is added to packet pointer R5, resulting in
248f632de6eSEduard Zingerman  * known fixed offset, and variable offset from R6.
249f632de6eSEduard Zingerman  */
250022ac075SEduard Zingerman __msg("11: {{.*}} R5=pkt(id=1,{{[^)]*}},var_off=(0x2; 0x7fc)")
251f632de6eSEduard Zingerman /* At the time the word size load is performed from R5,
252f632de6eSEduard Zingerman  * it's total offset is NET_IP_ALIGN + reg->off (0) +
253f632de6eSEduard Zingerman  * reg->aux_off (14) which is 16.  Then the variable
254f632de6eSEduard Zingerman  * offset is considered using reg->aux_off_align which
255f632de6eSEduard Zingerman  * is 4 and meets the load's requirements.
256f632de6eSEduard Zingerman  */
257*b42eb55fSAlexei Starovoitov __msg("15: {{.*}} R5={{[^)]*}}var_off=(0x2; 0x7fc)")
258f632de6eSEduard Zingerman /* Variable offset is added to R5 packet pointer,
259f632de6eSEduard Zingerman  * resulting in auxiliary alignment of 4. To avoid BPF
260f632de6eSEduard Zingerman  * verifier's precision backtracking logging
261f632de6eSEduard Zingerman  * interfering we also have a no-op R4 = R5
262f632de6eSEduard Zingerman  * instruction to validate R5 state. We also check
263f632de6eSEduard Zingerman  * that R4 is what it should be in such case.
264f632de6eSEduard Zingerman  */
265f632de6eSEduard Zingerman __msg("18: {{.*}} R4={{[^)]*}}var_off=(0x0; 0x3fc){{.*}} R5={{[^)]*}}var_off=(0x0; 0x3fc)")
266f632de6eSEduard Zingerman /* Constant offset is added to R5, resulting in
267f632de6eSEduard Zingerman  * reg->off of 14.
268f632de6eSEduard Zingerman  */
269022ac075SEduard Zingerman __msg("19: {{.*}} R5=pkt(id=2,{{[^)]*}}var_off=(0x2; 0x7fc)")
270f632de6eSEduard Zingerman /* At the time the word size load is performed from R5,
271f632de6eSEduard Zingerman  * its total fixed offset is NET_IP_ALIGN + reg->off
272f632de6eSEduard Zingerman  * (14) which is 16.  Then the variable offset is 4-byte
273f632de6eSEduard Zingerman  * aligned, so the total offset is 4-byte aligned and
274f632de6eSEduard Zingerman  * meets the load's requirements.
275f632de6eSEduard Zingerman  */
276*b42eb55fSAlexei Starovoitov __msg("24: {{.*}} R5={{[^)]*}}var_off=(0x2; 0x7fc)")
277f632de6eSEduard Zingerman /* Constant offset is added to R5 packet pointer,
278f632de6eSEduard Zingerman  * resulting in reg->off value of 14.
279f632de6eSEduard Zingerman  */
280022ac075SEduard Zingerman __msg("26: {{.*}} R5=pkt(r=8,imm=14)")
281f632de6eSEduard Zingerman /* Variable offset is added to R5, resulting in a
282f632de6eSEduard Zingerman  * variable offset of (4n). See comment for insn #18
283f632de6eSEduard Zingerman  * for R4 = R5 trick.
284f632de6eSEduard Zingerman  */
285022ac075SEduard Zingerman __msg("28: {{.*}} R4={{[^)]*}}var_off=(0x2; 0x7fc){{.*}} R5={{[^)]*}}var_off=(0x2; 0x7fc)")
286f632de6eSEduard Zingerman /* Constant is added to R5 again, setting reg->off to 18. */
287022ac075SEduard Zingerman __msg("29: {{.*}} R5=pkt(id=3,{{[^)]*}}var_off=(0x2; 0x7fc)")
288f632de6eSEduard Zingerman /* And once more we add a variable; resulting {{[^)]*}}var_off
289f632de6eSEduard Zingerman  * is still (4n), fixed offset is not changed.
290f632de6eSEduard Zingerman  * Also, we create a new reg->id.
291f632de6eSEduard Zingerman  */
292022ac075SEduard Zingerman __msg("31: {{.*}} R4={{[^)]*}}var_off=(0x2; 0xffc){{.*}} R5={{[^)]*}}var_off=(0x2; 0xffc)")
293f632de6eSEduard Zingerman /* At the time the word size load is performed from R5,
294f632de6eSEduard Zingerman  * its total fixed offset is NET_IP_ALIGN + reg->off (18)
295f632de6eSEduard Zingerman  * which is 20.  Then the variable offset is (4n), so
296f632de6eSEduard Zingerman  * the total offset is 4-byte aligned and meets the
297f632de6eSEduard Zingerman  * load's requirements.
298f632de6eSEduard Zingerman  */
299*b42eb55fSAlexei Starovoitov __msg("35: {{.*}} R5={{[^)]*}}var_off=(0x2; 0xffc)")
300f632de6eSEduard Zingerman __naked void packet_variable_offset(void)
301f632de6eSEduard Zingerman {
302f632de6eSEduard Zingerman 	asm volatile ("					\
303f632de6eSEduard Zingerman 	" LOAD_UNKNOWN("r6") "				\
304f632de6eSEduard Zingerman 	r6 <<= 2;					\
305f632de6eSEduard Zingerman 	/* First, add a constant to the R5 packet pointer,\
306f632de6eSEduard Zingerman 	 * then a variable with a known alignment.	\
307f632de6eSEduard Zingerman 	 */						\
308f632de6eSEduard Zingerman 	r5 = r2;					\
309f632de6eSEduard Zingerman 	r5 += 14;					\
310f632de6eSEduard Zingerman 	r5 += r6;					\
311f632de6eSEduard Zingerman 	r4 = r5;					\
312f632de6eSEduard Zingerman 	r4 += 4;					\
313f632de6eSEduard Zingerman 	if r3 >= r4 goto l0_%=;				\
314f632de6eSEduard Zingerman 	exit;						\
315f632de6eSEduard Zingerman l0_%=:	r4 = *(u32*)(r5 + 0);				\
316f632de6eSEduard Zingerman 	/* Now, test in the other direction.  Adding first\
317f632de6eSEduard Zingerman 	 * the variable offset to R5, then the constant.\
318f632de6eSEduard Zingerman 	 */						\
319f632de6eSEduard Zingerman 	r5 = r2;					\
320f632de6eSEduard Zingerman 	r5 += r6;					\
321f632de6eSEduard Zingerman 	r4 = r5;					\
322f632de6eSEduard Zingerman 	r5 += 14;					\
323f632de6eSEduard Zingerman 	r4 = r5;					\
324f632de6eSEduard Zingerman 	r4 += 4;					\
325f632de6eSEduard Zingerman 	if r3 >= r4 goto l1_%=;				\
326f632de6eSEduard Zingerman 	exit;						\
327f632de6eSEduard Zingerman l1_%=:	r4 = *(u32*)(r5 + 0);				\
328f632de6eSEduard Zingerman 	/* Test multiple accumulations of unknown values\
329f632de6eSEduard Zingerman 	 * into a packet pointer.			\
330f632de6eSEduard Zingerman 	 */						\
331f632de6eSEduard Zingerman 	r5 = r2;					\
332f632de6eSEduard Zingerman 	r5 += 14;					\
333f632de6eSEduard Zingerman 	r5 += r6;					\
334f632de6eSEduard Zingerman 	r4 = r5;					\
335f632de6eSEduard Zingerman 	r5 += 4;					\
336f632de6eSEduard Zingerman 	r5 += r6;					\
337f632de6eSEduard Zingerman 	r4 = r5;					\
338f632de6eSEduard Zingerman 	r4 += 4;					\
339f632de6eSEduard Zingerman 	if r3 >= r4 goto l2_%=;				\
340f632de6eSEduard Zingerman 	exit;						\
341f632de6eSEduard Zingerman l2_%=:	r4 = *(u32*)(r5 + 0);				\
342f632de6eSEduard Zingerman 	r0 = 0;						\
343f632de6eSEduard Zingerman 	exit;						\
344f632de6eSEduard Zingerman "	:
345f632de6eSEduard Zingerman 	: __imm_const(__sk_buff_data, offsetof(struct __sk_buff, data)),
346f632de6eSEduard Zingerman 	  __imm_const(__sk_buff_data_end, offsetof(struct __sk_buff, data_end))
347f632de6eSEduard Zingerman 	: __clobber_all);
348f632de6eSEduard Zingerman }
349f632de6eSEduard Zingerman 
350f632de6eSEduard Zingerman SEC("tc")
351f632de6eSEduard Zingerman __success __log_level(2)
352f632de6eSEduard Zingerman __flag(BPF_F_ANY_ALIGNMENT)
353f632de6eSEduard Zingerman /* Calculated offset in R6 has unknown value, but known
354f632de6eSEduard Zingerman  * alignment of 4.
355f632de6eSEduard Zingerman  */
356f632de6eSEduard Zingerman __msg("6: {{.*}} R2=pkt(r=8)")
357f632de6eSEduard Zingerman __msg("7: {{.*}} R6={{[^)]*}}var_off=(0x0; 0x3fc)")
358f632de6eSEduard Zingerman /* Adding 14 makes R6 be (4n+2) */
359f632de6eSEduard Zingerman __msg("8: {{.*}} R6={{[^)]*}}var_off=(0x2; 0x7fc)")
360f632de6eSEduard Zingerman /* Packet pointer has (4n+2) offset */
361f632de6eSEduard Zingerman __msg("11: {{.*}} R5={{[^)]*}}var_off=(0x2; 0x7fc)")
362f632de6eSEduard Zingerman __msg("12: {{.*}} R4={{[^)]*}}var_off=(0x2; 0x7fc)")
363f632de6eSEduard Zingerman /* At the time the word size load is performed from R5,
364f632de6eSEduard Zingerman  * its total fixed offset is NET_IP_ALIGN + reg->off (0)
365f632de6eSEduard Zingerman  * which is 2.  Then the variable offset is (4n+2), so
366f632de6eSEduard Zingerman  * the total offset is 4-byte aligned and meets the
367f632de6eSEduard Zingerman  * load's requirements.
368f632de6eSEduard Zingerman  */
369f632de6eSEduard Zingerman __msg("15: {{.*}} R5={{[^)]*}}var_off=(0x2; 0x7fc)")
370f632de6eSEduard Zingerman /* Newly read value in R6 was shifted left by 2, so has
371f632de6eSEduard Zingerman  * known alignment of 4.
372f632de6eSEduard Zingerman  */
373f632de6eSEduard Zingerman __msg("17: {{.*}} R6={{[^)]*}}var_off=(0x0; 0x3fc)")
374f632de6eSEduard Zingerman /* Added (4n) to packet pointer's (4n+2) {{[^)]*}}var_off, giving
375f632de6eSEduard Zingerman  * another (4n+2).
376f632de6eSEduard Zingerman  */
377f632de6eSEduard Zingerman __msg("19: {{.*}} R5={{[^)]*}}var_off=(0x2; 0xffc)")
378f632de6eSEduard Zingerman __msg("20: {{.*}} R4={{[^)]*}}var_off=(0x2; 0xffc)")
379f632de6eSEduard Zingerman /* At the time the word size load is performed from R5,
380f632de6eSEduard Zingerman  * its total fixed offset is NET_IP_ALIGN + reg->off (0)
381f632de6eSEduard Zingerman  * which is 2.  Then the variable offset is (4n+2), so
382f632de6eSEduard Zingerman  * the total offset is 4-byte aligned and meets the
383f632de6eSEduard Zingerman  * load's requirements.
384f632de6eSEduard Zingerman  */
385f632de6eSEduard Zingerman __msg("23: {{.*}} R5={{[^)]*}}var_off=(0x2; 0xffc)")
386f632de6eSEduard Zingerman __naked void packet_variable_offset_2(void)
387f632de6eSEduard Zingerman {
388f632de6eSEduard Zingerman 	asm volatile ("					\
389f632de6eSEduard Zingerman 	/* Create an unknown offset, (4n+2)-aligned */	\
390f632de6eSEduard Zingerman 	" LOAD_UNKNOWN("r6") "			\
391f632de6eSEduard Zingerman 	r6 <<= 2;					\
392f632de6eSEduard Zingerman 	r6 += 14;					\
393f632de6eSEduard Zingerman 	/* Add it to the packet pointer */		\
394f632de6eSEduard Zingerman 	r5 = r2;					\
395f632de6eSEduard Zingerman 	r5 += r6;					\
396f632de6eSEduard Zingerman 	/* Check bounds and perform a read */		\
397f632de6eSEduard Zingerman 	r4 = r5;					\
398f632de6eSEduard Zingerman 	r4 += 4;					\
399f632de6eSEduard Zingerman 	if r3 >= r4 goto l0_%=;				\
400f632de6eSEduard Zingerman 	exit;						\
401f632de6eSEduard Zingerman l0_%=:	r6 = *(u32*)(r5 + 0);				\
402f632de6eSEduard Zingerman 	/* Make a (4n) offset from the value we just read */\
403f632de6eSEduard Zingerman 	r6 &= 0xff;					\
404f632de6eSEduard Zingerman 	r6 <<= 2;					\
405f632de6eSEduard Zingerman 	/* Add it to the packet pointer */		\
406f632de6eSEduard Zingerman 	r5 += r6;					\
407f632de6eSEduard Zingerman 	/* Check bounds and perform a read */		\
408f632de6eSEduard Zingerman 	r4 = r5;					\
409f632de6eSEduard Zingerman 	r4 += 4;					\
410f632de6eSEduard Zingerman 	if r3 >= r4 goto l1_%=;				\
411f632de6eSEduard Zingerman 	exit;						\
412f632de6eSEduard Zingerman l1_%=:	r6 = *(u32*)(r5 + 0);				\
413f632de6eSEduard Zingerman 	r0 = 0;						\
414f632de6eSEduard Zingerman 	exit;						\
415f632de6eSEduard Zingerman "	:
416f632de6eSEduard Zingerman 	: __imm_const(__sk_buff_data, offsetof(struct __sk_buff, data)),
417f632de6eSEduard Zingerman 	  __imm_const(__sk_buff_data_end, offsetof(struct __sk_buff, data_end))
418f632de6eSEduard Zingerman 	: __clobber_all);
419f632de6eSEduard Zingerman }
420f632de6eSEduard Zingerman 
421f632de6eSEduard Zingerman SEC("tc")
422f632de6eSEduard Zingerman __failure __log_level(2)
423f632de6eSEduard Zingerman __msg("3: {{.*}} R5=pkt_end()")
424f632de6eSEduard Zingerman /* (ptr - ptr) << 2 == unknown, (4n) */
425f632de6eSEduard Zingerman __msg("5: {{.*}} R5={{[^)]*}}var_off=(0x0; 0xfffffffffffffffc)")
426f632de6eSEduard Zingerman /* (4n) + 14 == (4n+2).  We blow our bounds, because
427f632de6eSEduard Zingerman  * the add could overflow.
428f632de6eSEduard Zingerman  */
429f632de6eSEduard Zingerman __msg("6: {{.*}} R5={{[^)]*}}var_off=(0x2; 0xfffffffffffffffc)")
430f632de6eSEduard Zingerman /* Checked s>=0 */
431f632de6eSEduard Zingerman __msg("9: {{.*}} R5={{[^)]*}}var_off=(0x2; 0x7ffffffffffffffc)")
432f632de6eSEduard Zingerman /* packet pointer + nonnegative (4n+2) */
433022ac075SEduard Zingerman __msg("11: {{.*}} R4={{[^)]*}}var_off=(0x2; 0x7ffffffffffffffc){{.*}} R6={{[^)]*}}var_off=(0x2; 0x7ffffffffffffffc)")
434022ac075SEduard Zingerman __msg("12: (07) r4 += 4")
435022ac075SEduard Zingerman /* packet smax bound overflow */
436022ac075SEduard Zingerman __msg("pkt pointer offset -9223372036854775808 is not allowed")
437f632de6eSEduard Zingerman __naked void dubious_pointer_arithmetic(void)
438f632de6eSEduard Zingerman {
439f632de6eSEduard Zingerman 	asm volatile ("					\
440f632de6eSEduard Zingerman 	" PREP_PKT_POINTERS "				\
441f632de6eSEduard Zingerman 	r0 = 0;						\
442f632de6eSEduard Zingerman 	/* (ptr - ptr) << 2 */				\
443f632de6eSEduard Zingerman 	r5 = r3;					\
444f632de6eSEduard Zingerman 	r5 -= r2;					\
445f632de6eSEduard Zingerman 	r5 <<= 2;					\
446f632de6eSEduard Zingerman 	/* We have a (4n) value.  Let's make a packet offset\
447f632de6eSEduard Zingerman 	 * out of it.  First add 14, to make it a (4n+2)\
448f632de6eSEduard Zingerman 	 */						\
449f632de6eSEduard Zingerman 	r5 += 14;					\
450f632de6eSEduard Zingerman 	/* Then make sure it's nonnegative */		\
451f632de6eSEduard Zingerman 	if r5 s>= 0 goto l0_%=;				\
452f632de6eSEduard Zingerman 	exit;						\
453f632de6eSEduard Zingerman l0_%=:	/* Add it to packet pointer */			\
454f632de6eSEduard Zingerman 	r6 = r2;					\
455f632de6eSEduard Zingerman 	r6 += r5;					\
456f632de6eSEduard Zingerman 	/* Check bounds and perform a read */		\
457f632de6eSEduard Zingerman 	r4 = r6;					\
458f632de6eSEduard Zingerman 	r4 += 4;					\
459f632de6eSEduard Zingerman 	if r3 >= r4 goto l1_%=;				\
460f632de6eSEduard Zingerman 	exit;						\
461f632de6eSEduard Zingerman l1_%=:	r4 = *(u32*)(r6 + 0);				\
462f632de6eSEduard Zingerman 	exit;						\
463f632de6eSEduard Zingerman "	:
464f632de6eSEduard Zingerman 	: __imm_const(__sk_buff_data, offsetof(struct __sk_buff, data)),
465f632de6eSEduard Zingerman 	  __imm_const(__sk_buff_data_end, offsetof(struct __sk_buff, data_end))
466f632de6eSEduard Zingerman 	: __clobber_all);
467f632de6eSEduard Zingerman }
468f632de6eSEduard Zingerman 
469f632de6eSEduard Zingerman SEC("tc")
470f632de6eSEduard Zingerman __success __log_level(2)
471f632de6eSEduard Zingerman __flag(BPF_F_ANY_ALIGNMENT)
472f632de6eSEduard Zingerman /* Calculated offset in R6 has unknown value, but known
473f632de6eSEduard Zingerman  * alignment of 4.
474f632de6eSEduard Zingerman  */
475f632de6eSEduard Zingerman __msg("6: {{.*}} R2=pkt(r=8)")
476f632de6eSEduard Zingerman __msg("8: {{.*}} R6={{[^)]*}}var_off=(0x0; 0x3fc)")
477f632de6eSEduard Zingerman /* Adding 14 makes R6 be (4n+2) */
478f632de6eSEduard Zingerman __msg("9: {{.*}} R6={{[^)]*}}var_off=(0x2; 0x7fc)")
479f632de6eSEduard Zingerman /* New unknown value in R7 is (4n) */
480f632de6eSEduard Zingerman __msg("10: {{.*}} R7={{[^)]*}}var_off=(0x0; 0x3fc)")
481f632de6eSEduard Zingerman /* Subtracting it from R6 blows our unsigned bounds */
482f632de6eSEduard Zingerman __msg("11: {{.*}} R6={{[^)]*}}var_off=(0x2; 0xfffffffffffffffc)")
483f632de6eSEduard Zingerman /* Checked s>= 0 */
484f632de6eSEduard Zingerman __msg("14: {{.*}} R6={{[^)]*}}var_off=(0x2; 0x7fc)")
485f632de6eSEduard Zingerman /* At the time the word size load is performed from R5,
486f632de6eSEduard Zingerman  * its total fixed offset is NET_IP_ALIGN + reg->off (0)
487f632de6eSEduard Zingerman  * which is 2.  Then the variable offset is (4n+2), so
488f632de6eSEduard Zingerman  * the total offset is 4-byte aligned and meets the
489f632de6eSEduard Zingerman  * load's requirements.
490f632de6eSEduard Zingerman  */
491f632de6eSEduard Zingerman __msg("20: {{.*}} R5={{[^)]*}}var_off=(0x2; 0x7fc)")
492f632de6eSEduard Zingerman __naked void variable_subtraction(void)
493f632de6eSEduard Zingerman {
494f632de6eSEduard Zingerman 	asm volatile ("					\
495f632de6eSEduard Zingerman 	/* Create an unknown offset, (4n+2)-aligned */	\
496f632de6eSEduard Zingerman 	" LOAD_UNKNOWN("r6") "				\
497f632de6eSEduard Zingerman 	r7 = r6;					\
498f632de6eSEduard Zingerman 	r6 <<= 2;					\
499f632de6eSEduard Zingerman 	r6 += 14;					\
500f632de6eSEduard Zingerman 	/* Create another unknown, (4n)-aligned, and subtract\
501f632de6eSEduard Zingerman 	 * it from the first one			\
502f632de6eSEduard Zingerman 	 */						\
503f632de6eSEduard Zingerman 	r7 <<= 2;					\
504f632de6eSEduard Zingerman 	r6 -= r7;					\
505f632de6eSEduard Zingerman 	/* Bounds-check the result */			\
506f632de6eSEduard Zingerman 	if r6 s>= 0 goto l0_%=;				\
507f632de6eSEduard Zingerman 	exit;						\
508f632de6eSEduard Zingerman l0_%=:	/* Add it to the packet pointer */		\
509f632de6eSEduard Zingerman 	r5 = r2;					\
510f632de6eSEduard Zingerman 	r5 += r6;					\
511f632de6eSEduard Zingerman 	/* Check bounds and perform a read */		\
512f632de6eSEduard Zingerman 	r4 = r5;					\
513f632de6eSEduard Zingerman 	r4 += 4;					\
514f632de6eSEduard Zingerman 	if r3 >= r4 goto l1_%=;				\
515f632de6eSEduard Zingerman 	exit;						\
516f632de6eSEduard Zingerman l1_%=:	r6 = *(u32*)(r5 + 0);				\
517f632de6eSEduard Zingerman 	exit;						\
518f632de6eSEduard Zingerman "	:
519f632de6eSEduard Zingerman 	: __imm_const(__sk_buff_data, offsetof(struct __sk_buff, data)),
520f632de6eSEduard Zingerman 	  __imm_const(__sk_buff_data_end, offsetof(struct __sk_buff, data_end))
521f632de6eSEduard Zingerman 	: __clobber_all);
522f632de6eSEduard Zingerman }
523f632de6eSEduard Zingerman 
524f632de6eSEduard Zingerman SEC("tc")
525f632de6eSEduard Zingerman __success __log_level(2)
526f632de6eSEduard Zingerman __flag(BPF_F_ANY_ALIGNMENT)
527f632de6eSEduard Zingerman /* Calculated offset in R6 has unknown value, but known
528f632de6eSEduard Zingerman  * alignment of 4.
529f632de6eSEduard Zingerman  */
530f632de6eSEduard Zingerman __msg("6: {{.*}} R2=pkt(r=8)")
531f632de6eSEduard Zingerman __msg("9: {{.*}} R6={{[^)]*}}var_off=(0x0; 0x3c)")
532f632de6eSEduard Zingerman /* Adding 14 makes R6 be (4n+2) */
533f632de6eSEduard Zingerman __msg("10: {{.*}} R6={{[^)]*}}var_off=(0x2; 0x7c)")
534f632de6eSEduard Zingerman /* Subtracting from packet pointer overflows ubounds */
535f632de6eSEduard Zingerman __msg("13: R5={{[^)]*}}var_off=(0xffffffffffffff82; 0x7c)")
536f632de6eSEduard Zingerman /* New unknown value in R7 is (4n), >= 76 */
537f632de6eSEduard Zingerman __msg("14: {{.*}} R7={{[^)]*}}var_off=(0x0; 0x7fc)")
538f632de6eSEduard Zingerman /* Adding it to packet pointer gives nice bounds again */
539f632de6eSEduard Zingerman __msg("16: {{.*}} R5={{[^)]*}}var_off=(0x2; 0x7fc)")
540f632de6eSEduard Zingerman /* At the time the word size load is performed from R5,
541f632de6eSEduard Zingerman  * its total fixed offset is NET_IP_ALIGN + reg->off (0)
542f632de6eSEduard Zingerman  * which is 2.  Then the variable offset is (4n+2), so
543f632de6eSEduard Zingerman  * the total offset is 4-byte aligned and meets the
544f632de6eSEduard Zingerman  * load's requirements.
545f632de6eSEduard Zingerman  */
546f632de6eSEduard Zingerman __msg("20: {{.*}} R5={{[^)]*}}var_off=(0x2; 0x7fc)")
547f632de6eSEduard Zingerman __naked void pointer_variable_subtraction(void)
548f632de6eSEduard Zingerman {
549f632de6eSEduard Zingerman 	asm volatile ("					\
550f632de6eSEduard Zingerman 	/* Create an unknown offset, (4n+2)-aligned and bounded\
551f632de6eSEduard Zingerman 	 * to [14,74]					\
552f632de6eSEduard Zingerman 	 */						\
553f632de6eSEduard Zingerman 	" LOAD_UNKNOWN("r6") "				\
554f632de6eSEduard Zingerman 	r7 = r6;					\
555f632de6eSEduard Zingerman 	r6 &= 0xf;					\
556f632de6eSEduard Zingerman 	r6 <<= 2;					\
557f632de6eSEduard Zingerman 	r6 += 14;					\
558f632de6eSEduard Zingerman 	/* Subtract it from the packet pointer */	\
559f632de6eSEduard Zingerman 	r5 = r2;					\
560f632de6eSEduard Zingerman 	r5 -= r6;					\
561f632de6eSEduard Zingerman 	/* Create another unknown, (4n)-aligned and >= 74.\
562f632de6eSEduard Zingerman 	 * That in fact means >= 76, since 74 mod 4 == 2\
563f632de6eSEduard Zingerman 	 */						\
564f632de6eSEduard Zingerman 	r7 <<= 2;					\
565f632de6eSEduard Zingerman 	r7 += 76;					\
566f632de6eSEduard Zingerman 	/* Add it to the packet pointer */		\
567f632de6eSEduard Zingerman 	r5 += r7;					\
568f632de6eSEduard Zingerman 	/* Check bounds and perform a read */		\
569f632de6eSEduard Zingerman 	r4 = r5;					\
570f632de6eSEduard Zingerman 	r4 += 4;					\
571f632de6eSEduard Zingerman 	if r3 >= r4 goto l0_%=;				\
572f632de6eSEduard Zingerman 	exit;						\
573f632de6eSEduard Zingerman l0_%=:	r6 = *(u32*)(r5 + 0);				\
574f632de6eSEduard Zingerman 	exit;						\
575f632de6eSEduard Zingerman "	:
576f632de6eSEduard Zingerman 	: __imm_const(__sk_buff_data, offsetof(struct __sk_buff, data)),
577f632de6eSEduard Zingerman 	  __imm_const(__sk_buff_data_end, offsetof(struct __sk_buff, data_end))
578f632de6eSEduard Zingerman 	: __clobber_all);
579f632de6eSEduard Zingerman }
580f632de6eSEduard Zingerman 
581f632de6eSEduard Zingerman char _license[] SEC("license") = "GPL";
582