]> www.infradead.org Git - users/dwmw2/linux.git/commitdiff
net: tun: don't assume IFF_VNET_HDR in tun_xdp_one() tx path
authorDavid Woodhouse <dwmw@amazon.co.uk>
Tue, 22 Jun 2021 11:06:39 +0000 (12:06 +0100)
committerDavid Woodhouse <dwmw@amazon.co.uk>
Thu, 24 Jun 2021 12:14:07 +0000 (13:14 +0100)
Sometimes it's just a data packet. The virtio_net_hdr processing should be
conditional on IFF_VNET_HDR, just as it is in tun_get_user().

Fixes: 043d222f93ab ("tuntap: accept an array of XDP buffs through sendmsg()")
Signed-off-by: David Woodhouse <dwmw@amazon.co.uk>
drivers/net/tun.c

index 67b406fa088194203b696a6bd2ca449bac4e2e6e..9acd448e6dfc768d13e6b8dc1159111d96162d17 100644 (file)
@@ -2331,7 +2331,7 @@ static int tun_xdp_one(struct tun_struct *tun,
 {
        unsigned int datasize = xdp->data_end - xdp->data;
        struct tun_xdp_hdr *hdr = xdp->data_hard_start;
-       struct virtio_net_hdr *gso = &hdr->gso;
+       struct virtio_net_hdr *gso = NULL;
        struct bpf_prog *xdp_prog;
        struct sk_buff *skb = NULL;
        u32 rxhash = 0, act;
@@ -2340,9 +2340,12 @@ static int tun_xdp_one(struct tun_struct *tun,
        bool skb_xdp = false;
        struct page *page;
 
+       if (tun->flags & IFF_VNET_HDR)
+               gso = &hdr->gso;
+
        xdp_prog = rcu_dereference(tun->xdp_prog);
        if (xdp_prog) {
-               if (gso->gso_type) {
+               if (gso && gso->gso_type) {
                        skb_xdp = true;
                        goto build;
                }
@@ -2388,7 +2391,7 @@ build:
        skb_reserve(skb, xdp->data - xdp->data_hard_start);
        skb_put(skb, xdp->data_end - xdp->data);
 
-       if (virtio_net_hdr_to_skb(skb, gso, tun_is_little_endian(tun))) {
+       if (gso && virtio_net_hdr_to_skb(skb, gso, tun_is_little_endian(tun))) {
                atomic_long_inc(&tun->rx_frame_errors);
                kfree_skb(skb);
                err = -EINVAL;