From: Marc-AndrĂ© Lureau <[email protected]>

When the host chardev disconnects while the output queue is throttled,
virtio_serial_close() calls discard_throttle_data() which detaches the
in-flight element with virtqueue_detach_element(). This silently removes
the descriptor without placing it on the used ring, so the guest never
sees the write complete and the descriptor leaks.

Add return_throttle_data(), which pushes the element back via
virtqueue_push() instead of detaching it, and call it from
virtio_serial_close().

Fixes: d4c19cdeeb2f ("virtio-serial: add missing virtio_detach_element() call")
Signed-off-by: Marc-AndrĂ© Lureau <[email protected]>
---
 hw/char/virtio-serial-bus.c | 16 +++++++++++++++-
 1 file changed, 15 insertions(+), 1 deletion(-)

diff --git a/hw/char/virtio-serial-bus.c b/hw/char/virtio-serial-bus.c
index 623e9f17a83e..008cad1b625c 100644
--- a/hw/char/virtio-serial-bus.c
+++ b/hw/char/virtio-serial-bus.c
@@ -158,6 +158,20 @@ static void discard_throttle_data(VirtIOSerialPort *port)
     }
 }
 
+/*
+ * Return a partial element held back by throttling to the guest via
+ * the used ring, so the guest driver can reclaim the descriptor.
+ * Unlike discard_throttle_data() this must be used when the virtqueue
+ * stays live (port close) rather than being reset.
+ */
+static void return_throttle_data(VirtIOSerialPort *port)
+{
+    if (port->elem) {
+        virtqueue_push(port->ovq, port->elem, 0);
+        g_clear_pointer(&port->elem, g_free);
+    }
+}
+
 static void do_flush_queued_data(VirtIOSerialPort *port, VirtQueue *vq,
                                  VirtIODevice *vdev)
 {
@@ -283,7 +297,7 @@ int virtio_serial_close(VirtIOSerialPort *port)
      * consume, reset the throttling flag and discard the data.
      */
     port->throttled = false;
-    discard_throttle_data(port);
+    return_throttle_data(port);
     discard_vq_data(port->ovq, VIRTIO_DEVICE(port->vser));
 
     send_control_event(port->vser, port->id, VIRTIO_CONSOLE_PORT_OPEN, 0);
-- 
2.56.0.rc0.29.g47ce80527c56


Reply via email to