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