qemu/hw/virtio
Stefan Hajnoczi abdd16f468 virtio: gracefully handle invalid region caches
The virtqueue code sets up MemoryRegionCaches to access the virtqueue
guest RAM data structures.  The code currently assumes that
VRingMemoryRegionCaches is initialized before device emulation code
accesses the virtqueue.  An assertion will fail in
vring_get_region_caches() when this is not true.  Device fuzzing found a
case where this assumption is false (see below).

Virtqueue guest RAM addresses can also be changed from a vCPU thread
while an IOThread is accessing the virtqueue.  This breaks the same
assumption but this time the caches could become invalid partway through
the virtqueue code.  The code fetches the caches RCU pointer multiple
times so we will need to validate the pointer every time it is fetched.

Add checks each time we call vring_get_region_caches() and treat invalid
caches as a nop: memory stores are ignored and memory reads return 0.

The fuzz test failure is as follows:

  $ qemu -M pc -device virtio-blk-pci,id=drv0,drive=drive0,addr=4.0 \
         -drive if=none,id=drive0,file=null-co://,format=raw,auto-read-only=off \
         -drive if=none,id=drive1,file=null-co://,file.read-zeroes=on,format=raw \
         -display none \
         -qtest stdio
  endianness
  outl 0xcf8 0x80002020
  outl 0xcfc 0xe0000000
  outl 0xcf8 0x80002004
  outw 0xcfc 0x7
  write 0xe0000000 0x24 0x00ffffffabffffffabffffffabffffffabffffffabffffffabffffffabffffffabffffffabffffffabffffffabffffffabffffffabffffffab5cffffffabffffffabffffffabffffffabffffffabffffffabffffffabffffffabffffffabffffffabffffffabffffffabffffffabffffffabffffffab0000000001
  inb 0x4
  writew 0xe000001c 0x1
  write 0xe0000014 0x1 0x0d

The following error message is produced:

  qemu-system-x86_64: /home/stefanha/qemu/hw/virtio/virtio.c:286: vring_get_region_caches: Assertion `caches != NULL' failed.

The backtrace looks like this:

  #0  0x00007ffff5520625 in raise () at /lib64/libc.so.6
  #1  0x00007ffff55098d9 in abort () at /lib64/libc.so.6
  #2  0x00007ffff55097a9 in _nl_load_domain.cold () at /lib64/libc.so.6
  #3  0x00007ffff5518a66 in annobin_assert.c_end () at /lib64/libc.so.6
  #4  0x00005555559073da in vring_get_region_caches (vq=<optimized out>) at qemu/hw/virtio/virtio.c:286
  #5  vring_get_region_caches (vq=<optimized out>) at qemu/hw/virtio/virtio.c:283
  #6  0x000055555590818d in vring_used_flags_set_bit (mask=1, vq=0x5555575ceea0) at qemu/hw/virtio/virtio.c:398
  #7  virtio_queue_split_set_notification (enable=0, vq=0x5555575ceea0) at qemu/hw/virtio/virtio.c:398
  #8  virtio_queue_set_notification (vq=vq@entry=0x5555575ceea0, enable=enable@entry=0) at qemu/hw/virtio/virtio.c:451
  #9  0x0000555555908512 in virtio_queue_set_notification (vq=vq@entry=0x5555575ceea0, enable=enable@entry=0) at qemu/hw/virtio/virtio.c:444
  #10 0x00005555558c697a in virtio_blk_handle_vq (s=0x5555575c57e0, vq=0x5555575ceea0) at qemu/hw/block/virtio-blk.c:775
  #11 0x0000555555907836 in virtio_queue_notify_aio_vq (vq=0x5555575ceea0) at qemu/hw/virtio/virtio.c:2244
  #12 0x0000555555cb5dd7 in aio_dispatch_handlers (ctx=ctx@entry=0x55555671a420) at util/aio-posix.c:429
  #13 0x0000555555cb67a8 in aio_dispatch (ctx=0x55555671a420) at util/aio-posix.c:460
  #14 0x0000555555cb307e in aio_ctx_dispatch (source=<optimized out>, callback=<optimized out>, user_data=<optimized out>) at util/async.c:260
  #15 0x00007ffff7bbc510 in g_main_context_dispatch () at /lib64/libglib-2.0.so.0
  #16 0x0000555555cb5848 in glib_pollfds_poll () at util/main-loop.c:219
  #17 os_host_main_loop_wait (timeout=<optimized out>) at util/main-loop.c:242
  #18 main_loop_wait (nonblocking=<optimized out>) at util/main-loop.c:518
  #19 0x00005555559b20c9 in main_loop () at vl.c:1683
  #20 0x0000555555838115 in main (argc=<optimized out>, argv=<optimized out>, envp=<optimized out>) at vl.c:4441

Reported-by: Alexander Bulekov <alxndr@bu.edu>
Cc: Michael Tsirkin <mst@redhat.com>
Cc: Cornelia Huck <cohuck@redhat.com>
Cc: Paolo Bonzini <pbonzini@redhat.com>
Cc: qemu-stable@nongnu.org
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
Message-Id: <20200207104619.164892-1-stefanha@redhat.com>
Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
2020-02-27 03:45:54 -05:00
..
Kconfig configure: simplify vhost condition with Kconfig 2019-12-17 19:32:48 +01:00
Makefile.objs configure: simplify vhost condition with Kconfig 2019-12-17 19:32:48 +01:00
trace-events hw/virtio/virtio-mmio: Convert DPRINTF to trace and log 2019-05-22 15:33:20 +02:00
vhost-backend.c Include qemu/main-loop.h less 2019-08-16 13:31:52 +02:00
vhost-scsi-pci.c qdev: set properties with device_class_set_props() 2020-01-24 20:59:15 +01:00
vhost-stub.c vhost-user: simplify vhost_user_init/vhost_user_cleanup 2019-03-12 21:22:31 -04:00
vhost-user-blk-pci.c qdev: set properties with device_class_set_props() 2020-01-24 20:59:15 +01:00
vhost-user-fs-pci.c qdev: set properties with device_class_set_props() 2020-01-24 20:59:15 +01:00
vhost-user-fs.c vhost-user-fs: convert to the new virtio_delete_queue function 2020-02-25 08:32:45 -05:00
vhost-user-input-pci.c Add vhost-user-input-pci 2019-05-10 14:52:47 +02:00
vhost-user-scsi-pci.c qdev: set properties with device_class_set_props() 2020-01-24 20:59:15 +01:00
vhost-user.c vhost-user: Print unexpected slave message types 2020-01-23 16:41:37 +00:00
vhost-vsock-pci.c qdev: set properties with device_class_set_props() 2020-01-24 20:59:15 +01:00
vhost-vsock.c * Register qdev properties as class properties (Marc-André) 2020-01-27 09:44:04 +00:00
vhost.c vhost: coding style fix 2020-01-23 02:08:15 -05:00
virtio-9p-pci.c qdev: set properties with device_class_set_props() 2020-01-24 20:59:15 +01:00
virtio-balloon-pci.c qdev: set properties with device_class_set_props() 2020-01-24 20:59:15 +01:00
virtio-balloon.c qdev: set properties with device_class_set_props() 2020-01-24 20:59:15 +01:00
virtio-blk-pci.c qdev: set properties with device_class_set_props() 2020-01-24 20:59:15 +01:00
virtio-bus.c virtio: notify virtqueue via host notifier when available 2019-11-06 06:35:00 -05:00
virtio-crypto-pci.c qdev: set properties with device_class_set_props() 2020-01-24 20:59:15 +01:00
virtio-crypto.c virtio-crypto: do delete ctrl_vq in virtio_crypto_device_unrealize 2020-02-25 08:32:45 -05:00
virtio-input-host-pci.c Include qemu/module.h where needed, drop it from qemu-common.h 2019-06-12 13:18:33 +02:00
virtio-input-pci.c qdev: set properties with device_class_set_props() 2020-01-24 20:59:15 +01:00
virtio-mmio.c qdev: set properties with device_class_set_props() 2020-01-24 20:59:15 +01:00
virtio-net-pci.c qdev: set properties with device_class_set_props() 2020-01-24 20:59:15 +01:00
virtio-pci.c qdev: set properties with device_class_set_props() 2020-01-24 20:59:15 +01:00
virtio-pci.h virtio-pci: Add Function Level Reset support 2019-09-04 06:33:10 -04:00
virtio-pmem-pci.c virtio pmem: remove transitional names 2019-07-12 10:57:27 -04:00
virtio-pmem-pci.h virtio-pci: Proxy for virtio-pmem 2019-07-04 17:00:32 -04:00
virtio-pmem.c virtio-pmem: do delete rq_vq in virtio_pmem_unrealize 2020-02-25 08:32:45 -05:00
virtio-rng-pci.c Include qemu/module.h where needed, drop it from qemu-common.h 2019-06-12 13:18:33 +02:00
virtio-rng.c qdev: set properties with device_class_set_props() 2020-01-24 20:59:15 +01:00
virtio-scsi-pci.c qdev: set properties with device_class_set_props() 2020-01-24 20:59:15 +01:00
virtio-serial-pci.c qdev: set properties with device_class_set_props() 2020-01-24 20:59:15 +01:00
virtio.c virtio: gracefully handle invalid region caches 2020-02-27 03:45:54 -05:00