diff options
author | Andy Lutomirski <luto@kernel.org> | 2016-12-05 21:10:58 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2016-12-06 11:38:43 -0500 |
commit | e37e2ff350a321ad9c36b588e76f34fbba305be6 (patch) | |
tree | ea9cc96f7d589fe209cccd7af95047d5e631d423 | |
parent | dcb17d22e1c2cd72e72190c736349a675362b3bc (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.c | 19 |
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; | 1007 | out: |
1008 | kfree(addr); | ||
1009 | return ret; | ||
1001 | } | 1010 | } |
1002 | 1011 | ||
1003 | static struct rtnl_link_stats64 *virtnet_stats(struct net_device *dev, | 1012 | static struct rtnl_link_stats64 *virtnet_stats(struct net_device *dev, |