Comment 17 for bug 1894772

Revision history for this message
Seyeong Kim (seyeongkim) wrote :

I think below commit is included inside 2.5 qemu in Xenial but not in 2.11

and I tested it with upstream commit build with migration. but I haven't tested it yet

I'm going to test them with ubuntu releases as well.

If it is correct, we need patch > queens instead of mitaka

Description: make sure vdev->vq[i].inuse never goes below 0
 This is a work-around to fix live migrations after the patches for
 CVE-2016-5403 were applied. The true root cause still needs to be
 determined.
Origin: based on a patch by Len <email address hidden>
Bug-Ubuntu: https://bugs.launchpad.net/ubuntu/+source/qemu/+bug/1647389

Index: qemu-2.5+dfsg/hw/virtio/virtio.c
===================================================================
--- qemu-2.5+dfsg.orig/hw/virtio/virtio.c 2017-04-05 09:48:17.420025137 -0400
+++ qemu-2.5+dfsg/hw/virtio/virtio.c 2017-04-05 09:49:59.565337543 -0400
@@ -1510,6 +1510,7 @@
     for (i = 0; i < num; i++) {
         if (vdev->vq[i].vring.desc) {
             uint16_t nheads;
+ int inuse_tmp;
             nheads = vring_avail_idx(&vdev->vq[i]) - vdev->vq[i].last_avail_idx;
             /* Check it isn't doing strange things with descriptor numbers. */
             if (nheads > vdev->vq[i].vring.num) {
@@ -1527,12 +1528,15 @@
              * Since max ring size < UINT16_MAX it's safe to use modulo
              * UINT16_MAX + 1 subtraction.
              */
- vdev->vq[i].inuse = (uint16_t)(vdev->vq[i].last_avail_idx -
+ inuse_tmp = (int)(vdev->vq[i].last_avail_idx -
                                 vring_used_idx(&vdev->vq[i]));
+
+ vdev->vq[i].inuse = (inuse_tmp < 0 ? 0 : inuse_tmp);
+
             if (vdev->vq[i].inuse > vdev->vq[i].vring.num) {
- error_report("VQ %d size 0x%x < last_avail_idx 0x%x - "
+ error_report("VQ %d inuse %u size 0x%x < last_avail_idx 0x%x - "
                              "used_idx 0x%x",
- i, vdev->vq[i].vring.num,
+ i, vdev->vq[i].inuse, vdev->vq[i].vring.num,
                              vdev->vq[i].last_avail_idx,
                              vring_used_idx(&vdev->vq[i]));
                 return -1;