virtio_net_hdr_tnl_to_skb() does not check that a UDP tunnel GSO packet really has outer IPv4/IPv6 and UDP headers matching the declared tunnel type. A guest, or any tap writer, can send a frame with another outer ethertype (NSH in the report), and the GSO stack then builds segments with skb->data before skb->head. The host crashes in skb_under_panic() as soon as a header is pushed.
Patch 1 validates the outer headers, using the parsing helpers from Michael's series "net: resolve uncommon partial checksums at ingress", as Willem suggested. The rest of that series (checksum validation and completion) is left to Michael. Patch 2 fixes a selftest helper computing UDP checksums over a length in network byte order. Patch 3 adds tun selftests, on tap and IFF_TUN devices: valid outer IPv4 frames (plain and VLAN tagged) are accepted, mismatched or non-IP outer headers are rejected. v2: - Patch 1: use Michael's helpers instead of a new one: find the L3 header from the device type instead of assuming Ethernet when skb->protocol is unset, do not trust skb->protocol when it disagrees with the frame, and require UDP exactly at outer_th_offset. Stop at IPv6 AH headers (Willem). - Patch 2: clear udph->check before summing and send 0xffff instead of a zero checksum (Willem). - Patch 3: clear the reused buffer before building each frame (Willem). Add IFF_TUN tests, where skb->protocol comes from the tun_pi header. v1: https://lore.kernel.org/netdev/[email protected]/ Eric Dumazet (3): net: virtio: validate outer protocol of UDP tunnel GSO packets selftests: net: tuntap: fix UDP checksum length in build_udp_packet_csum() selftests: net: tun: test outer protocol of UDP tunnel GSO packets include/linux/virtio_net.h | 169 ++++++++++++ tools/testing/selftests/net/tun.c | 269 +++++++++++++++++++ tools/testing/selftests/net/tuntap_helpers.h | 10 +- 3 files changed, 447 insertions(+), 1 deletion(-) base-commit: 787268686c64be60023743b527645a907e38ccca -- 2.53.0
