diff --git a/block-nbd-extract-the-common-cleanup-code.patch b/block-nbd-extract-the-common-cleanup-code.patch new file mode 100644 index 0000000000000000000000000000000000000000..4cc24818b7c96cc8c85a0c8ac97dc2452c234610 --- /dev/null +++ b/block-nbd-extract-the-common-cleanup-code.patch @@ -0,0 +1,67 @@ +From 1196a2079a558cbb673e06142fa67a401c5e6c30 Mon Sep 17 00:00:00 2001 +From: Pan Nengyuan +Date: Thu, 5 Dec 2019 11:45:27 +0800 +Subject: [PATCH 6/9] block/nbd: extract the common cleanup code + +The BDRVNBDState cleanup code is common in two places, add +nbd_clear_bdrvstate() function to do these cleanups. + +Suggested-by: Stefano Garzarella +Signed-off-by: Pan Nengyuan +Reviewed-by: Vladimir Sementsov-Ogievskiy +Message-Id: <1575517528-44312-2-git-send-email-pannengyuan@huawei.com> +Reviewed-by: Eric Blake +[eblake: fix compilation error and commit message] +Signed-off-by: Eric Blake +Signed-off-by: AlexChen +--- + block/nbd.c | 19 ++++++++++++------- + 1 file changed, 12 insertions(+), 7 deletions(-) + +diff --git a/block/nbd.c b/block/nbd.c +index 57c1a20..3977b1e 100644 +--- a/block/nbd.c ++++ b/block/nbd.c +@@ -73,6 +73,16 @@ typedef struct BDRVNBDState { + char *export, *tlscredsid; + } BDRVNBDState; + ++static void nbd_clear_bdrvstate(BDRVNBDState *s) ++{ ++ qapi_free_SocketAddress(s->saddr); ++ s->saddr = NULL; ++ g_free(s->export); ++ s->export = NULL; ++ g_free(s->tlscredsid); ++ s->tlscredsid = NULL; ++} ++ + static void nbd_recv_coroutines_wake_all(BDRVNBDState *s) + { + int i; +@@ -1640,9 +1650,7 @@ static int nbd_open(BlockDriverState *bs, QDict *options, int flags, + object_unref(OBJECT(tlscreds)); + } + if (ret < 0) { +- qapi_free_SocketAddress(s->saddr); +- g_free(s->export); +- g_free(s->tlscredsid); ++ nbd_clear_bdrvstate(s); + } + qemu_opts_del(opts); + return ret; +@@ -1692,10 +1700,7 @@ static void nbd_close(BlockDriverState *bs) + BDRVNBDState *s = bs->opaque; + + nbd_client_close(bs); +- +- qapi_free_SocketAddress(s->saddr); +- g_free(s->export); +- g_free(s->tlscredsid); ++ nbd_clear_bdrvstate(s); + } + + static int64_t nbd_getlength(BlockDriverState *bs) +-- +1.8.3.1 + diff --git a/migration-savevm-release-gslist-after-dump_vmstate_j.patch b/migration-savevm-release-gslist-after-dump_vmstate_j.patch new file mode 100644 index 0000000000000000000000000000000000000000..d5ec9b881005dc21ec927a9f4b37f57999c89c1f --- /dev/null +++ b/migration-savevm-release-gslist-after-dump_vmstate_j.patch @@ -0,0 +1,63 @@ +From 0d8c145e986d4f500f065d2d8645e95175324e62 Mon Sep 17 00:00:00 2001 +From: Pan Nengyuan +Date: Wed, 19 Feb 2020 17:47:05 +0800 +Subject: [PATCH 8/9] migration/savevm: release gslist after dump_vmstate_json + +'list' forgot to free at the end of dump_vmstate_json_to_file(), although it's called only once, but seems like a clean code. + +Fix the leak as follow: +Direct leak of 16 byte(s) in 1 object(s) allocated from: + #0 0x7fb946abd768 in __interceptor_malloc (/lib64/libasan.so.5+0xef768) + #1 0x7fb945eca445 in g_malloc (/lib64/libglib-2.0.so.0+0x52445) + #2 0x7fb945ee2066 in g_slice_alloc (/lib64/libglib-2.0.so.0+0x6a066) + #3 0x7fb945ee3139 in g_slist_prepend (/lib64/libglib-2.0.so.0+0x6b139) + #4 0x5585db591581 in object_class_get_list_tramp /mnt/sdb/qemu-new/qemu/qom/object.c:1084 + #5 0x5585db590f66 in object_class_foreach_tramp /mnt/sdb/qemu-new/qemu/qom/object.c:1028 + #6 0x7fb945eb35f7 in g_hash_table_foreach (/lib64/libglib-2.0.so.0+0x3b5f7) + #7 0x5585db59110c in object_class_foreach /mnt/sdb/qemu-new/qemu/qom/object.c:1038 + #8 0x5585db5916b6 in object_class_get_list /mnt/sdb/qemu-new/qemu/qom/object.c:1092 + #9 0x5585db335ca0 in dump_vmstate_json_to_file /mnt/sdb/qemu-new/qemu/migration/savevm.c:638 + #10 0x5585daa5bcbf in main /mnt/sdb/qemu-new/qemu/vl.c:4420 + #11 0x7fb941204812 in __libc_start_main ../csu/libc-start.c:308 + #12 0x5585da29420d in _start (/mnt/sdb/qemu-new/qemu/build/x86_64-softmmu/qemu-system-x86_64+0x27f020d) + +Indirect leak of 7472 byte(s) in 467 object(s) allocated from: + #0 0x7fb946abd768 in __interceptor_malloc (/lib64/libasan.so.5+0xef768) + #1 0x7fb945eca445 in g_malloc (/lib64/libglib-2.0.so.0+0x52445) + #2 0x7fb945ee2066 in g_slice_alloc (/lib64/libglib-2.0.so.0+0x6a066) + #3 0x7fb945ee3139 in g_slist_prepend (/lib64/libglib-2.0.so.0+0x6b139) + #4 0x5585db591581 in object_class_get_list_tramp /mnt/sdb/qemu-new/qemu/qom/object.c:1084 + #5 0x5585db590f66 in object_class_foreach_tramp /mnt/sdb/qemu-new/qemu/qom/object.c:1028 + #6 0x7fb945eb35f7 in g_hash_table_foreach (/lib64/libglib-2.0.so.0+0x3b5f7) + #7 0x5585db59110c in object_class_foreach /mnt/sdb/qemu-new/qemu/qom/object.c:1038 + #8 0x5585db5916b6 in object_class_get_list /mnt/sdb/qemu-new/qemu/qom/object.c:1092 + #9 0x5585db335ca0 in dump_vmstate_json_to_file /mnt/sdb/qemu-new/qemu/migration/savevm.c:638 + #10 0x5585daa5bcbf in main /mnt/sdb/qemu-new/qemu/vl.c:4420 + #11 0x7fb941204812 in __libc_start_main ../csu/libc-start.c:308 + #12 0x5585da29420d in _start (/mnt/sdb/qemu-new/qemu/build/x86_64-softmmu/qemu-system-x86_64+0x27f020d) + +Reported-by: Euler Robot +Signed-off-by: Pan Nengyuan +Reviewed-by: Juan Quintela +Reviewed-by: Dr. David Alan Gilbert +Signed-off-by: Juan Quintela +Signed-off-by: AlexChen +--- + migration/savevm.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/migration/savevm.c b/migration/savevm.c +index 7d89c57..8163de7 100644 +--- a/migration/savevm.c ++++ b/migration/savevm.c +@@ -614,6 +614,7 @@ void dump_vmstate_json_to_file(FILE *out_file) + } + fprintf(out_file, "\n}\n"); + fclose(out_file); ++ g_slist_free(list); + } + + static uint32_t calculate_new_instance_id(const char *idstr) +-- +1.8.3.1 + diff --git a/qemu.spec b/qemu.spec index a6a76a55d88e499c0396bd3155dabadd4806e898..0afa0c340b7092c3a84d46db1be9483dd81166bc 100644 --- a/qemu.spec +++ b/qemu.spec @@ -1,6 +1,6 @@ Name: qemu Version: 4.1.0 -Release: 27 +Release: 28 Epoch: 2 Summary: QEMU is a generic and open source machine emulator and virtualizer License: GPLv2 and BSD and MIT and CC-BY @@ -280,6 +280,15 @@ Patch0267: migration-Define-VMSTATE_INSTANCE_ID_ANY.patch Patch0268: migration-Change-SaveStateEntry.instance_id-into-uin.patch Patch0269: apic-Use-32bit-APIC-ID-for-migration-instance-ID.patch Patch0270: Drop-bogus-IPv6-messages.patch +Patch0271: virtio-add-ability-to-delete-vq-through-a-pointer.patch +Patch0272: virtio-pmem-do-delete-rq_vq-in-virtio_pmem_unrealize.patch +Patch0273: virtio-crypto-do-delete-ctrl_vq-in-virtio_crypto_dev.patch +Patch0274: vhost-user-blk-delete-virtioqueues-in-unrealize-to-f.patch +Patch0275: vhost-user-blk-convert-to-new-virtio_delete_queue.patch +Patch0276: block-nbd-extract-the-common-cleanup-code.patch +Patch0277: virtio-gracefully-handle-invalid-region-caches.patch +Patch0278: migration-savevm-release-gslist-after-dump_vmstate_j.patch +Patch0279: virtio-input-fix-memory-leak-on-unrealize.patch BuildRequires: flex BuildRequires: bison @@ -626,17 +635,28 @@ getent passwd qemu >/dev/null || \ %endif %changelog +* Fri sep 11 2020 Huawei Technologies Co., Ltd +- virtio: add ability to delete vq through a pointer +- virtio-pmem: do delete rq_vq in virtio_pmem_unrealize +- virtio-crypto: do delete ctrl_vq in virtio_crypto_device_unrealize +- vhost-user-blk: delete virtioqueues in unrealize to fix memleaks +- vhost-user-blk: convert to new virtio_delete_queue +- block/nbd: extract the common cleanup code +- virtio: gracefully handle invalid region caches +- migration/savevm: release gslist after dump_vmstate_json +- virtio-input: fix memory leak on unrealize + * Fri sep 11 2020 Huawei Technologies Co., Ltd - slir/src/ip6_input.c: fix out-of-bounds read information vulnerablity * Thu sep 10 2020 Huawei Technologies Co., Ltd -- apic-Use-32bit-APIC-ID-for-migration-instance-ID.patch -- audio-fix-integer-overflow.patch -- display-bochs-display-fix-memory-leak.patch -- migration-Change-SaveStateEntry.instance_id-into-uin.patch -- migration-Define-VMSTATE_INSTANCE_ID_ANY.patch -- migration-multifd-clean-pages-after-filling-packet.patch -- migration-multifd-not-use-multifd-during-postcopy.patch +- apic: Use 32bit APIC ID for migration instance-ID +- audio: fix integer overflow +- display/bochs-display: fix memory leak +- migration: Change SaveStateEntry.instance_id into uint32_t +- migration: Define VMSTATE_INSTANCE_ID_ANY +- migration/multifd: clean pages after filling packet +- migration/multifd: not use multifd during postcopy * Wed Sep 09 2020 Huawei Technologies Co., Ltd - usbredir-fix-buffer-overflow-on-vmload.patch diff --git a/vhost-user-blk-convert-to-new-virtio_delete_queue.patch b/vhost-user-blk-convert-to-new-virtio_delete_queue.patch new file mode 100644 index 0000000000000000000000000000000000000000..3f419966ec034fe4eecd8e6606b6e7dc611517e1 --- /dev/null +++ b/vhost-user-blk-convert-to-new-virtio_delete_queue.patch @@ -0,0 +1,99 @@ +From 30d20e1258722431198cd2a8298c85b7af2a0c1b Mon Sep 17 00:00:00 2001 +From: Pan Nengyuan +Date: Mon, 24 Feb 2020 12:13:36 +0800 +Subject: [PATCH 5/9] vhost-user-blk: convert to new virtio_delete_queue + +use the new virtio_delete_queue function to cleanup. + +Signed-off-by: Pan Nengyuan +Message-Id: <20200224041336.30790-3-pannengyuan@huawei.com> +Reviewed-by: Stefan Hajnoczi +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Michael S. Tsirkin +Signed-off-by: AlexChen +--- + hw/block/vhost-user-blk.c | 20 ++++++++++++-------- + include/hw/virtio/vhost-user-blk.h | 4 +++- + 2 files changed, 15 insertions(+), 9 deletions(-) + +diff --git a/hw/block/vhost-user-blk.c b/hw/block/vhost-user-blk.c +index dbc0a2e..146b927 100644 +--- a/hw/block/vhost-user-blk.c ++++ b/hw/block/vhost-user-blk.c +@@ -303,7 +303,7 @@ static int vhost_user_blk_connect(DeviceState *dev) + s->connected = true; + + s->dev.nvqs = s->num_queues; +- s->dev.vqs = s->vqs; ++ s->dev.vqs = s->vhost_vqs; + s->dev.vq_index = 0; + s->dev.backend_features = 0; + +@@ -430,13 +430,15 @@ static void vhost_user_blk_device_realize(DeviceState *dev, Error **errp) + virtio_init(vdev, "virtio-blk", VIRTIO_ID_BLOCK, + sizeof(struct virtio_blk_config)); + ++ s->virtqs = g_new(VirtQueue *, s->num_queues); + for (i = 0; i < s->num_queues; i++) { +- virtio_add_queue(vdev, s->queue_size, +- vhost_user_blk_handle_output); ++ s->virtqs[i] = virtio_add_queue(vdev, s->queue_size, ++ vhost_user_blk_handle_output); + } + + s->inflight = g_new0(struct vhost_inflight, 1); +- s->vqs = g_new(struct vhost_virtqueue, s->num_queues); ++ s->vhost_vqs = g_new0(struct vhost_virtqueue, s->num_queues); ++ s->watch = 0; + s->connected = false; + + qemu_chr_fe_set_handlers(&s->chardev, NULL, NULL, vhost_user_blk_event, +@@ -467,11 +469,12 @@ reconnect: + return; + + virtio_err: +- g_free(s->vqs); ++ g_free(s->vhost_vqs); + g_free(s->inflight); + for (i = 0; i < s->num_queues; i++) { +- virtio_del_queue(vdev, i); ++ virtio_delete_queue(s->virtqs[i]); + } ++ g_free(s->virtqs); + virtio_cleanup(vdev); + vhost_user_cleanup(&s->vhost_user); + } +@@ -487,12 +490,13 @@ static void vhost_user_blk_device_unrealize(DeviceState *dev, Error **errp) + NULL, NULL, NULL, false); + vhost_dev_cleanup(&s->dev); + vhost_dev_free_inflight(s->inflight); +- g_free(s->vqs); ++ g_free(s->vhost_vqs); + g_free(s->inflight); + + for (i = 0; i < s->num_queues; i++) { +- virtio_del_queue(vdev, i); ++ virtio_delete_queue(s->virtqs[i]); + } ++ g_free(s->virtqs); + virtio_cleanup(vdev); + vhost_user_cleanup(&s->vhost_user); + } +diff --git a/include/hw/virtio/vhost-user-blk.h b/include/hw/virtio/vhost-user-blk.h +index ad9b742..29375dd 100644 +--- a/include/hw/virtio/vhost-user-blk.h ++++ b/include/hw/virtio/vhost-user-blk.h +@@ -37,7 +37,9 @@ typedef struct VHostUserBlk { + struct vhost_dev dev; + struct vhost_inflight *inflight; + VhostUserState vhost_user; +- struct vhost_virtqueue *vqs; ++ struct vhost_virtqueue *vhost_vqs; ++ VirtQueue **virtqs; ++ guint watch; + bool connected; + } VHostUserBlk; + +-- +1.8.3.1 + diff --git a/vhost-user-blk-delete-virtioqueues-in-unrealize-to-f.patch b/vhost-user-blk-delete-virtioqueues-in-unrealize-to-f.patch new file mode 100644 index 0000000000000000000000000000000000000000..e57f5b59c972cf4c769d7b87cc2a654b72eb3b64 --- /dev/null +++ b/vhost-user-blk-delete-virtioqueues-in-unrealize-to-f.patch @@ -0,0 +1,69 @@ +From d8febdc4940d719dba77a17a10a8d36ad08305ab Mon Sep 17 00:00:00 2001 +From: Pan Nengyuan +Date: Mon, 24 Feb 2020 12:13:35 +0800 +Subject: [PATCH 4/9] vhost-user-blk: delete virtioqueues in unrealize to fix + memleaks + +virtio queues forgot to delete in unrealize, and aslo error path in +realize, this patch fix these memleaks, the leak stack is as follow: + +Direct leak of 114688 byte(s) in 16 object(s) allocated from: + #0 0x7f24024fdbf0 in calloc (/lib64/libasan.so.3+0xcabf0) + #1 0x7f2401642015 in g_malloc0 (/lib64/libglib-2.0.so.0+0x50015) + #2 0x55ad175a6447 in virtio_add_queue /mnt/sdb/qemu/hw/virtio/virtio.c:2327 + #3 0x55ad17570cf9 in vhost_user_blk_device_realize /mnt/sdb/qemu/hw/block/vhost-user-blk.c:419 + #4 0x55ad175a3707 in virtio_device_realize /mnt/sdb/qemu/hw/virtio/virtio.c:3509 + #5 0x55ad176ad0d1 in device_set_realized /mnt/sdb/qemu/hw/core/qdev.c:876 + #6 0x55ad1781ff9d in property_set_bool /mnt/sdb/qemu/qom/object.c:2080 + #7 0x55ad178245ae in object_property_set_qobject /mnt/sdb/qemu/qom/qom-qobject.c:26 + #8 0x55ad17821eb4 in object_property_set_bool /mnt/sdb/qemu/qom/object.c:1338 + #9 0x55ad177aeed7 in virtio_pci_realize /mnt/sdb/qemu/hw/virtio/virtio-pci.c:1801 + +Reported-by: Euler Robot +Signed-off-by: Pan Nengyuan +Reviewed-by: Stefan Hajnoczi +Message-Id: <20200224041336.30790-2-pannengyuan@huawei.com> +Reviewed-by: Stefan Hajnoczi +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Michael S. Tsirkin +Signed-off-by: AlexChen +--- + hw/block/vhost-user-blk.c | 8 ++++++++ + 1 file changed, 8 insertions(+) + +diff --git a/hw/block/vhost-user-blk.c b/hw/block/vhost-user-blk.c +index 6b719d1..dbc0a2e 100644 +--- a/hw/block/vhost-user-blk.c ++++ b/hw/block/vhost-user-blk.c +@@ -469,6 +469,9 @@ reconnect: + virtio_err: + g_free(s->vqs); + g_free(s->inflight); ++ for (i = 0; i < s->num_queues; i++) { ++ virtio_del_queue(vdev, i); ++ } + virtio_cleanup(vdev); + vhost_user_cleanup(&s->vhost_user); + } +@@ -477,6 +480,7 @@ static void vhost_user_blk_device_unrealize(DeviceState *dev, Error **errp) + { + VirtIODevice *vdev = VIRTIO_DEVICE(dev); + VHostUserBlk *s = VHOST_USER_BLK(dev); ++ int i; + + virtio_set_status(vdev, 0); + qemu_chr_fe_set_handlers(&s->chardev, NULL, NULL, NULL, +@@ -485,6 +489,10 @@ static void vhost_user_blk_device_unrealize(DeviceState *dev, Error **errp) + vhost_dev_free_inflight(s->inflight); + g_free(s->vqs); + g_free(s->inflight); ++ ++ for (i = 0; i < s->num_queues; i++) { ++ virtio_del_queue(vdev, i); ++ } + virtio_cleanup(vdev); + vhost_user_cleanup(&s->vhost_user); + } +-- +1.8.3.1 + diff --git a/virtio-add-ability-to-delete-vq-through-a-pointer.patch b/virtio-add-ability-to-delete-vq-through-a-pointer.patch new file mode 100644 index 0000000000000000000000000000000000000000..e0989895e40fe4e0d3816966a24075d74b8797a0 --- /dev/null +++ b/virtio-add-ability-to-delete-vq-through-a-pointer.patch @@ -0,0 +1,61 @@ +From 98ae454efe48b2a465dfe9bc3c412b6375f1fbfc Mon Sep 17 00:00:00 2001 +From: "Michael S. Tsirkin" +Date: Mon, 9 Dec 2019 11:46:13 -0500 +Subject: [PATCH 1/9] virtio: add ability to delete vq through a pointer + +Devices tend to maintain vq pointers, allow deleting them trough a vq pointer. + +Signed-off-by: Michael S. Tsirkin +Reviewed-by: David Hildenbrand +Signed-off-by: AlexChen +--- + hw/virtio/virtio.c | 13 +++++++++---- + include/hw/virtio/virtio.h | 2 ++ + 2 files changed, 11 insertions(+), 4 deletions(-) + +diff --git a/hw/virtio/virtio.c b/hw/virtio/virtio.c +index 79c2dcf..3d027d3 100644 +--- a/hw/virtio/virtio.c ++++ b/hw/virtio/virtio.c +@@ -1636,16 +1636,21 @@ VirtQueue *virtio_add_queue(VirtIODevice *vdev, int queue_size, + return &vdev->vq[i]; + } + ++void virtio_delete_queue(VirtQueue *vq) ++{ ++ vq->vring.num = 0; ++ vq->vring.num_default = 0; ++ vq->handle_output = NULL; ++ vq->handle_aio_output = NULL; ++} ++ + void virtio_del_queue(VirtIODevice *vdev, int n) + { + if (n < 0 || n >= VIRTIO_QUEUE_MAX) { + abort(); + } + +- vdev->vq[n].vring.num = 0; +- vdev->vq[n].vring.num_default = 0; +- vdev->vq[n].handle_output = NULL; +- vdev->vq[n].handle_aio_output = NULL; ++ virtio_delete_queue(&vdev->vq[n]); + } + + static void virtio_set_isr(VirtIODevice *vdev, int value) +diff --git a/include/hw/virtio/virtio.h b/include/hw/virtio/virtio.h +index f9f6237..ca2fbae 100644 +--- a/include/hw/virtio/virtio.h ++++ b/include/hw/virtio/virtio.h +@@ -187,6 +187,8 @@ VirtQueue *virtio_add_queue(VirtIODevice *vdev, int queue_size, + + void virtio_del_queue(VirtIODevice *vdev, int n); + ++void virtio_delete_queue(VirtQueue *vq); ++ + void virtqueue_push(VirtQueue *vq, const VirtQueueElement *elem, + unsigned int len); + void virtqueue_flush(VirtQueue *vq, unsigned int count); +-- +1.8.3.1 + diff --git a/virtio-crypto-do-delete-ctrl_vq-in-virtio_crypto_dev.patch b/virtio-crypto-do-delete-ctrl_vq-in-virtio_crypto_dev.patch new file mode 100644 index 0000000000000000000000000000000000000000..aab3e86663021d2576763fff2a4f9c5985a2fb32 --- /dev/null +++ b/virtio-crypto-do-delete-ctrl_vq-in-virtio_crypto_dev.patch @@ -0,0 +1,55 @@ +From 62ded4fc6b38e2642ea4d95a93d70d0f608bee65 Mon Sep 17 00:00:00 2001 +From: Pan Nengyuan +Date: Tue, 25 Feb 2020 15:55:54 +0800 +Subject: [PATCH 3/9] virtio-crypto: do delete ctrl_vq in + virtio_crypto_device_unrealize + +Similar to other virtio-deivces, ctrl_vq forgot to delete in virtio_crypto_device_unrealize, this patch fix it. +This device has aleardy maintained vq pointers. Thus, we use the new virtio_delete_queue function directly to do the cleanup. + +The leak stack: +Direct leak of 10752 byte(s) in 3 object(s) allocated from: + #0 0x7f4c024b1970 in __interceptor_calloc (/lib64/libasan.so.5+0xef970) + #1 0x7f4c018be49d in g_malloc0 (/lib64/libglib-2.0.so.0+0x5249d) + #2 0x55a2f8017279 in virtio_add_queue /mnt/sdb/qemu-new/qemu_test/qemu/hw/virtio/virtio.c:2333 + #3 0x55a2f8057035 in virtio_crypto_device_realize /mnt/sdb/qemu-new/qemu_test/qemu/hw/virtio/virtio-crypto.c:814 + #4 0x55a2f8005d80 in virtio_device_realize /mnt/sdb/qemu-new/qemu_test/qemu/hw/virtio/virtio.c:3531 + #5 0x55a2f8497d1b in device_set_realized /mnt/sdb/qemu-new/qemu_test/qemu/hw/core/qdev.c:891 + #6 0x55a2f8b48595 in property_set_bool /mnt/sdb/qemu-new/qemu_test/qemu/qom/object.c:2238 + #7 0x55a2f8b54fad in object_property_set_qobject /mnt/sdb/qemu-new/qemu_test/qemu/qom/qom-qobject.c:26 + #8 0x55a2f8b4de2c in object_property_set_bool /mnt/sdb/qemu-new/qemu_test/qemu/qom/object.c:1390 + #9 0x55a2f80609c9 in virtio_crypto_pci_realize /mnt/sdb/qemu-new/qemu_test/qemu/hw/virtio/virtio-crypto-pci.c:58 + +Reported-by: Euler Robot +Signed-off-by: Pan Nengyuan +Cc: "Gonglei (Arei)" +Message-Id: <20200225075554.10835-5-pannengyuan@huawei.com> +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Michael S. Tsirkin +Signed-off-by: AlexChen +--- + hw/virtio/virtio-crypto.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/hw/virtio/virtio-crypto.c b/hw/virtio/virtio-crypto.c +index 45187d3..0076b4b 100644 +--- a/hw/virtio/virtio-crypto.c ++++ b/hw/virtio/virtio-crypto.c +@@ -830,12 +830,13 @@ static void virtio_crypto_device_unrealize(DeviceState *dev, Error **errp) + + max_queues = vcrypto->multiqueue ? vcrypto->max_queues : 1; + for (i = 0; i < max_queues; i++) { +- virtio_del_queue(vdev, i); ++ virtio_delete_queue(vcrypto->vqs[i].dataq); + q = &vcrypto->vqs[i]; + qemu_bh_delete(q->dataq_bh); + } + + g_free(vcrypto->vqs); ++ virtio_delete_queue(vcrypto->ctrl_vq); + + virtio_cleanup(vdev); + cryptodev_backend_set_used(vcrypto->cryptodev, false); +-- +1.8.3.1 + diff --git a/virtio-gracefully-handle-invalid-region-caches.patch b/virtio-gracefully-handle-invalid-region-caches.patch new file mode 100644 index 0000000000000000000000000000000000000000..2793f21b0d988625b4f53624c471c403937fcedc --- /dev/null +++ b/virtio-gracefully-handle-invalid-region-caches.patch @@ -0,0 +1,238 @@ +From 63a3c25baa9c7372b80df80be4447552af6d6ba0 Mon Sep 17 00:00:00 2001 +From: Stefan Hajnoczi +Date: Fri, 7 Feb 2020 10:46:19 +0000 +Subject: [PATCH 7/9] 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=) at qemu/hw/virtio/virtio.c:286 + #5 vring_get_region_caches (vq=) 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=, callback=, user_data=) 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=) at util/main-loop.c:242 + #18 main_loop_wait (nonblocking=) at util/main-loop.c:518 + #19 0x00005555559b20c9 in main_loop () at vl.c:1683 + #20 0x0000555555838115 in main (argc=, argv=, envp=) at vl.c:4441 + +Reported-by: Alexander Bulekov +Cc: Michael Tsirkin +Cc: Cornelia Huck +Cc: Paolo Bonzini +Cc: qemu-stable@nongnu.org +Signed-off-by: Stefan Hajnoczi +Message-Id: <20200207104619.164892-1-stefanha@redhat.com> +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Michael S. Tsirkin +Signed-off-by: AlexChen +--- + hw/virtio/virtio.c | 66 ++++++++++++++++++++++++++++++++++++++++++++++++------ + 1 file changed, 59 insertions(+), 7 deletions(-) + +diff --git a/hw/virtio/virtio.c b/hw/virtio/virtio.c +index 3d027d3..90971f4 100644 +--- a/hw/virtio/virtio.c ++++ b/hw/virtio/virtio.c +@@ -221,15 +221,19 @@ static void vring_desc_read(VirtIODevice *vdev, VRingDesc *desc, + + static VRingMemoryRegionCaches *vring_get_region_caches(struct VirtQueue *vq) + { +- VRingMemoryRegionCaches *caches = atomic_rcu_read(&vq->vring.caches); +- assert(caches != NULL); +- return caches; ++ return atomic_rcu_read(&vq->vring.caches); + } ++ + /* Called within rcu_read_lock(). */ + static inline uint16_t vring_avail_flags(VirtQueue *vq) + { + VRingMemoryRegionCaches *caches = vring_get_region_caches(vq); + hwaddr pa = offsetof(VRingAvail, flags); ++ ++ if (!caches) { ++ return 0; ++ } ++ + return virtio_lduw_phys_cached(vq->vdev, &caches->avail, pa); + } + +@@ -238,6 +242,11 @@ static inline uint16_t vring_avail_idx(VirtQueue *vq) + { + VRingMemoryRegionCaches *caches = vring_get_region_caches(vq); + hwaddr pa = offsetof(VRingAvail, idx); ++ ++ if (!caches) { ++ return 0; ++ } ++ + vq->shadow_avail_idx = virtio_lduw_phys_cached(vq->vdev, &caches->avail, pa); + return vq->shadow_avail_idx; + } +@@ -247,6 +256,11 @@ static inline uint16_t vring_avail_ring(VirtQueue *vq, int i) + { + VRingMemoryRegionCaches *caches = vring_get_region_caches(vq); + hwaddr pa = offsetof(VRingAvail, ring[i]); ++ ++ if (!caches) { ++ return 0; ++ } ++ + return virtio_lduw_phys_cached(vq->vdev, &caches->avail, pa); + } + +@@ -262,6 +276,11 @@ static inline void vring_used_write(VirtQueue *vq, VRingUsedElem *uelem, + { + VRingMemoryRegionCaches *caches = vring_get_region_caches(vq); + hwaddr pa = offsetof(VRingUsed, ring[i]); ++ ++ if (!caches) { ++ return; ++ } ++ + virtio_tswap32s(vq->vdev, &uelem->id); + virtio_tswap32s(vq->vdev, &uelem->len); + address_space_write_cached(&caches->used, pa, uelem, sizeof(VRingUsedElem)); +@@ -273,6 +292,11 @@ static uint16_t vring_used_idx(VirtQueue *vq) + { + VRingMemoryRegionCaches *caches = vring_get_region_caches(vq); + hwaddr pa = offsetof(VRingUsed, idx); ++ ++ if (!caches) { ++ return 0; ++ } ++ + return virtio_lduw_phys_cached(vq->vdev, &caches->used, pa); + } + +@@ -281,8 +305,12 @@ static inline void vring_used_idx_set(VirtQueue *vq, uint16_t val) + { + VRingMemoryRegionCaches *caches = vring_get_region_caches(vq); + hwaddr pa = offsetof(VRingUsed, idx); +- virtio_stw_phys_cached(vq->vdev, &caches->used, pa, val); +- address_space_cache_invalidate(&caches->used, pa, sizeof(val)); ++ ++ if (caches) { ++ virtio_stw_phys_cached(vq->vdev, &caches->used, pa, val); ++ address_space_cache_invalidate(&caches->used, pa, sizeof(val)); ++ } ++ + vq->used_idx = val; + } + +@@ -292,8 +320,13 @@ static inline void vring_used_flags_set_bit(VirtQueue *vq, int mask) + VRingMemoryRegionCaches *caches = vring_get_region_caches(vq); + VirtIODevice *vdev = vq->vdev; + hwaddr pa = offsetof(VRingUsed, flags); +- uint16_t flags = virtio_lduw_phys_cached(vq->vdev, &caches->used, pa); ++ uint16_t flags; ++ ++ if (!caches) { ++ return; ++ } + ++ flags = virtio_lduw_phys_cached(vq->vdev, &caches->used, pa); + virtio_stw_phys_cached(vdev, &caches->used, pa, flags | mask); + address_space_cache_invalidate(&caches->used, pa, sizeof(flags)); + } +@@ -304,8 +337,13 @@ static inline void vring_used_flags_unset_bit(VirtQueue *vq, int mask) + VRingMemoryRegionCaches *caches = vring_get_region_caches(vq); + VirtIODevice *vdev = vq->vdev; + hwaddr pa = offsetof(VRingUsed, flags); +- uint16_t flags = virtio_lduw_phys_cached(vq->vdev, &caches->used, pa); ++ uint16_t flags; + ++ if (!caches) { ++ return; ++ } ++ ++ flags = virtio_lduw_phys_cached(vq->vdev, &caches->used, pa); + virtio_stw_phys_cached(vdev, &caches->used, pa, flags & ~mask); + address_space_cache_invalidate(&caches->used, pa, sizeof(flags)); + } +@@ -320,6 +358,10 @@ static inline void vring_set_avail_event(VirtQueue *vq, uint16_t val) + } + + caches = vring_get_region_caches(vq); ++ if (!caches) { ++ return; ++ } ++ + pa = offsetof(VRingUsed, ring[vq->vring.num]); + virtio_stw_phys_cached(vq->vdev, &caches->used, pa, val); + address_space_cache_invalidate(&caches->used, pa, sizeof(val)); +@@ -626,6 +668,11 @@ void virtqueue_get_avail_bytes(VirtQueue *vq, unsigned int *in_bytes, + + max = vq->vring.num; + caches = vring_get_region_caches(vq); ++ if (!caches) { ++ virtio_error(vdev, "Region cached not initialized"); ++ goto err; ++ } ++ + if (caches->desc.len < max * sizeof(VRingDesc)) { + virtio_error(vdev, "Cannot map descriptor ring"); + goto err; +@@ -894,6 +941,11 @@ void *virtqueue_pop(VirtQueue *vq, size_t sz) + i = head; + + caches = vring_get_region_caches(vq); ++ if (!caches) { ++ virtio_error(vdev, "Region caches not initialized"); ++ goto done; ++ } ++ + if (caches->desc.len < max * sizeof(VRingDesc)) { + virtio_error(vdev, "Cannot map descriptor ring"); + goto done; +-- +1.8.3.1 + diff --git a/virtio-input-fix-memory-leak-on-unrealize.patch b/virtio-input-fix-memory-leak-on-unrealize.patch new file mode 100644 index 0000000000000000000000000000000000000000..df83453f04525eb4b9fa29ba3d03dc6fa8b31fc5 --- /dev/null +++ b/virtio-input-fix-memory-leak-on-unrealize.patch @@ -0,0 +1,45 @@ +From e29f08036ff11bf220463b4327b315505e760a44 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= +Date: Thu, 21 Nov 2019 13:56:49 +0400 +Subject: [PATCH 9/9] virtio-input: fix memory leak on unrealize +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Spotted by ASAN + minor stylistic change. + +Signed-off-by: Marc-André Lureau +Reviewed-by: Michael S. Tsirkin +Message-Id: <20191121095649.25453-1-marcandre.lureau@redhat.com> +Signed-off-by: Michael S. Tsirkin +Signed-off-by: Marc-André Lureau +Reviewed-by: Michael S. Tsirkin +Signed-off-by: AlexChen +--- + hw/input/virtio-input.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/hw/input/virtio-input.c b/hw/input/virtio-input.c +index 9946394..401c1de 100644 +--- a/hw/input/virtio-input.c ++++ b/hw/input/virtio-input.c +@@ -275,6 +275,7 @@ static void virtio_input_finalize(Object *obj) + + g_free(vinput->queue); + } ++ + static void virtio_input_device_unrealize(DeviceState *dev, Error **errp) + { + VirtIOInputClass *vic = VIRTIO_INPUT_GET_CLASS(dev); +@@ -288,6 +289,8 @@ static void virtio_input_device_unrealize(DeviceState *dev, Error **errp) + return; + } + } ++ virtio_del_queue(vdev, 0); ++ virtio_del_queue(vdev, 1); + virtio_cleanup(vdev); + } + +-- +1.8.3.1 + diff --git a/virtio-pmem-do-delete-rq_vq-in-virtio_pmem_unrealize.patch b/virtio-pmem-do-delete-rq_vq-in-virtio_pmem_unrealize.patch new file mode 100644 index 0000000000000000000000000000000000000000..d8ed58faa8f5c6517d131ced73209bc41122158e --- /dev/null +++ b/virtio-pmem-do-delete-rq_vq-in-virtio_pmem_unrealize.patch @@ -0,0 +1,39 @@ +From 637606d18c7208e21d8ab4f318cccde64ae58c76 Mon Sep 17 00:00:00 2001 +From: Pan Nengyuan +Date: Tue, 25 Feb 2020 15:55:53 +0800 +Subject: [PATCH 2/9] virtio-pmem: do delete rq_vq in virtio_pmem_unrealize +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Similar to other virtio-devices, rq_vq forgot to delete in +virtio_pmem_unrealize, this patch fix it. This device has already +maintained a vq pointer, thus we use the new virtio_delete_queue +function directly to do the cleanup. + +Reported-by: Euler Robot +Signed-off-by: Pan Nengyuan +Message-Id: <20200225075554.10835-4-pannengyuan@huawei.com> +Reviewed-by: Philippe Mathieu-Daudé +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Michael S. Tsirkin +Signed-off-by: AlexChen +--- + hw/virtio/virtio-pmem.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/hw/virtio/virtio-pmem.c b/hw/virtio/virtio-pmem.c +index 17c196d..c680b0a 100644 +--- a/hw/virtio/virtio-pmem.c ++++ b/hw/virtio/virtio-pmem.c +@@ -127,6 +127,7 @@ static void virtio_pmem_unrealize(DeviceState *dev, Error **errp) + VirtIOPMEM *pmem = VIRTIO_PMEM(dev); + + host_memory_backend_set_mapped(pmem->memdev, false); ++ virtio_delete_queue(pmem->rq_vq); + virtio_cleanup(vdev); + } + +-- +1.8.3.1 +