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