Linux内核5.10验证者拒绝EBPF XDP程序,该程序适合内核5.13

发布于 2025-02-06 04:54:17 字数 6796 浏览 3 评论 0 原文

我使用REDBPF在Rust中编写了一些EBPF程序,并且我遇到了仅在某些内核上出现的验证者的问题。

这是一个最小的复制器XDP探测器,显示了该问题:

#[xdp]
unsafe fn xdp_test(ctx: XdpContext) -> XdpResult {
    let data = ctx.data()?;
    let start = ctx.data_start();
    let off = data.offset();
    let end = ctx.data_end();

    /* Ensuring an upper bound for off doesn't make any difference
    if off > 50 {
        return XdpResult::Err(OutOfBounds);
    }
    */

    let mut address = start + off;
    for i in 0..500 {
        address = start + off + i;
        if address <= start || address >= end {
            break;
        }

        // This line (packet access) fails on kernel 5.10, but works fine on 5.13
        let byte = *(address as *const u8);
        // Just so the packet read above doesn't get optimized away
        printk!("%u", byte as u32);
    }

    Ok(XdpAction::Pass)
}

将其编译到EBPF字节码中并将其加载到Ubuntu 5.13内核中( 5.13.0-48总计#54〜20.04.14.1-144.1-ubuntu smp smp thu Jun Jun Jun 2 23: 37:17 UTC 2022 x86_64 x86_64 x86_64 gnu/linux )无问题。验证者接受该程序。

但是,尝试将完全相同的字节码加载到Android模拟器内核 5.10.66-android12-9-00041-GFA9C9074531E-AB7914766#1 SMP 1 SMP Preempt Preempt Fri Nov Fri Nov 12 11:36:25 UTC 2021 X86_64 验证者拒绝该程序。这是来自验证者的完整错误日志:

ret=-1 os error=Permission denied (os error 13): 0: (61) r6 = *(u32 *)(r1 +4)
1: (61) r7 = *(u32 *)(r1 +0)
2: (bf) r1 = r7
3: (07) r1 += 14
4: (2d) if r1 > r6 goto pc+43
 R1_w=pkt(id=0,off=14,r=14,imm=0) R6_w=pkt_end(id=0,off=0,imm=0) R7_w=pkt(id=0,off=0,r=14,imm=0) R10=fp0
5: (71) r2 = *(u8 *)(r7 +13)
6: (67) r2 <<= 8
7: (71) r3 = *(u8 *)(r7 +12)
8: (4f) r2 |= r3
9: (55) if r2 != 0x8 goto pc+38
 R1_w=pkt(id=0,off=14,r=14,imm=0) R2_w=inv8 R3_w=inv(id=0,umax_value=255,var_off=(0x0; 0xff)) R6_w=pkt_end(id=0,off=0,imm=0) R7_w=pkt(id=0,off=0,r=14,imm=0) R10=fp0
10: (bf) r2 = r7
11: (07) r2 += 34
12: (2d) if r2 > r6 goto pc+35
 R1=pkt(id=0,off=14,r=34,imm=0) R2=pkt(id=0,off=34,r=34,imm=0) R3=inv(id=0,umax_value=255,var_off=(0x0; 0xff)) R6=pkt_end(id=0,off=0,imm=0) R7=pkt(id=0,off=0,r=34,imm=0) R10=fp0
13: (71) r3 = *(u8 *)(r1 +0)
14: (67) r3 <<= 2
15: (57) r3 &= 60
16: (71) r2 = *(u8 *)(r1 +9)
17: (0f) r1 += r3
last_idx 17 first_idx 12
regs=8 stack=0 before 16: (71) r2 = *(u8 *)(r1 +9)
regs=8 stack=0 before 15: (57) r3 &= 60
regs=8 stack=0 before 14: (67) r3 <<= 2
regs=8 stack=0 before 13: (71) r3 = *(u8 *)(r1 +0)
18: (15) if r2 == 0x11 goto pc+31
 R1_w=pkt(id=1,off=14,r=0,umax_value=60,var_off=(0x0; 0x3c)) R2_w=inv(id=0,umax_value=255,var_off=(0x0; 0xff)) R3_w=invP(id=0,umax_value=60,var_off=(0x0; 0x3c)) R6=pkt_end(id=0,off=0,imm=0) R7=pkt(id=0,off=0,r=34,imm=0) R10=fp0
19: (55) if r2 != 0x6 goto pc+28
 R1_w=pkt(id=1,off=14,r=0,umax_value=60,var_off=(0x0; 0x3c)) R2_w=inv6 R3_w=invP(id=0,umax_value=60,var_off=(0x0; 0x3c)) R6=pkt_end(id=0,off=0,imm=0) R7=pkt(id=0,off=0,r=34,imm=0) R10=fp0
20: (2d) if r7 > r1 goto pc+27
 R1=pkt(id=1,off=14,r=0,umax_value=60,var_off=(0x0; 0x3c)) R2=inv6 R3=invP(id=0,umax_value=60,var_off=(0x0; 0x3c)) R6=pkt_end(id=0,off=0,imm=0) R7=pkt(id=0,off=0,r=34,imm=0) R10=fp0
21: (bf) r2 = r1
22: (07) r2 += 20
23: (2d) if r2 > r6 goto pc+24
 R1=pkt(id=1,off=14,r=34,umax_value=60,var_off=(0x0; 0x3c)) R2_w=pkt(id=1,off=34,r=34,umax_value=60,var_off=(0x0; 0x3c)) R3=invP(id=0,umax_value=60,var_off=(0x0; 0x3c)) R6=pkt_end(id=0,off=0,imm=0) R7=pkt(id=0,off=0,r=34,imm=0) R10=fp0
24: (71) r2 = *(u8 *)(r1 +12)
25: (77) r2 >>= 2
26: (57) r2 &= 60
27: (0f) r1 += r2
last_idx 27 first_idx 20
regs=4 stack=0 before 26: (57) r2 &= 60
regs=4 stack=0 before 25: (77) r2 >>= 2
regs=4 stack=0 before 24: (71) r2 = *(u8 *)(r1 +12)
28: (2d) if r7 > r1 goto pc+19
 R1=pkt(id=2,off=14,r=0,umax_value=120,var_off=(0x0; 0x7c),s32_max_value=124,u32_max_value=124) R2=invP(id=0,umax_value=60,var_off=(0x0; 0x3c)) R3=invP(id=0,umax_value=60,var_off=(0x0; 0x3c)) R6=pkt_end(id=0,off=0,imm=0) R7=pkt(id=0,off=0,r=34,imm=0) R10=fp0
29: (bf) r8 = r1
30: (3d) if r1 >= r6 goto pc+17
 R1=pkt(id=2,off=14,r=13,umax_value=120,var_off=(0x0; 0x7c),s32_max_value=124,u32_max_value=124) R2=invP(id=0,umax_value=60,var_off=(0x0; 0x3c)) R3=invP(id=0,umax_value=60,var_off=(0x0; 0x3c)) R6=pkt_end(id=0,off=0,imm=0) R7=pkt(id=0,off=0,r=34,imm=0) R8_w=pkt(id=2,off=14,r=13,umax_value=120,var_off=(0x0; 0x7c),s32_max_value=124,u32_max_value=124) R10=fp0
31: (bf) r1 = r8
32: (1f) r1 -= r7
33: (25) if r1 > 0x32 goto pc+14
 R1_w=inv(id=0,umax_value=50,var_off=(0x0; 0xffffffff)) R2=invP(id=0,umax_value=60,var_off=(0x0; 0x3c)) R3=invP(id=0,umax_value=60,var_off=(0x0; 0x3c)) R6=pkt_end(id=0,off=0,imm=0) R7=pkt(id=0,off=0,r=34,imm=0) R8_w=pkt(id=2,off=14,r=13,umax_value=120,var_off=(0x0; 0x7c),s32_max_value=124,u32_max_value=124) R10=fp0
34: (b7) r9 = 0
35: (bf) r1 = r8
36: (0f) r1 += r9
last_idx 36 first_idx 28
regs=200 stack=0 before 35: (bf) r1 = r8
regs=200 stack=0 before 34: (b7) r9 = 0
37: (3d) if r7 >= r1 goto pc+10
 R1=pkt(id=2,off=14,r=13,umax_value=120,var_off=(0x0; 0x7c),s32_max_value=124,u32_max_value=124) R2=invP(id=0,umax_value=60,var_off=(0x0; 0x3c)) R3=invP(id=0,umax_value=60,var_off=(0x0; 0x3c)) R6=pkt_end(id=0,off=0,imm=0) R7=pkt(id=0,off=0,r=34,imm=0) R8=pkt(id=2,off=14,r=13,umax_value=120,var_off=(0x0; 0x7c),s32_max_value=124,u32_max_value=124) R9=invP0 R10=fp0
38: (3d) if r1 >= r6 goto pc+9
 R1=pkt(id=2,off=14,r=13,umax_value=120,var_off=(0x0; 0x7c),s32_max_value=124,u32_max_value=124) R2=invP(id=0,umax_value=60,var_off=(0x0; 0x3c)) R3=invP(id=0,umax_value=60,var_off=(0x0; 0x3c)) R6=pkt_end(id=0,off=0,imm=0) R7=pkt(id=0,off=0,r=34,imm=0) R8=pkt(id=2,off=14,r=13,umax_value=120,var_off=(0x0; 0x7c),s32_max_value=124,u32_max_value=124) R9=invP0 R10=fp0
39: (71) r3 = *(u8 *)(r1 +0)
invalid access to packet, off=14 size=1, R1(id=2,off=14,r=13)
R1 offset is outside of the packet
processed 40 insns (limit 1000000) max_states_per_insn 0 total_states 4 peak_states 4 mark_read 2

据我了解,5.10内核的验证者拒绝数据包指针的删除,声称我们没有验证它始终在范围内(在OFFSET 14中读取14时, R是13)。实际上,我们确实在上面检查了此操作。

有趣的是,如果我将上面的界限超大到类似的范围,则 5.10和5.13内核验证者都接受该程序

[snip]
    for i in 0..500 {
        address = start + off + i;
        // Checking 2 bytes ahead makes 5.10 verifier happy
        if address <= start || (address + 2) >= end {
            break;
        }

        // Works on both 5.10 and 5.13
        let byte = *(address as *const u8);
        // Just so the packet read above doesn't get optimized away
        printk!("%u", byte as u32);
    }

    Ok(XdpAction::Pass)
}

但是以上不是我想要的,因为这会导致有限的循环流产早期 - 如果数据包足够大,我希望循环完全运行。当我遇到验证器问题时,我尝试了通常的技巧,但到目前为止无济于事。我不太明白为什么5.10验证者对第一个示例不满意。通常,这与一些无限的寄存器有关,但据我所知,所有界限都应该得到满足。

我尝试查看两个版本之间的内核验证符,但看不到任何引起这一点的明显变化。

I am writing some eBPF programs in Rust using redBPF and I've encountered some issue with the verifier that only appears on some kernels.

This is a minimal reproducer XDP probe that shows the issue:

#[xdp]
unsafe fn xdp_test(ctx: XdpContext) -> XdpResult {
    let data = ctx.data()?;
    let start = ctx.data_start();
    let off = data.offset();
    let end = ctx.data_end();

    /* Ensuring an upper bound for off doesn't make any difference
    if off > 50 {
        return XdpResult::Err(OutOfBounds);
    }
    */

    let mut address = start + off;
    for i in 0..500 {
        address = start + off + i;
        if address <= start || address >= end {
            break;
        }

        // This line (packet access) fails on kernel 5.10, but works fine on 5.13
        let byte = *(address as *const u8);
        // Just so the packet read above doesn't get optimized away
        printk!("%u", byte as u32);
    }

    Ok(XdpAction::Pass)
}

Compiling this into eBPF bytecode and loading it into an Ubuntu 5.13 kernel (5.13.0-48-generic #54~20.04.1-Ubuntu SMP Thu Jun 2 23:37:17 UTC 2022 x86_64 x86_64 x86_64 GNU/Linux) works without issues. The verifier accepts the program.

However, trying to load the exact same bytecode into an Android emulator kernel 5.10.66-android12-9-00041-gfa9c9074531e-ab7914766 #1 SMP PREEMPT Fri Nov 12 11:36:25 UTC 2021 x86_64 the verifier rejects the program. This is the full error log from the verifier:

ret=-1 os error=Permission denied (os error 13): 0: (61) r6 = *(u32 *)(r1 +4)
1: (61) r7 = *(u32 *)(r1 +0)
2: (bf) r1 = r7
3: (07) r1 += 14
4: (2d) if r1 > r6 goto pc+43
 R1_w=pkt(id=0,off=14,r=14,imm=0) R6_w=pkt_end(id=0,off=0,imm=0) R7_w=pkt(id=0,off=0,r=14,imm=0) R10=fp0
5: (71) r2 = *(u8 *)(r7 +13)
6: (67) r2 <<= 8
7: (71) r3 = *(u8 *)(r7 +12)
8: (4f) r2 |= r3
9: (55) if r2 != 0x8 goto pc+38
 R1_w=pkt(id=0,off=14,r=14,imm=0) R2_w=inv8 R3_w=inv(id=0,umax_value=255,var_off=(0x0; 0xff)) R6_w=pkt_end(id=0,off=0,imm=0) R7_w=pkt(id=0,off=0,r=14,imm=0) R10=fp0
10: (bf) r2 = r7
11: (07) r2 += 34
12: (2d) if r2 > r6 goto pc+35
 R1=pkt(id=0,off=14,r=34,imm=0) R2=pkt(id=0,off=34,r=34,imm=0) R3=inv(id=0,umax_value=255,var_off=(0x0; 0xff)) R6=pkt_end(id=0,off=0,imm=0) R7=pkt(id=0,off=0,r=34,imm=0) R10=fp0
13: (71) r3 = *(u8 *)(r1 +0)
14: (67) r3 <<= 2
15: (57) r3 &= 60
16: (71) r2 = *(u8 *)(r1 +9)
17: (0f) r1 += r3
last_idx 17 first_idx 12
regs=8 stack=0 before 16: (71) r2 = *(u8 *)(r1 +9)
regs=8 stack=0 before 15: (57) r3 &= 60
regs=8 stack=0 before 14: (67) r3 <<= 2
regs=8 stack=0 before 13: (71) r3 = *(u8 *)(r1 +0)
18: (15) if r2 == 0x11 goto pc+31
 R1_w=pkt(id=1,off=14,r=0,umax_value=60,var_off=(0x0; 0x3c)) R2_w=inv(id=0,umax_value=255,var_off=(0x0; 0xff)) R3_w=invP(id=0,umax_value=60,var_off=(0x0; 0x3c)) R6=pkt_end(id=0,off=0,imm=0) R7=pkt(id=0,off=0,r=34,imm=0) R10=fp0
19: (55) if r2 != 0x6 goto pc+28
 R1_w=pkt(id=1,off=14,r=0,umax_value=60,var_off=(0x0; 0x3c)) R2_w=inv6 R3_w=invP(id=0,umax_value=60,var_off=(0x0; 0x3c)) R6=pkt_end(id=0,off=0,imm=0) R7=pkt(id=0,off=0,r=34,imm=0) R10=fp0
20: (2d) if r7 > r1 goto pc+27
 R1=pkt(id=1,off=14,r=0,umax_value=60,var_off=(0x0; 0x3c)) R2=inv6 R3=invP(id=0,umax_value=60,var_off=(0x0; 0x3c)) R6=pkt_end(id=0,off=0,imm=0) R7=pkt(id=0,off=0,r=34,imm=0) R10=fp0
21: (bf) r2 = r1
22: (07) r2 += 20
23: (2d) if r2 > r6 goto pc+24
 R1=pkt(id=1,off=14,r=34,umax_value=60,var_off=(0x0; 0x3c)) R2_w=pkt(id=1,off=34,r=34,umax_value=60,var_off=(0x0; 0x3c)) R3=invP(id=0,umax_value=60,var_off=(0x0; 0x3c)) R6=pkt_end(id=0,off=0,imm=0) R7=pkt(id=0,off=0,r=34,imm=0) R10=fp0
24: (71) r2 = *(u8 *)(r1 +12)
25: (77) r2 >>= 2
26: (57) r2 &= 60
27: (0f) r1 += r2
last_idx 27 first_idx 20
regs=4 stack=0 before 26: (57) r2 &= 60
regs=4 stack=0 before 25: (77) r2 >>= 2
regs=4 stack=0 before 24: (71) r2 = *(u8 *)(r1 +12)
28: (2d) if r7 > r1 goto pc+19
 R1=pkt(id=2,off=14,r=0,umax_value=120,var_off=(0x0; 0x7c),s32_max_value=124,u32_max_value=124) R2=invP(id=0,umax_value=60,var_off=(0x0; 0x3c)) R3=invP(id=0,umax_value=60,var_off=(0x0; 0x3c)) R6=pkt_end(id=0,off=0,imm=0) R7=pkt(id=0,off=0,r=34,imm=0) R10=fp0
29: (bf) r8 = r1
30: (3d) if r1 >= r6 goto pc+17
 R1=pkt(id=2,off=14,r=13,umax_value=120,var_off=(0x0; 0x7c),s32_max_value=124,u32_max_value=124) R2=invP(id=0,umax_value=60,var_off=(0x0; 0x3c)) R3=invP(id=0,umax_value=60,var_off=(0x0; 0x3c)) R6=pkt_end(id=0,off=0,imm=0) R7=pkt(id=0,off=0,r=34,imm=0) R8_w=pkt(id=2,off=14,r=13,umax_value=120,var_off=(0x0; 0x7c),s32_max_value=124,u32_max_value=124) R10=fp0
31: (bf) r1 = r8
32: (1f) r1 -= r7
33: (25) if r1 > 0x32 goto pc+14
 R1_w=inv(id=0,umax_value=50,var_off=(0x0; 0xffffffff)) R2=invP(id=0,umax_value=60,var_off=(0x0; 0x3c)) R3=invP(id=0,umax_value=60,var_off=(0x0; 0x3c)) R6=pkt_end(id=0,off=0,imm=0) R7=pkt(id=0,off=0,r=34,imm=0) R8_w=pkt(id=2,off=14,r=13,umax_value=120,var_off=(0x0; 0x7c),s32_max_value=124,u32_max_value=124) R10=fp0
34: (b7) r9 = 0
35: (bf) r1 = r8
36: (0f) r1 += r9
last_idx 36 first_idx 28
regs=200 stack=0 before 35: (bf) r1 = r8
regs=200 stack=0 before 34: (b7) r9 = 0
37: (3d) if r7 >= r1 goto pc+10
 R1=pkt(id=2,off=14,r=13,umax_value=120,var_off=(0x0; 0x7c),s32_max_value=124,u32_max_value=124) R2=invP(id=0,umax_value=60,var_off=(0x0; 0x3c)) R3=invP(id=0,umax_value=60,var_off=(0x0; 0x3c)) R6=pkt_end(id=0,off=0,imm=0) R7=pkt(id=0,off=0,r=34,imm=0) R8=pkt(id=2,off=14,r=13,umax_value=120,var_off=(0x0; 0x7c),s32_max_value=124,u32_max_value=124) R9=invP0 R10=fp0
38: (3d) if r1 >= r6 goto pc+9
 R1=pkt(id=2,off=14,r=13,umax_value=120,var_off=(0x0; 0x7c),s32_max_value=124,u32_max_value=124) R2=invP(id=0,umax_value=60,var_off=(0x0; 0x3c)) R3=invP(id=0,umax_value=60,var_off=(0x0; 0x3c)) R6=pkt_end(id=0,off=0,imm=0) R7=pkt(id=0,off=0,r=34,imm=0) R8=pkt(id=2,off=14,r=13,umax_value=120,var_off=(0x0; 0x7c),s32_max_value=124,u32_max_value=124) R9=invP0 R10=fp0
39: (71) r3 = *(u8 *)(r1 +0)
invalid access to packet, off=14 size=1, R1(id=2,off=14,r=13)
R1 offset is outside of the packet
processed 40 insns (limit 1000000) max_states_per_insn 0 total_states 4 peak_states 4 mark_read 2

As I understand the issue, the verifier of the 5.10 kernel rejects the dereferencing of the packet pointer, claiming that we don't have validated that it is always within bounds (reading at offset 14 while r is 13). We do in fact check this just above.

Interestingly, if I oversize the bounds check above to something like this, both the 5.10 and 5.13 kernel verifiers accept the program:

[snip]
    for i in 0..500 {
        address = start + off + i;
        // Checking 2 bytes ahead makes 5.10 verifier happy
        if address <= start || (address + 2) >= end {
            break;
        }

        // Works on both 5.10 and 5.13
        let byte = *(address as *const u8);
        // Just so the packet read above doesn't get optimized away
        printk!("%u", byte as u32);
    }

    Ok(XdpAction::Pass)
}

But the above is not what I want, because this causes the bounded loop to abort too early - I want the loop to run fully, if the packet is large enough. I have tried the usual tricks I do when I run into verifier issues, but so far to no avail. I don't quite understand why the 5.10 verifier is unhappy with the first example. Usually this is related to some unbounded registers, but as far as I can see all bounds should be satisfied.

I have tried looking at a diff of the kernel verifier between the two versions, but couldn't see any obvious change that causes this.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

葬花如无物 2025-02-13 04:54:17

tl; dr。您缺少错误fix 2FA7D94AFC1A 用于BPF验证器。它已退回到您使用的v5.13内核中,您正在用作提交E7A61F15BEEA,但没有将其用于v5.10内核。

如果可能的话,您可能需要尝试一个较新的Android内核,或者要求他们在v5.10上携带bugox。


验证者错误解释

i删除了此处无关紧要的输出部分。

 R1=pkt(id=2,off=14,r=0,umax_value=120,var_off=(0x0; 0x7c),s32_max_value=124,u32_max_value=124) R2=invP(id=0,umax_value=60,var_off=(0x0; 0x3c)) R3=invP(id=0,umax_value=60,var_off=(0x0; 0x3c)) R6=pkt_end(id=0,off=0,imm=0) R7=pkt(id=0,off=0,r=34,imm=0) R10=fp0
29: (bf) r8 = r1
30: (3d) if r1 >= r6 goto pc+17
 R1=pkt(id=2,off=14,r=13,umax_value=120,var_off=(0x0; 0x7c),s32_max_value=124,u32_max_value=124) R2=invP(id=0,umax_value=60,var_off=(0x0; 0x3c)) R3=invP(id=0,umax_value=60,var_off=(0x0; 0x3c)) R6=pkt_end(id=0,off=0,imm=0) R7=pkt(id=0,off=0,r=34,imm=0) R8_w=pkt(id=2,off=14,r=13,umax_value=120,var_off=(0x0; 0x7c),s32_max_value=124,u32_max_value=124) R10=fp0
[...]
34: (b7) r9 = 0
35: (bf) r1 = r8
36: (0f) r1 += r9
37: (3d) if r7 >= r1 goto pc+10
 R1=pkt(id=2,off=14,r=13,umax_value=120,var_off=(0x0; 0x7c),s32_max_value=124,u32_max_value=124) R2=invP(id=0,umax_value=60,var_off=(0x0; 0x3c)) R3=invP(id=0,umax_value=60,var_off=(0x0; 0x3c)) R6=pkt_end(id=0,off=0,imm=0) R7=pkt(id=0,off=0,r=34,imm=0) R8=pkt(id=2,off=14,r=13,umax_value=120,var_off=(0x0; 0x7c),s32_max_value=124,u32_max_value=124) R9=invP0 R10=fp0
38: (3d) if r1 >= r6 goto pc+9
 R1=pkt(id=2,off=14,r=13,umax_value=120,var_off=(0x0; 0x7c),s32_max_value=124,u32_max_value=124) R2=invP(id=0,umax_value=60,var_off=(0x0; 0x3c)) R3=invP(id=0,umax_value=60,var_off=(0x0; 0x3c)) R6=pkt_end(id=0,off=0,imm=0) R7=pkt(id=0,off=0,r=34,imm=0) R8=pkt(id=2,off=14,r=13,umax_value=120,var_off=(0x0; 0x7c),s32_max_value=124,u32_max_value=124) R9=invP0 R10=fp0
39: (71) r3 = *(u8 *)(r1 +0)
invalid access to packet, off=14 size=1, R1(id=2,off=14,r=13)
R1 offset is outside of the packet

验证者告诉我们,我们试图以偏移14( off = 14 )访问数据包,当数据包仅知道至少13个字节时,访问大小为1个字节( r = 13 )。这里已知的数据包长度不正确,因为您检查了地址&gt; = end

上升,我们可以检查数据包范围( r = 13 )来自哪里。它是从R8通过指令35分配的,本身在指令29上分配了R1。

在指令30处,我们找到 address&gt; = End 在其字节码表单中检查。我们看到,在此检查后,R1和R8的范围都从 r = 0 r = 13 更新。但是,这是不正确的,应更新为 off+1 ,因此 r = 15


检查验证源

在验证者中,此范围的更新以 find_good_pkt_pointers “ nofollow noreferrer”>更新逻辑不应该引起这个问题。

但是,如果我们 git blade 这些行,我们可以看到它们在commit 2fa7d94afc1a 。该提交描述了您遇到的两个错误错误:

此提交通过调整new_range在
正确的方向并通过将范围更改为
一个实际上应该失败的一个。

该提交是在v5.16上游发布的。检查Ubuntu源的Ubuntu-HWE-5.13-5.13.0-48.54_20.04.1,我们发现与E7A61F15BEEA相同的提交,这解释了它在您的v5.13内核上的作用。

TL;DR. You are missing bug fix 2fa7d94afc1a for the BPF verifier. It was backported to the v5.13 kernel you are using as commit e7a61f15beea, but not to the v5.10 kernel.

You might want to try a newer Android kernel if possible, or to ask them to carry the bugfix if they don't on v5.10.


Verifier Error Explanation

I removed parts of the output that were irrelevant here.

 R1=pkt(id=2,off=14,r=0,umax_value=120,var_off=(0x0; 0x7c),s32_max_value=124,u32_max_value=124) R2=invP(id=0,umax_value=60,var_off=(0x0; 0x3c)) R3=invP(id=0,umax_value=60,var_off=(0x0; 0x3c)) R6=pkt_end(id=0,off=0,imm=0) R7=pkt(id=0,off=0,r=34,imm=0) R10=fp0
29: (bf) r8 = r1
30: (3d) if r1 >= r6 goto pc+17
 R1=pkt(id=2,off=14,r=13,umax_value=120,var_off=(0x0; 0x7c),s32_max_value=124,u32_max_value=124) R2=invP(id=0,umax_value=60,var_off=(0x0; 0x3c)) R3=invP(id=0,umax_value=60,var_off=(0x0; 0x3c)) R6=pkt_end(id=0,off=0,imm=0) R7=pkt(id=0,off=0,r=34,imm=0) R8_w=pkt(id=2,off=14,r=13,umax_value=120,var_off=(0x0; 0x7c),s32_max_value=124,u32_max_value=124) R10=fp0
[...]
34: (b7) r9 = 0
35: (bf) r1 = r8
36: (0f) r1 += r9
37: (3d) if r7 >= r1 goto pc+10
 R1=pkt(id=2,off=14,r=13,umax_value=120,var_off=(0x0; 0x7c),s32_max_value=124,u32_max_value=124) R2=invP(id=0,umax_value=60,var_off=(0x0; 0x3c)) R3=invP(id=0,umax_value=60,var_off=(0x0; 0x3c)) R6=pkt_end(id=0,off=0,imm=0) R7=pkt(id=0,off=0,r=34,imm=0) R8=pkt(id=2,off=14,r=13,umax_value=120,var_off=(0x0; 0x7c),s32_max_value=124,u32_max_value=124) R9=invP0 R10=fp0
38: (3d) if r1 >= r6 goto pc+9
 R1=pkt(id=2,off=14,r=13,umax_value=120,var_off=(0x0; 0x7c),s32_max_value=124,u32_max_value=124) R2=invP(id=0,umax_value=60,var_off=(0x0; 0x3c)) R3=invP(id=0,umax_value=60,var_off=(0x0; 0x3c)) R6=pkt_end(id=0,off=0,imm=0) R7=pkt(id=0,off=0,r=34,imm=0) R8=pkt(id=2,off=14,r=13,umax_value=120,var_off=(0x0; 0x7c),s32_max_value=124,u32_max_value=124) R9=invP0 R10=fp0
39: (71) r3 = *(u8 *)(r1 +0)
invalid access to packet, off=14 size=1, R1(id=2,off=14,r=13)
R1 offset is outside of the packet

The verifier tells us that we are trying to access the packet at offset 14 (off=14) with an access size of 1 byte when the packet is only known to be at least 13 bytes long (r=13). The known packet length here is incorrect somehow because you checked that address >= end.

Going up, we can check where that packet range (r=13) is coming from. It is assigned from R8 at instruction 35, itself assigned from R1 at instruction 29.

At instruction 30, we find the address >= end check in its bytecode form. We see that both R1 and R8's ranges are updated from r=0 to r=13 after this check. That is however incorrect and should be updated to off+1, hence r=15.


Checking the Verifier Sources

In the verifier, this update of the range is implemented in find_good_pkt_pointers. The update logic looks fine and shouldn't cause this issue.

But if we git blame those lines, we can see they were changed in commit 2fa7d94afc1a. The commit describes the off-by-two error you are hitting:

This commit fixes the off-by-two error by adjusting new_range in the
right direction and fixes the tests by changing the range into the
one that should actually fail.

This commit was released upstream in v5.16. Checking the Ubuntu sources for Ubuntu-hwe-5.13-5.13.0-48.54_20.04.1, we find this same commit backported as e7a61f15beea, which explains why it works on your v5.13 kernel.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文