virtio-net: Fix DMA-from-the-stack in virtnet_set_mac_address()
authorAndy Lutomirski <luto@kernel.org>
Tue, 6 Dec 2016 02:10:58 +0000 (18:10 -0800)
committerDavid S. Miller <davem@davemloft.net>
Tue, 6 Dec 2016 16:38:43 +0000 (11:38 -0500)
With CONFIG_VMAP_STACK=y, virtnet_set_mac_address() can be passed a
pointer to the stack and it will OOPS.  Copy the address to the heap
to prevent the crash.

Cc: Michael S. Tsirkin <mst@redhat.com>
Cc: Jason Wang <jasowang@redhat.com>
Cc: Laura Abbott <labbott@redhat.com>
Reported-by: zbyszek@in.waw.pl
Signed-off-by: Andy Lutomirski <luto@kernel.org>
Acked-by: Jason Wang <jasowang@redhat.com>
Acked-by: Michael S. Tsirkin <mst@redhat.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/virtio_net.c

index 7276d5a95bd0ee417a0051990dcb86824e2523d2..cbf1c613c67aefc48692079a5f11f64c34728fa5 100644 (file)
@@ -969,12 +969,17 @@ static int virtnet_set_mac_address(struct net_device *dev, void *p)
        struct virtnet_info *vi = netdev_priv(dev);
        struct virtio_device *vdev = vi->vdev;
        int ret;
-       struct sockaddr *addr = p;
+       struct sockaddr *addr;
        struct scatterlist sg;
 
-       ret = eth_prepare_mac_addr_change(dev, p);
+       addr = kmalloc(sizeof(*addr), GFP_KERNEL);
+       if (!addr)
+               return -ENOMEM;
+       memcpy(addr, p, sizeof(*addr));
+
+       ret = eth_prepare_mac_addr_change(dev, addr);
        if (ret)
-               return ret;
+               goto out;
 
        if (virtio_has_feature(vdev, VIRTIO_NET_F_CTRL_MAC_ADDR)) {
                sg_init_one(&sg, addr->sa_data, dev->addr_len);
@@ -982,7 +987,8 @@ static int virtnet_set_mac_address(struct net_device *dev, void *p)
                                          VIRTIO_NET_CTRL_MAC_ADDR_SET, &sg)) {
                        dev_warn(&vdev->dev,
                                 "Failed to set mac address by vq command.\n");
-                       return -EINVAL;
+                       ret = -EINVAL;
+                       goto out;
                }
        } else if (virtio_has_feature(vdev, VIRTIO_NET_F_MAC) &&
                   !virtio_has_feature(vdev, VIRTIO_F_VERSION_1)) {
@@ -996,8 +1002,11 @@ static int virtnet_set_mac_address(struct net_device *dev, void *p)
        }
 
        eth_commit_mac_addr_change(dev, p);
+       ret = 0;
 
-       return 0;
+out:
+       kfree(addr);
+       return ret;
 }
 
 static struct rtnl_link_stats64 *virtnet_stats(struct net_device *dev,