From bb75a93a34e72c9b9d4fa77735f56210f3b420b1 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..03a9ecc --- /dev/null +++ b/virtio-net-fix-use-after-unmap-free-for-sg.patch @@ -0,0 +1,123 @@ +From 6f74d7f3f6776a4363fb07e908220ab89d0d6a16 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 6adb0fe252..22d430c7c1 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 b3ef21622be14ba6c4c0628ff35524767122dd78 Mon Sep 17 00:00:00 2001 From: Chen Qun Date: Sun, 26 Sep 2021 16:28:43 +0800 Subject: [PATCH 2/3] spec: Update patch and changelog with !202 fix CVE-2021-3748 #I4BI3F !202 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 58b785e..fbb03ab 100644 --- a/qemu.spec +++ b/qemu.spec @@ -251,6 +251,7 @@ Patch0238: hw-net-rocker_of_dpa-fix-double-free-bug-of-rocker-d.patch Patch0239: usbredir-fix-free-call.patch Patch0240: hw-arm-virt-Init-PMU-for-hotplugged-vCPU.patch Patch0241: uas-add-stream-number-sanity-checks.patch +Patch0242: virtio-net-fix-use-after-unmap-free-for-sg.patch BuildRequires: flex BuildRequires: bison @@ -596,6 +597,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 be9e3460d9ed108baf39b6333df59858ae65738c Mon Sep 17 00:00:00 2001 From: Chen Qun Date: Sun, 26 Sep 2021 16:28:59 +0800 Subject: [PATCH 3/3] spec: Update release version with !202 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 fbb03ab..faad5ad 100644 --- a/qemu.spec +++ b/qemu.spec @@ -1,6 +1,6 @@ Name: qemu Version: 4.1.0 -Release: 47 +Release: 48 Epoch: 2 Summary: QEMU is a generic and open source machine emulator and virtualizer License: GPLv2 and BSD and MIT and CC-BY -- Gitee