virtio_net: fix use after free
authorMichael S. Tsirkin <mst@redhat.com>
Wed, 15 Oct 2014 13:23:28 +0000 (16:23 +0300)
committerDavid S. Miller <davem@davemloft.net>
Wed, 15 Oct 2014 20:47:45 +0000 (16:47 -0400)
commit 0b725a2ca61bedc33a2a63d0451d528b268cf975
    net: Remove ndo_xmit_flush netdev operation, use signalling instead.

added code that looks at skb->xmit_more after the skb has
been put in TX VQ. Since some paths process the ring and free the skb
immediately, this can cause use after free.

Fix by storing xmit_more in a local variable.

Cc: David S. Miller <davem@davemloft.net>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/virtio_net.c

index 3d0ce4468ce6b6a5cde558a9df6e8614150fc2ea..13d0a8bc8bf3558d666087a273ab87109f902b59 100644 (file)
@@ -920,6 +920,8 @@ static netdev_tx_t start_xmit(struct sk_buff *skb, struct net_device *dev)
        int qnum = skb_get_queue_mapping(skb);
        struct send_queue *sq = &vi->sq[qnum];
        int err;
+       struct netdev_queue *txq = netdev_get_tx_queue(dev, qnum);
+       bool kick = !skb->xmit_more;
 
        /* Free up any pending old buffers before queueing new ones. */
        free_old_xmit_skbs(sq);
@@ -956,7 +958,7 @@ static netdev_tx_t start_xmit(struct sk_buff *skb, struct net_device *dev)
                }
        }
 
-       if (__netif_subqueue_stopped(dev, qnum) || !skb->xmit_more)
+       if (kick || netif_xmit_stopped(txq))
                virtqueue_kick(sq->vq);
 
        return NETDEV_TX_OK;