Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

selftests/bpf: Test bpf_skb_adjust_room on CHECKSUM_PARTIAL

When the bpf_skb_adjust_room() shrinks the skb such that its csum_start
is invalid, the skb->ip_summed should be reset from CHECKSUM_PARTIAL to
CHECKSUM_NONE.

The commit 54c3f1a81421 ("bpf: pull before calling skb_postpull_rcsum()")
fixed it.

This patch adds a test to ensure the skb->ip_summed changed from
CHECKSUM_PARTIAL to CHECKSUM_NONE after bpf_skb_adjust_room().

Signed-off-by: Martin KaFai Lau <martin.lau@kernel.org>
Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
Acked-by: Stanislav Fomichev <sdf@google.com>
Link: https://lore.kernel.org/bpf/20221221185653.1589961-1-martin.lau@linux.dev

authored by

Martin KaFai Lau and committed by
Daniel Borkmann
70a00e2f 54c3f1a8

+160
+1
tools/testing/selftests/bpf/DENYLIST.s390x
··· 14 14 cgrp_local_storage # prog_attach unexpected error: -524 (trampoline) 15 15 core_read_macros # unknown func bpf_probe_read#4 (overlapping) 16 16 d_path # failed to auto-attach program 'prog_stat': -524 (trampoline) 17 + decap_sanity # JIT does not support calling kernel function (kfunc) 17 18 deny_namespace # failed to attach: ERROR: strerror_r(-524)=22 (trampoline) 18 19 dummy_st_ops # test_run unexpected error: -524 (errno 524) (trampoline) 19 20 fentry_fexit # fentry attach failed: -524 (trampoline)
+85
tools/testing/selftests/bpf/prog_tests/decap_sanity.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + /* Copyright (c) 2022 Meta Platforms, Inc. and affiliates. */ 3 + 4 + #include <sys/types.h> 5 + #include <sys/socket.h> 6 + #include <net/if.h> 7 + #include <linux/in6.h> 8 + 9 + #include "test_progs.h" 10 + #include "network_helpers.h" 11 + #include "decap_sanity.skel.h" 12 + 13 + #define SYS(fmt, ...) \ 14 + ({ \ 15 + char cmd[1024]; \ 16 + snprintf(cmd, sizeof(cmd), fmt, ##__VA_ARGS__); \ 17 + if (!ASSERT_OK(system(cmd), cmd)) \ 18 + goto fail; \ 19 + }) 20 + 21 + #define NS_TEST "decap_sanity_ns" 22 + #define IPV6_IFACE_ADDR "face::1" 23 + #define UDP_TEST_PORT 7777 24 + 25 + void test_decap_sanity(void) 26 + { 27 + LIBBPF_OPTS(bpf_tc_hook, qdisc_hook, .attach_point = BPF_TC_EGRESS); 28 + LIBBPF_OPTS(bpf_tc_opts, tc_attach); 29 + struct nstoken *nstoken = NULL; 30 + struct decap_sanity *skel; 31 + struct sockaddr_in6 addr; 32 + socklen_t addrlen; 33 + char buf[128] = {}; 34 + int sockfd, err; 35 + 36 + skel = decap_sanity__open_and_load(); 37 + if (!ASSERT_OK_PTR(skel, "skel open_and_load")) 38 + return; 39 + 40 + SYS("ip netns add %s", NS_TEST); 41 + SYS("ip -net %s -6 addr add %s/128 dev lo nodad", NS_TEST, IPV6_IFACE_ADDR); 42 + SYS("ip -net %s link set dev lo up", NS_TEST); 43 + 44 + nstoken = open_netns(NS_TEST); 45 + if (!ASSERT_OK_PTR(nstoken, "open_netns")) 46 + goto fail; 47 + 48 + qdisc_hook.ifindex = if_nametoindex("lo"); 49 + if (!ASSERT_GT(qdisc_hook.ifindex, 0, "if_nametoindex lo")) 50 + goto fail; 51 + 52 + err = bpf_tc_hook_create(&qdisc_hook); 53 + if (!ASSERT_OK(err, "create qdisc hook")) 54 + goto fail; 55 + 56 + tc_attach.prog_fd = bpf_program__fd(skel->progs.decap_sanity); 57 + err = bpf_tc_attach(&qdisc_hook, &tc_attach); 58 + if (!ASSERT_OK(err, "attach filter")) 59 + goto fail; 60 + 61 + addrlen = sizeof(addr); 62 + err = make_sockaddr(AF_INET6, IPV6_IFACE_ADDR, UDP_TEST_PORT, 63 + (void *)&addr, &addrlen); 64 + if (!ASSERT_OK(err, "make_sockaddr")) 65 + goto fail; 66 + sockfd = socket(AF_INET6, SOCK_DGRAM, 0); 67 + if (!ASSERT_NEQ(sockfd, -1, "socket")) 68 + goto fail; 69 + err = sendto(sockfd, buf, sizeof(buf), 0, (void *)&addr, addrlen); 70 + close(sockfd); 71 + if (!ASSERT_EQ(err, sizeof(buf), "send")) 72 + goto fail; 73 + 74 + ASSERT_TRUE(skel->bss->init_csum_partial, "init_csum_partial"); 75 + ASSERT_TRUE(skel->bss->final_csum_none, "final_csum_none"); 76 + ASSERT_FALSE(skel->bss->broken_csum_start, "broken_csum_start"); 77 + 78 + fail: 79 + if (nstoken) { 80 + bpf_tc_hook_destroy(&qdisc_hook); 81 + close_netns(nstoken); 82 + } 83 + system("ip netns del " NS_TEST " >& /dev/null"); 84 + decap_sanity__destroy(skel); 85 + }
+6
tools/testing/selftests/bpf/progs/bpf_tracing_net.h
··· 50 50 #define ICSK_TIME_LOSS_PROBE 5 51 51 #define ICSK_TIME_REO_TIMEOUT 6 52 52 53 + #define ETH_HLEN 14 54 + #define ETH_P_IPV6 0x86DD 55 + 56 + #define CHECKSUM_NONE 0 57 + #define CHECKSUM_PARTIAL 3 58 + 53 59 #define IFNAMSIZ 16 54 60 55 61 #define RTF_GATEWAY 0x0002
+68
tools/testing/selftests/bpf/progs/decap_sanity.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + /* Copyright (c) 2022 Meta Platforms, Inc. and affiliates. */ 3 + 4 + #include "vmlinux.h" 5 + #include "bpf_tracing_net.h" 6 + #include <bpf/bpf_helpers.h> 7 + #include <bpf/bpf_endian.h> 8 + 9 + #define UDP_TEST_PORT 7777 10 + 11 + void *bpf_cast_to_kern_ctx(void *) __ksym; 12 + bool init_csum_partial = false; 13 + bool final_csum_none = false; 14 + bool broken_csum_start = false; 15 + 16 + static unsigned int skb_headlen(const struct sk_buff *skb) 17 + { 18 + return skb->len - skb->data_len; 19 + } 20 + 21 + static unsigned int skb_headroom(const struct sk_buff *skb) 22 + { 23 + return skb->data - skb->head; 24 + } 25 + 26 + static int skb_checksum_start_offset(const struct sk_buff *skb) 27 + { 28 + return skb->csum_start - skb_headroom(skb); 29 + } 30 + 31 + SEC("tc") 32 + int decap_sanity(struct __sk_buff *skb) 33 + { 34 + struct sk_buff *kskb; 35 + struct ipv6hdr ip6h; 36 + struct udphdr udph; 37 + int err; 38 + 39 + if (skb->protocol != __bpf_constant_htons(ETH_P_IPV6)) 40 + return TC_ACT_SHOT; 41 + 42 + if (bpf_skb_load_bytes(skb, ETH_HLEN, &ip6h, sizeof(ip6h))) 43 + return TC_ACT_SHOT; 44 + 45 + if (ip6h.nexthdr != IPPROTO_UDP) 46 + return TC_ACT_SHOT; 47 + 48 + if (bpf_skb_load_bytes(skb, ETH_HLEN + sizeof(ip6h), &udph, sizeof(udph))) 49 + return TC_ACT_SHOT; 50 + 51 + if (udph.dest != __bpf_constant_htons(UDP_TEST_PORT)) 52 + return TC_ACT_SHOT; 53 + 54 + kskb = bpf_cast_to_kern_ctx(skb); 55 + init_csum_partial = (kskb->ip_summed == CHECKSUM_PARTIAL); 56 + err = bpf_skb_adjust_room(skb, -(s32)(ETH_HLEN + sizeof(ip6h) + sizeof(udph)), 57 + 1, BPF_F_ADJ_ROOM_FIXED_GSO); 58 + if (err) 59 + return TC_ACT_SHOT; 60 + final_csum_none = (kskb->ip_summed == CHECKSUM_NONE); 61 + if (kskb->ip_summed == CHECKSUM_PARTIAL && 62 + (unsigned int)skb_checksum_start_offset(kskb) >= skb_headlen(kskb)) 63 + broken_csum_start = true; 64 + 65 + return TC_ACT_SHOT; 66 + } 67 + 68 + char __license[] SEC("license") = "GPL";