Skip to content

Commit 46764fe

Browse files
stefanhaRHmstsirkin
authored andcommitted
virtio-serial: fix segfault on disconnect
Since commit d4c19cd ("virtio-serial: add missing virtio_detach_element() call") the following commands may cause QEMU to segfault: $ qemu -M accel=kvm -cpu host -m 1G \ -drive if=virtio,file=test.img,format=raw \ -device virtio-serial-pci,id=virtio-serial0 \ -chardev socket,id=channel1,path=/tmp/chardev.sock,server,nowait \ -device virtserialport,chardev=channel1,bus=virtio-serial0.0,id=port1 $ nc -U /tmp/chardev.sock ^C (guest)$ cat /dev/zero >/dev/vport0p1 The segfault is non-deterministic: if the event loop notices the socket has been closed then there is no crash. The disconnect has to happen right before QEMU attempts to write data to the socket. The backtrace is as follows: Thread 1 "qemu-system-x86" received signal SIGSEGV, Segmentation fault. 0x00005555557e0698 in do_flush_queued_data (port=0x5555582cedf0, vq=0x7fffcc854290, vdev=0x55555807b1d0) at hw/char/virtio-serial-bus.c:180 180 for (i = port->iov_idx; i < port->elem->out_num; i++) { #1 0x000055555580d363 in virtio_queue_notify_vq (vq=0x7fffcc854290) at hw/virtio/virtio.c:1524 #2 0x000055555580d363 in virtio_queue_host_notifier_read (n=0x7fffcc8542f8) at hw/virtio/virtio.c:2430 qemu#3 0x0000555555b3482c in aio_dispatch_handlers (ctx=ctx@entry=0x5555566b8c80) at util/aio-posix.c:399 qemu#4 0x0000555555b350d8 in aio_dispatch (ctx=0x5555566b8c80) at util/aio-posix.c:430 qemu#5 0x0000555555b3212e in aio_ctx_dispatch (source=<optimized out>, callback=<optimized out>, user_data=<optimized out>) at util/async.c:261 qemu#6 0x00007fffde71de52 in g_main_context_dispatch () at /lib64/libglib-2.0.so.0 qemu#7 0x0000555555b34353 in glib_pollfds_poll () at util/main-loop.c:213 qemu#8 0x0000555555b34353 in os_host_main_loop_wait (timeout=<optimized out>) at util/main-loop.c:261 qemu#9 0x0000555555b34353 in main_loop_wait (nonblocking=<optimized out>) at util/main-loop.c:517 qemu#10 0x0000555555773207 in main_loop () at vl.c:1917 qemu#11 0x0000555555773207 in main (argc=<optimized out>, argv=<optimized out>, envp=<optimized out>) at vl.c:4751 The do_flush_queued_data() function does not anticipate chardev close events during vsc->have_data(). It expects port->elem to remain non-NULL for the duration its for loop. The fix is simply to return from do_flush_queued_data() if the port closes because the close event already frees port->elem and drains the virtqueue - there is nothing left for do_flush_queued_data() to do. Reported-by: Sitong Liu <siliu@redhat.com> Reported-by: Min Deng <mdeng@redhat.com> Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com> Reviewed-by: Michael S. Tsirkin <mst@redhat.com> Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
1 parent b0ac429 commit 46764fe

File tree

1 file changed

+3
-0
lines changed

1 file changed

+3
-0
lines changed

hw/char/virtio-serial-bus.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -186,6 +186,9 @@ static void do_flush_queued_data(VirtIOSerialPort *port, VirtQueue *vq,
186186
port->elem->out_sg[i].iov_base
187187
+ port->iov_offset,
188188
buf_size);
189+
if (!port->elem) { /* bail if we got disconnected */
190+
return;
191+
}
189192
if (port->throttled) {
190193
port->iov_idx = i;
191194
if (ret > 0) {

0 commit comments

Comments
 (0)