packet: Don't write vnet header beyond end of buffer
authorBenjamin Poirier <bpoirier@suse.com>
Mon, 28 Aug 2017 18:29:41 +0000 (14:29 -0400)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Wed, 20 Sep 2017 06:19:54 +0000 (08:19 +0200)
[ Upstream commit edbd58be15a957f6a760c4a514cd475217eb97fd ]

... which may happen with certain values of tp_reserve and maclen.

Fixes: 58d19b19cd99 ("packet: vnet_hdr support for tpacket_rcv")
Signed-off-by: Benjamin Poirier <bpoirier@suse.com>
Cc: Willem de Bruijn <willemb@google.com>
Acked-by: Willem de Bruijn <willemb@google.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
net/packet/af_packet.c

index ae7bfd2..35ba4b6 100644 (file)
@@ -2151,6 +2151,7 @@ static int tpacket_rcv(struct sk_buff *skb, struct net_device *dev,
        struct timespec ts;
        __u32 ts_status;
        bool is_drop_n_account = false;
+       bool do_vnet = false;
 
        /* struct tpacket{2,3}_hdr is aligned to a multiple of TPACKET_ALIGNMENT.
         * We may add members to them until current aligned size without forcing
@@ -2201,8 +2202,10 @@ static int tpacket_rcv(struct sk_buff *skb, struct net_device *dev,
                netoff = TPACKET_ALIGN(po->tp_hdrlen +
                                       (maclen < 16 ? 16 : maclen)) +
                                       po->tp_reserve;
-               if (po->has_vnet_hdr)
+               if (po->has_vnet_hdr) {
                        netoff += sizeof(struct virtio_net_hdr);
+                       do_vnet = true;
+               }
                macoff = netoff - maclen;
        }
        if (po->tp_version <= TPACKET_V2) {
@@ -2219,8 +2222,10 @@ static int tpacket_rcv(struct sk_buff *skb, struct net_device *dev,
                                        skb_set_owner_r(copy_skb, sk);
                        }
                        snaplen = po->rx_ring.frame_size - macoff;
-                       if ((int)snaplen < 0)
+                       if ((int)snaplen < 0) {
                                snaplen = 0;
+                               do_vnet = false;
+                       }
                }
        } else if (unlikely(macoff + snaplen >
                            GET_PBDQC_FROM_RB(&po->rx_ring)->max_frame_len)) {
@@ -2233,6 +2238,7 @@ static int tpacket_rcv(struct sk_buff *skb, struct net_device *dev,
                if (unlikely((int)snaplen < 0)) {
                        snaplen = 0;
                        macoff = GET_PBDQC_FROM_RB(&po->rx_ring)->max_frame_len;
+                       do_vnet = false;
                }
        }
        spin_lock(&sk->sk_receive_queue.lock);
@@ -2258,7 +2264,7 @@ static int tpacket_rcv(struct sk_buff *skb, struct net_device *dev,
        }
        spin_unlock(&sk->sk_receive_queue.lock);
 
-       if (po->has_vnet_hdr) {
+       if (do_vnet) {
                if (__packet_rcv_vnet(skb, h.raw + macoff -
                                           sizeof(struct virtio_net_hdr))) {
                        spin_lock(&sk->sk_receive_queue.lock);