From db0d282eebb65839bbeda810b1e94422d62b4e5c Mon Sep 17 00:00:00 2001 From: "Michael S. Tsirkin" Date: Wed, 29 Mar 2017 19:09:14 +0300 Subject: [PATCH] virtio_net: clear MTU when out of range virtio attempts to clear the MTU feature bit if the value is out of the supported range, but this has no real effect since FEATURES_OK has already been set. Fix this up by checking the MTU in the new validate callback. Fixes: 14de9d114a82 ("virtio-net: Add initial MTU advice feature") Signed-off-by: Michael S. Tsirkin (cherry picked from commit fe36cbe0671e868cbd2f534a50ac60273fa5acf2) Orabug: 26584452 Signed-off-by: Si-Wei Liu Reviewed-by: Joao Martins Conflicts: drivers/net/virtio_net.c Due to the lack of commit d0c2c9973ecd ("net: use core MTU range checking in virt drivers") the MTU size check is still done in the virtio_net. --- drivers/net/virtio_net.c | 39 ++++++++++++++++++++++++++++++--------- 1 file changed, 30 insertions(+), 9 deletions(-) diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c index 4f0b08363073..84da82b8555e 100644 --- a/drivers/net/virtio_net.c +++ b/drivers/net/virtio_net.c @@ -1713,14 +1713,8 @@ static bool virtnet_validate_features(struct virtio_device *vdev) return true; } -static int virtnet_probe(struct virtio_device *vdev) +static int virtnet_validate(struct virtio_device *vdev) { - int i, err; - struct net_device *dev; - struct virtnet_info *vi; - u16 max_queue_pairs; - int mtu; - if (!vdev->config->get) { dev_err(&vdev->dev, "%s failure: config access disabled\n", __func__); @@ -1730,6 +1724,25 @@ static int virtnet_probe(struct virtio_device *vdev) if (!virtnet_validate_features(vdev)) return -EINVAL; + if (virtio_has_feature(vdev, VIRTIO_NET_F_MTU)) { + int mtu = virtio_cread16(vdev, + offsetof(struct virtio_net_config, + mtu)); + if (mtu < MIN_MTU || mtu > MAX_MTU) + __virtio_clear_bit(vdev, VIRTIO_NET_F_MTU); + } + + return 0; +} + +static int virtnet_probe(struct virtio_device *vdev) +{ + int i, err; + struct net_device *dev; + struct virtnet_info *vi; + u16 max_queue_pairs; + int mtu; + /* Find if host supports multiqueue virtio_net device */ err = virtio_cread_feature(vdev, VIRTIO_NET_F_MQ, struct virtio_net_config, @@ -1840,8 +1853,15 @@ static int virtnet_probe(struct virtio_device *vdev) mtu = virtio_cread16(vdev, offsetof(struct virtio_net_config, mtu)); - if (virtnet_change_mtu(dev, mtu)) - __virtio_clear_bit(vdev, VIRTIO_NET_F_MTU); + if (virtnet_change_mtu(dev, mtu)) { + /* Should never trigger: MTU was previously validated + * in virtnet_validate. + */ + dev_err(&vdev->dev, "device MTU appears to have changed " + "it is now %d out of range [%d, %d]", mtu, + MIN_MTU, MAX_MTU); + goto free_stats; + } /* TODO: size buffers correctly in this case. */ if (dev->mtu > ETH_DATA_LEN) @@ -2047,6 +2067,7 @@ static struct virtio_driver virtio_net_driver = { .driver.name = KBUILD_MODNAME, .driver.owner = THIS_MODULE, .id_table = id_table, + .validate = virtnet_validate, .probe = virtnet_probe, .remove = virtnet_remove, .config_changed = virtnet_config_changed, -- 2.50.1