]> www.infradead.org Git - users/jedix/linux-maple.git/commitdiff
virtio_net: clear MTU when out of range
authorMichael S. Tsirkin <mst@redhat.com>
Wed, 29 Mar 2017 16:09:14 +0000 (19:09 +0300)
committerSi-Wei Liu <si-wei.liu@oracle.com>
Fri, 15 Sep 2017 18:24:22 +0000 (14:24 -0400)
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 <mst@redhat.com>
(cherry picked from commit fe36cbe0671e868cbd2f534a50ac60273fa5acf2)

Orabug: 26584452

Signed-off-by: Si-Wei Liu <si-wei.liu@oracle.com>
Reviewed-by: Joao Martins <joao.m.martins@oracle.com>
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

index 4f0b08363073d8990f2d4e4db62e9919408482c2..84da82b8555e09e3f20b16bebae7ae00ceae7b36 100644 (file)
@@ -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,