yeahuh / rpms / qemu-kvm

Forked from rpms/qemu-kvm 2 years ago
Clone
76daa3
From baae39c2c63098031cd7448b1b1331bcf6140c45 Mon Sep 17 00:00:00 2001
76daa3
From: Stefan Hajnoczi <stefanha@redhat.com>
76daa3
Date: Mon, 12 Jun 2017 14:36:56 +0200
76daa3
Subject: [PATCH 10/13] virtio-serial: fix segfault on disconnect
76daa3
76daa3
RH-Author: Stefan Hajnoczi <stefanha@redhat.com>
76daa3
Message-id: <20170612143656.19554-2-stefanha@redhat.com>
76daa3
Patchwork-id: 75591
76daa3
O-Subject: [RHV-7.4 qemu-kvm-rhev PATCH 1/1] virtio-serial: fix segfault on disconnect
76daa3
Bugzilla: 1447257
76daa3
RH-Acked-by: Ladi Prosek <lprosek@redhat.com>
76daa3
RH-Acked-by: Michael S. Tsirkin <mst@redhat.com>
76daa3
RH-Acked-by: Pankaj Gupta <pagupta@redhat.com>
76daa3
76daa3
Since commit d4c19cdeeb2f1e474bc426a6da261f1d7346eb5b ("virtio-serial:
76daa3
add missing virtio_detach_element() call") the following commands may
76daa3
cause QEMU to segfault:
76daa3
76daa3
  $ qemu -M accel=kvm -cpu host -m 1G \
76daa3
         -drive if=virtio,file=test.img,format=raw \
76daa3
         -device virtio-serial-pci,id=virtio-serial0 \
76daa3
         -chardev socket,id=channel1,path=/tmp/chardev.sock,server,nowait \
76daa3
         -device virtserialport,chardev=channel1,bus=virtio-serial0.0,id=port1
76daa3
  $ nc -U /tmp/chardev.sock
76daa3
  ^C
76daa3
76daa3
  (guest)$ cat /dev/zero >/dev/vport0p1
76daa3
76daa3
The segfault is non-deterministic: if the event loop notices the socket
76daa3
has been closed then there is no crash.  The disconnect has to happen
76daa3
right before QEMU attempts to write data to the socket.
76daa3
76daa3
The backtrace is as follows:
76daa3
76daa3
  Thread 1 "qemu-system-x86" received signal SIGSEGV, Segmentation fault.
76daa3
  0x00005555557e0698 in do_flush_queued_data (port=0x5555582cedf0, vq=0x7fffcc854290, vdev=0x55555807b1d0) at hw/char/virtio-serial-bus.c:180
76daa3
  180           for (i = port->iov_idx; i < port->elem->out_num; i++) {
76daa3
  #1  0x000055555580d363 in virtio_queue_notify_vq (vq=0x7fffcc854290) at hw/virtio/virtio.c:1524
76daa3
  #2  0x000055555580d363 in virtio_queue_host_notifier_read (n=0x7fffcc8542f8) at hw/virtio/virtio.c:2430
76daa3
  #3  0x0000555555b3482c in aio_dispatch_handlers (ctx=ctx@entry=0x5555566b8c80) at util/aio-posix.c:399
76daa3
  #4  0x0000555555b350d8 in aio_dispatch (ctx=0x5555566b8c80) at util/aio-posix.c:430
76daa3
  #5  0x0000555555b3212e in aio_ctx_dispatch (source=<optimized out>, callback=<optimized out>, user_data=<optimized out>) at util/async.c:261
76daa3
  #6  0x00007fffde71de52 in g_main_context_dispatch () at /lib64/libglib-2.0.so.0
76daa3
  #7  0x0000555555b34353 in glib_pollfds_poll () at util/main-loop.c:213
76daa3
  #8  0x0000555555b34353 in os_host_main_loop_wait (timeout=<optimized out>) at util/main-loop.c:261
76daa3
  #9  0x0000555555b34353 in main_loop_wait (nonblocking=<optimized out>) at util/main-loop.c:517
76daa3
  #10 0x0000555555773207 in main_loop () at vl.c:1917
76daa3
  #11 0x0000555555773207 in main (argc=<optimized out>, argv=<optimized out>, envp=<optimized out>) at vl.c:4751
76daa3
76daa3
The do_flush_queued_data() function does not anticipate chardev close
76daa3
events during vsc->have_data().  It expects port->elem to remain
76daa3
non-NULL for the duration its for loop.
76daa3
76daa3
The fix is simply to return from do_flush_queued_data() if the port
76daa3
closes because the close event already frees port->elem and drains the
76daa3
virtqueue - there is nothing left for do_flush_queued_data() to do.
76daa3
76daa3
Reported-by: Sitong Liu <siliu@redhat.com>
76daa3
Reported-by: Min Deng <mdeng@redhat.com>
76daa3
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
76daa3
Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
76daa3
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
76daa3
(cherry picked from commit 46764fe09ca2e0f15c0981a672c166ed8cf57e72)
76daa3
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
76daa3
Signed-off-by: Miroslav Rezanina <mrezanin@redhat.com>
76daa3
---
76daa3
 hw/char/virtio-serial-bus.c | 3 +++
76daa3
 1 file changed, 3 insertions(+)
76daa3
76daa3
diff --git a/hw/char/virtio-serial-bus.c b/hw/char/virtio-serial-bus.c
76daa3
index aa9c11a..f5bc173 100644
76daa3
--- a/hw/char/virtio-serial-bus.c
76daa3
+++ b/hw/char/virtio-serial-bus.c
76daa3
@@ -186,6 +186,9 @@ static void do_flush_queued_data(VirtIOSerialPort *port, VirtQueue *vq,
76daa3
                                   port->elem->out_sg[i].iov_base
76daa3
                                   + port->iov_offset,
76daa3
                                   buf_size);
76daa3
+            if (!port->elem) { /* bail if we got disconnected */
76daa3
+                return;
76daa3
+            }
76daa3
             if (port->throttled) {
76daa3
                 port->iov_idx = i;
76daa3
                 if (ret > 0) {
76daa3
-- 
76daa3
1.8.3.1
76daa3