summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSungho Bae <baver.bae@lge.com>2026-06-04 03:37:56 +0900
committerMichael S. Tsirkin <mst@redhat.com>2026-09-03 11:25:00 -0400
commit01933589c95cdbe0d37cf1b165beb4e5c8a95a3f (patch)
tree4cdd3a936bb1172214b91ebc06df2fe26193195d
parenteed3dd2a9a29d52395c74e2ad86eebfedacfc17f (diff)
downloadlinux-next-01933589c95cdbe0d37cf1b165beb4e5c8a95a3f.tar.gz
linux-next-01933589c95cdbe0d37cf1b165beb4e5c8a95a3f.zip
virtio_console: fix control queue race during restore
In virtcons_restore(), after virtio_device_ready() sets DRIVER_OK, the device becomes active. If the control receive queue (c_ivq) is populated immediately, the host can instantly deliver pending control messages (e.g., VIRTIO_CONSOLE_PORT_REMOVE). This triggers the control_work_handler(), which can modify the portdev->ports list concurrently with the unprotected list_for_each_entry loop in virtcons_restore(), leading to list corruption or Use-After-Free. Fix this by deferring the population of the control receive queue (fill_queue for c_ivq) until after the list iteration is complete. This ensures the host cannot inject control messages during the vulnerable window. Signed-off-by: Sungho Bae <baver.bae@lge.com> Signed-off-by: Michael S. Tsirkin <mst@redhat.com> Message-ID: <20260603183757.21587-4-baver.bae@gmail.com>
-rw-r--r--drivers/char/virtio_console.c15
1 files changed, 12 insertions, 3 deletions
diff --git a/drivers/char/virtio_console.c b/drivers/char/virtio_console.c
index aba1977fa046..6cc398b1526d 100644
--- a/drivers/char/virtio_console.c
+++ b/drivers/char/virtio_console.c
@@ -2189,9 +2189,6 @@ static int virtcons_restore(struct virtio_device *vdev)
virtio_device_ready(portdev->vdev);
- if (use_multiport(portdev))
- fill_queue(portdev->c_ivq, &portdev->c_ivq_lock);
-
list_for_each_entry(port, &portdev->ports, list) {
port->in_vq = portdev->in_vqs[port->id];
port->out_vq = portdev->out_vqs[port->id];
@@ -2208,6 +2205,18 @@ static int virtcons_restore(struct virtio_device *vdev)
if (port->guest_connected)
send_control_msg(port, VIRTIO_CONSOLE_PORT_OPEN, 1);
}
+
+ /*
+ * Populate the control receive queue only after the list iteration
+ * is complete. If we fill this queue before iterating, the host could
+ * immediately deliver a VIRTIO_CONSOLE_PORT_REMOVE message.
+ * This would trigger the control workqueue, which modifies the
+ * portdev->ports list concurrently with the unprotected loop above,
+ * leading to a Use-After-Free and list corruption.
+ */
+ if (use_multiport(portdev))
+ fill_queue(portdev->c_ivq, &portdev->c_ivq_lock);
+
return 0;
}
#endif