]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
virtio_console: fix misc probe bugs
authorMichael S. Tsirkin <mst@redhat.com>
Mon, 16 Sep 2024 18:16:44 +0000 (14:16 -0400)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Thu, 17 Oct 2024 13:11:49 +0000 (15:11 +0200)
[ Upstream commit b9efbe2b8f0177fa97bfab290d60858900aa196b ]

This fixes the following issue discovered by code review:

after vqs have been created, a buggy device can send an interrupt.

A control vq callback will then try to schedule control_work which has
not been initialized yet. Similarly for config interrupt.  Further, in
and out vq callbacks invoke find_port_by_vq which attempts to take
ports_lock which also has not been initialized.

To fix, init all locks and work before creating vqs.

Message-ID: <ad982e975a6160ad110c623c016041311ca15b4f.1726511547.git.mst@redhat.com>
Fixes: 17634ba25544 ("virtio: console: Add a new MULTIPORT feature, support for generic ports")
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
drivers/char/virtio_console.c

index 77bc993d75130be14482338ff3809e766d0e4ca8..a5d38fdc2589709fb2d889a764b9c53db5fc88a9 100644 (file)
@@ -2046,25 +2046,27 @@ static int virtcons_probe(struct virtio_device *vdev)
                multiport = true;
        }
 
-       err = init_vqs(portdev);
-       if (err < 0) {
-               dev_err(&vdev->dev, "Error %d initializing vqs\n", err);
-               goto free_chrdev;
-       }
-
        spin_lock_init(&portdev->ports_lock);
        INIT_LIST_HEAD(&portdev->ports);
        INIT_LIST_HEAD(&portdev->list);
 
-       virtio_device_ready(portdev->vdev);
-
        INIT_WORK(&portdev->config_work, &config_work_handler);
        INIT_WORK(&portdev->control_work, &control_work_handler);
 
        if (multiport) {
                spin_lock_init(&portdev->c_ivq_lock);
                spin_lock_init(&portdev->c_ovq_lock);
+       }
 
+       err = init_vqs(portdev);
+       if (err < 0) {
+               dev_err(&vdev->dev, "Error %d initializing vqs\n", err);
+               goto free_chrdev;
+       }
+
+       virtio_device_ready(portdev->vdev);
+
+       if (multiport) {
                err = fill_queue(portdev->c_ivq, &portdev->c_ivq_lock);
                if (err < 0) {
                        dev_err(&vdev->dev,