From 1060a0ef70a95cfe451711de4ba13b05318bd84a Mon Sep 17 00:00:00 2001 From: Chen Qun Date: Thu, 2 Sep 2021 13:44:12 +0800 Subject: [PATCH 1/3] virtio-net: fix use after unmap/free for sg When mergeable buffer is enabled, we try to set the num_buffers after the virtqueue elem has been unmapped. This will lead several issues, E.g a use after free when the descriptor has an address which belongs to the non direct access region. In this case we use bounce buffer that is allocated during address_space_map() and freed during address_space_unmap(). Fixing this by storing the elems temporarily in an array and delay the unmap after we set the the num_buffers. This addresses CVE-2021-3748. Reported-by: Alexander Bulekov Fixes: fbe78f4f55c6 ("virtio-net support") Cc: qemu-stable@nongnu.org Signed-off-by: Jason Wang Signed-off-by: imxcc --- ...-net-fix-use-after-unmap-free-for-sg.patch | 123 ++++++++++++++++++ 1 file changed, 123 insertions(+) create mode 100644 virtio-net-fix-use-after-unmap-free-for-sg.patch diff --git a/virtio-net-fix-use-after-unmap-free-for-sg.patch b/virtio-net-fix-use-after-unmap-free-for-sg.patch new file mode 100644 index 0000000..ee1fa06 --- /dev/null +++ b/virtio-net-fix-use-after-unmap-free-for-sg.patch @@ -0,0 +1,123 @@ +From 662633f388c5cead35b6ba5428dc9ab88710a471 Mon Sep 17 00:00:00 2001 +From: Jason Wang +Date: Thu, 2 Sep 2021 13:44:12 +0800 +Subject: [PATCH] virtio-net: fix use after unmap/free for sg + +When mergeable buffer is enabled, we try to set the num_buffers after +the virtqueue elem has been unmapped. This will lead several issues, +E.g a use after free when the descriptor has an address which belongs +to the non direct access region. In this case we use bounce buffer +that is allocated during address_space_map() and freed during +address_space_unmap(). + +Fixing this by storing the elems temporarily in an array and delay the +unmap after we set the the num_buffers. + +This addresses CVE-2021-3748. + +Reported-by: Alexander Bulekov +Fixes: fbe78f4f55c6 ("virtio-net support") +Cc: qemu-stable@nongnu.org +Signed-off-by: Jason Wang +Signed-off-by: imxcc +--- + hw/net/virtio-net.c | 39 ++++++++++++++++++++++++++++++++------- + 1 file changed, 32 insertions(+), 7 deletions(-) + +diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c +index 63f1bae99c..f93823d06d 100644 +--- a/hw/net/virtio-net.c ++++ b/hw/net/virtio-net.c +@@ -1265,10 +1265,13 @@ static ssize_t virtio_net_receive_rcu(NetClientState *nc, const uint8_t *buf, + VirtIONet *n = qemu_get_nic_opaque(nc); + VirtIONetQueue *q = virtio_net_get_subqueue(nc); + VirtIODevice *vdev = VIRTIO_DEVICE(n); ++ VirtQueueElement *elems[VIRTQUEUE_MAX_SIZE]; ++ size_t lens[VIRTQUEUE_MAX_SIZE]; + struct iovec mhdr_sg[VIRTQUEUE_MAX_SIZE]; + struct virtio_net_hdr_mrg_rxbuf mhdr; + unsigned mhdr_cnt = 0; +- size_t offset, i, guest_offset; ++ size_t offset, i, guest_offset, j; ++ ssize_t err; + + if (!virtio_net_can_receive(nc)) { + return -1; +@@ -1291,6 +1294,12 @@ static ssize_t virtio_net_receive_rcu(NetClientState *nc, const uint8_t *buf, + + total = 0; + ++ if (i == VIRTQUEUE_MAX_SIZE) { ++ virtio_error(vdev, "virtio-net unexpected long buffer chain"); ++ err = size; ++ goto err; ++ } ++ + elem = virtqueue_pop(q->rx_vq, sizeof(VirtQueueElement)); + if (!elem) { + if (i) { +@@ -1302,7 +1311,8 @@ static ssize_t virtio_net_receive_rcu(NetClientState *nc, const uint8_t *buf, + n->guest_hdr_len, n->host_hdr_len, + vdev->guest_features); + } +- return -1; ++ err = -1; ++ goto err; + } + + if (elem->in_num < 1) { +@@ -1310,7 +1320,8 @@ static ssize_t virtio_net_receive_rcu(NetClientState *nc, const uint8_t *buf, + "virtio-net receive queue contains no in buffers"); + virtqueue_detach_element(q->rx_vq, elem, 0); + g_free(elem); +- return -1; ++ err = -1; ++ goto err; + } + + sg = elem->in_sg; +@@ -1342,12 +1353,13 @@ static ssize_t virtio_net_receive_rcu(NetClientState *nc, const uint8_t *buf, + if (!n->mergeable_rx_bufs && offset < size) { + virtqueue_unpop(q->rx_vq, elem, total); + g_free(elem); +- return size; ++ err = size; ++ goto err; + } + +- /* signal other side */ +- virtqueue_fill(q->rx_vq, elem, total, i++); +- g_free(elem); ++ elems[i] = elem; ++ lens[i] = total; ++ i++; + } + + if (mhdr_cnt) { +@@ -1357,10 +1369,23 @@ static ssize_t virtio_net_receive_rcu(NetClientState *nc, const uint8_t *buf, + &mhdr.num_buffers, sizeof mhdr.num_buffers); + } + ++ for (j = 0; j < i; j++) { ++ /* signal other side */ ++ virtqueue_fill(q->rx_vq, elems[j], lens[j], j); ++ g_free(elems[j]); ++ } ++ + virtqueue_flush(q->rx_vq, i); + virtio_notify(vdev, q->rx_vq); + + return size; ++ ++err: ++ for (j = 0; j < i; j++) { ++ g_free(elems[j]); ++ } ++ ++ return err; + } + + static ssize_t virtio_net_do_receive(NetClientState *nc, const uint8_t *buf, +-- +2.27.0 + -- Gitee From ed707fa2787369f1df129bafb4bf9b162b3fd0f9 Mon Sep 17 00:00:00 2001 From: Chen Qun Date: Sun, 26 Sep 2021 16:28:37 +0800 Subject: [PATCH 2/3] spec: Update patch and changelog with !204 fix CVE-2021-3748 !204 virtio-net: fix use after unmap/free for sg Signed-off-by: Chen Qun --- qemu.spec | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/qemu.spec b/qemu.spec index 7bb1ad1..36699b5 100644 --- a/qemu.spec +++ b/qemu.spec @@ -559,6 +559,7 @@ Patch0546: usbredir-fix-free-call.patch Patch0547: vfio-common-Fix-incorrect-address-alignment-in-vfio_.patch Patch0548: vfio-common-Add-address-alignment-check-in-vfio_list.patch Patch0549: uas-add-stream-number-sanity-checks.patch +Patch0550: virtio-net-fix-use-after-unmap-free-for-sg.patch BuildRequires: flex BuildRequires: gcc @@ -962,6 +963,9 @@ getent passwd qemu >/dev/null || \ %endif %changelog +* Sun Sep 26 2021 Chen Qun +- virtio-net: fix use after unmap/free for sg + * Thu Sep 16 2021 Chen Qun - uas: add stream number sanity checks. -- Gitee From e7c93b74e5049ae5b93d34b31e798fe18ce037b0 Mon Sep 17 00:00:00 2001 From: Chen Qun Date: Sun, 26 Sep 2021 16:28:51 +0800 Subject: [PATCH 3/3] spec: Update release version with !204 increase release verison by one Signed-off-by: Chen Qun --- qemu.spec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/qemu.spec b/qemu.spec index 36699b5..f0008a5 100644 --- a/qemu.spec +++ b/qemu.spec @@ -1,6 +1,6 @@ Name: qemu Version: 4.1.0 -Release: 81 +Release: 82 Epoch: 2 Summary: QEMU is a generic and open source machine emulator and virtualizer License: GPLv2 and BSD and MIT and CC-BY-SA-4.0 -- Gitee