aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAndy Lutomirski <luto@kernel.org>2016-12-05 21:10:58 -0500
committerDavid S. Miller <davem@davemloft.net>2016-12-06 11:38:43 -0500
commite37e2ff350a321ad9c36b588e76f34fbba305be6 (patch)
treeea9cc96f7d589fe209cccd7af95047d5e631d423
parentdcb17d22e1c2cd72e72190c736349a675362b3bc (diff)
virtio-net: Fix DMA-from-the-stack in virtnet_set_mac_address()
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>
-rw-r--r--drivers/net/virtio_net.c19
1 files changed, 14 insertions, 5 deletions
diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c
index 7276d5a95bd0..cbf1c613c67a 100644
--- a/drivers/net/virtio_net.c
+++ b/drivers/net/virtio_net.c
@@ -969,12 +969,17 @@ static int virtnet_set_mac_address(struct net_device *dev, void *p)
969 struct virtnet_info *vi = netdev_priv(dev); 969 struct virtnet_info *vi = netdev_priv(dev);
970 struct virtio_device *vdev = vi->vdev; 970 struct virtio_device *vdev = vi->vdev;
971 int ret; 971 int ret;
972 struct sockaddr *addr = p; 972 struct sockaddr *addr;
973 struct scatterlist sg; 973 struct scatterlist sg;
974 974
975 ret = eth_prepare_mac_addr_change(dev, p); 975 addr = kmalloc(sizeof(*addr), GFP_KERNEL);
976 if (!addr)
977 return -ENOMEM;
978 memcpy(addr, p, sizeof(*addr));
979
980 ret = eth_prepare_mac_addr_change(dev, addr);
976 if (ret) 981 if (ret)
977 return ret; 982 goto out;
978 983
979 if (virtio_has_feature(vdev, VIRTIO_NET_F_CTRL_MAC_ADDR)) { 984 if (virtio_has_feature(vdev, VIRTIO_NET_F_CTRL_MAC_ADDR)) {
980 sg_init_one(&sg, addr->sa_data, dev->addr_len); 985 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)
982 VIRTIO_NET_CTRL_MAC_ADDR_SET, &sg)) { 987 VIRTIO_NET_CTRL_MAC_ADDR_SET, &sg)) {
983 dev_warn(&vdev->dev, 988 dev_warn(&vdev->dev,
984 "Failed to set mac address by vq command.\n"); 989 "Failed to set mac address by vq command.\n");
985 return -EINVAL; 990 ret = -EINVAL;
991 goto out;
986 } 992 }
987 } else if (virtio_has_feature(vdev, VIRTIO_NET_F_MAC) && 993 } else if (virtio_has_feature(vdev, VIRTIO_NET_F_MAC) &&
988 !virtio_has_feature(vdev, VIRTIO_F_VERSION_1)) { 994 !virtio_has_feature(vdev, VIRTIO_F_VERSION_1)) {
@@ -996,8 +1002,11 @@ static int virtnet_set_mac_address(struct net_device *dev, void *p)
996 } 1002 }
997 1003
998 eth_commit_mac_addr_change(dev, p); 1004 eth_commit_mac_addr_change(dev, p);
1005 ret = 0;
999 1006
1000 return 0; 1007out:
1008 kfree(addr);
1009 return ret;
1001} 1010}
1002 1011
1003static struct rtnl_link_stats64 *virtnet_stats(struct net_device *dev, 1012static struct rtnl_link_stats64 *virtnet_stats(struct net_device *dev,