ошибка верификатора для кода xdp, вычисляющего контрольную сумму icmp? - PullRequest
0 голосов
/ 04 февраля 2020

Я использую xdp (используйте действие XDP_TX) для создания пакетов icmp resv.

linux: centos8

ядро ​​4.18.0-80.el8.x86_64

llvm: 7.0.1

clang: clang version 7.0.1 (tags / RELEASE_701 / final)

Вот мой код:

SEC("xdp_icmp")
int _xdp_icmp(struct xdp_md *xdp)
{
    void *data_end = (void *)(long)xdp->data_end;
    void *data = (void *)(long)xdp->data;
    struct ethhdr *eth = data;
    struct iphdr *iph;
    struct icmphdr *icmph;
    __u16 h_proto;
    __be32 raddr;

    ....
    icmph = data + sizeof(*eth) + sizeof(*iph);
    if (icmph + 1 > data_end)
        return  XDP_DROP;

    if (icmph -> type != ICMP_ECHO)
    {
        return XDP_PASS;
    }

    if (handle_ipv4(xdp) != XDP_TX)
    {
        return XDP_PASS;
    }

    raddr = iph->saddr;
    swap_src_dst_mac(data);
    iph->saddr = iph->daddr;
    iph->daddr = raddr;
    icmph->type = ICMP_ECHOREPLY;
    icmph->checksum = 0;
    __u32 sum = 0;
    sum = bpf_csum_diff(0, 0, icmph, ICMP_ECHO_LEN, 0);
    icmph->checksum = csum_fold_helper(sum);
    return XDP_TX;
}

Но компиляция результат сказал мне "ошибка верификатора":

ошибка:

libbpf: load bpf program failed: Permission denied
libbpf: -- BEGIN DUMP LOG ---
libbpf:
...
48: (b7) r5 = 0
49: (85) call bpf_csum_diff#28
invalid access to packet, off=34 size=64, R3(id=0,off=34,r=42)
R3 offset is outside of the packet

1 Ответ

0 голосов
/ 04 февраля 2020

Я считаю, что при вызове:

// s64 bpf_csum_diff(__be32 *from, u32 from_size, __be32 *to, u32 to_size, __wsum seed)
sum = bpf_csum_diff(0, 0, icmph, ICMP_ECHO_LEN, 0);

Значение to_size, передаваемое в качестве третьего аргумента, должно быть числом байтов. Предполагая, что вы скопировали ICMP_ECHO_LEN из самотестирования ядра, я подозреваю, что его значение равно 64, поэтому просит ядро ​​вычислить контрольную сумму в 64-байтовом буфере. Но вы никогда не проверяли, что ваш пакет был таким длинным (у вас есть if (icmph + 1 > data_end), что мне кажется правильным).

Я подозреваю, что вместо этого вы должны попытаться передать длину вашего заголовка в качестве третьего аргумента, что-то вроде это (не проверено):

um = bpf_csum_diff(0, 0, icmph, sizeof(struct icmphdr), 0);

struct icmphdr определено в include/uapi/linux/icmp.h и, кажется, имеет длину 8 байт, хотя вам не нужно это знать, и все должно быть хорошо, пока вы передайте правильную длину заголовка.

...