Re: bpf_csum_diff - R3 offset is outside of the packet

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Hi Francesco,

пт, 6 дек. 2019 г. в 19:12, Francesco Ruta (fruta) <fruta@xxxxxxxxx>:
>
> Hello,
>
> I am trying to use bpf_csum_diff() to recompute a corrupted checksum in XDP; unfortunately, in this specific case, I am unable to just perform an incremental update.
> I understand that the verifier will reject code that uses dynamic length, but even the stripped-down test shown below is rejected.
> I tried directly in assembly adding extra range checks for the r3 register to placate the most phobic verifier to no avail.
> Is there any workaround -or any alternative?
> BR
> F.
>
> SEC("test")
> int intercept(struct xdp_md *ctx) {
>     void * data = (void*)(long)ctx->data;
>     void * dataEnd = (void*)(long)ctx->data_end;
>     void * dataPnt = data;
>     if (dataPnt >= dataEnd) {
>         return XDP_ABORTED;
>     }
>     __u32 dataLen = (__be32 *)dataEnd - (__be32 *)dataPnt;
>     if (dataLen > sizeof(__be32)){
>         (void)bpf_csum_diff(0, 0, (__be32 *)dataPnt, sizeof(__be32), 0);
>    }
>     return XDP_PASS;
> }
> char _license[] SEC("license") = "GPL";
>
> Prog section 'test' rejected: Permission denied (13)!
> - Type:         6
> - Instructions: 18 (0 over limit)
> - License:      GPL
>
> Verifier analysis:
>
> 0: (b7) r6 = 1
> 1: (61) r2 = *(u32 *)(r1 +4)
> 2: (61) r3 = *(u32 *)(r1 +0)
> 3: (3d) if r3 >= r2 goto pc+12
> R1=ctx(id=0,off=0,imm=0) R2=pkt_end(id=0,off=0,imm=0) R3=pkt(id=0,off=0,r=0,imm=0) R6=inv1 R10=fp0,call_-1
> 4: (1f) r2 -= r3
> 5: (18) r1 = 0x3fffffffc
> 7: (5f) r2 &= r1
> 8: (b7) r6 = 2
> 9: (b7) r1 = 17
> 10: (2d) if r1 > r2 goto pc+5
> R1=inv17 R2=inv(id=0,umin_value=17,umax_value=17179869180,var_off=(0x0; 0x3fffffffc)) R3=pkt(id=0,off=0,r=0,imm=0) R6=inv2 R10=fp0,call_-1
> 11: (b7) r1 = 0
> 12: (b7) r2 = 0
> 13: (b7) r4 = 4
> 14: (b7) r5 = 0
> 15: (85) call bpf_csum_diff#28
> invalid access to packet, off=0 size=4, R3(id=0,off=0,r=0)
> R3 offset is outside of the packet
>
> uname -sr
> Linux 5.0.0-1022-gke

You need to check pointer boundaries, try something like this:

SEC("test")
int intercept(struct xdp_md *ctx) {
    void * data = (void*)(long)ctx->data;
    void * data_end = (void*)(long)ctx->data_end;
    const int N = sizeof(__be32);

    if (data >= data_end)
        return XDP_ABORTED;

    if (data + N <= data_end) /* lets verifier to know that
data[0,...,N-1] is valid */
        bpf_csum_diff(0, 0, data, N, 0);

    return XDP_PASS;
}




[Index of Archives]     [Linux Networking Development]     [Fedora Linux Users]     [Linux SCTP]     [DCCP]     [Gimp]     [Yosemite Campsites]

  Powered by Linux