BPF / XDP: почему `bpf_ntohs` выдает ошибку верификатора? - PullRequest
0 голосов
/ 01 апреля 2020

У меня проблема с верификатором BPF / XDP. Я пытаюсь отфильтровать пакеты UDP и написать метку времени в конце пакета (с udh->len). Поскольку udh->len находится в сетевом порядке байтов, я сначала должен преобразовать его в "хост". Поэтому я попробовал это так:

SEC("xdp_sock")
int xdp_sock_prog(struct xdp_md *ctx) {

    const void *data = (void*)(unsigned long)ctx->data;
    const void *data_end = (void*)(unsigned long)ctx->data_end;

    const struct ethhdr *eth = (struct ethhdr*)(data);

    if((void*)eth + sizeof(struct ethhdr) <= data_end) {

        if(bpf_ntohs(eth->h_proto) == ETH_P_IP) {
            const struct iphdr *iph = (struct iphdr*)(data + sizeof(struct ethhdr));

            if((void*)iph + sizeof(struct iphdr) <= data_end) {

                if(iph->protocol == IPPROTO_UDP) {
                    const __u16 iph_sz_in_bytes = iph->ihl * IP_HDR_MULT_IHL;

                    if((void*)iph + iph_sz_in_bytes <= data_end) {

                        const struct udphdr *udh = (struct udphdr*)(data + sizeof(struct ethhdr) + iph_sz_in_bytes);

                        if((void*)udh + sizeof(struct udphdr) <= data_end) {
                            const __u16 udh_sz_in_bytes = bpf_ntohs(udh->len);

                            if((void*)udh + udh_sz_in_bytes <= data_end) {
                                bpf_printk("HELLO!\n");
                                /* Usually I would start to write the timestamp here */
                            }

Но я получаю math between pkt pointer and register with unbounded min value is not allowed.

Поскольку я не мог придумать, как это не получится, я попытался удалить bpf_ntohs просто для целей тестирования (я знаю, что это не сработает):

SEC("xdp_sock")
int xdp_sock_prog(struct xdp_md *ctx) {

    const void *data = (void*)(unsigned long)ctx->data;
    const void *data_end = (void*)(unsigned long)ctx->data_end;

    const struct ethhdr *eth = (struct ethhdr*)(data);

    if((void*)eth + sizeof(struct ethhdr) <= data_end) {

        if(bpf_ntohs(eth->h_proto) == ETH_P_IP) {
            const struct iphdr *iph = (struct iphdr*)(data + sizeof(struct ethhdr));

            if((void*)iph + sizeof(struct iphdr) <= data_end) {

                if(iph->protocol == IPPROTO_UDP) {
                    const __u16 iph_sz_in_bytes = iph->ihl * IP_HDR_MULT_IHL;

                    if((void*)iph + iph_sz_in_bytes <= data_end) {

                        const struct udphdr *udh = (struct udphdr*)(data + sizeof(struct ethhdr) + iph_sz_in_bytes);

                        if((void*)udh + sizeof(struct udphdr) <= data_end) {
                            const __u16 udh_sz_in_bytes = udh->len;

                            if((void*)udh + udh_sz_in_bytes <= data_end) {
                                bpf_printk("HELLO!\n");
                            }

Но я действительно могу запустить свою программу таким образом - есть идеи, почему bpf_ntohs выдает ошибку верификатора?

...