From 1d9099474424a9f9962619eecc0f0d6c4f73b0fe Mon Sep 17 00:00:00 2001 From: Wolfgang Bumiller Date: Tue, 9 Feb 2016 09:06:57 +0100 Subject: [PATCH] various fixes: CVE-2016-1568: ide: ahci: reset ncq object to unused on error CVE-2015-3209: pcnet: force the buffer access to be in bounds during tx CVE-2015-7504: net: pcnet: add check to validate receive data size CVE-2015-7512: pcnet: fix rx buffer overflow CVE-2015-7295: 3 patches: virtio: introduce virtqueue_unmap_sg() virtio: introduce virtqueue_discard() virtio-net: correctly drop truncated packets --- debian/patches/CVE-2015-3209-pcnet-oob.patch | 49 ++++++ ...-virtio-introduce-virtqueue_unmap_sg.patch | 153 ++++++++++++++++++ .../CVE-2015-7504-pcnet-validate-size.patch | 49 ++++++ ...E-2015-7512-pcnet-rx-buffer-overflow.patch | 37 +++++ ...-2016-1568-ide-ahci-reset-ncq-object.patch | 62 +++++++ debian/patches/series | 5 + 6 files changed, 355 insertions(+) create mode 100644 debian/patches/CVE-2015-3209-pcnet-oob.patch create mode 100644 debian/patches/CVE-2015-7295-virtio-introduce-virtqueue_unmap_sg.patch create mode 100644 debian/patches/CVE-2015-7504-pcnet-validate-size.patch create mode 100644 debian/patches/CVE-2015-7512-pcnet-rx-buffer-overflow.patch create mode 100644 debian/patches/CVE-2016-1568-ide-ahci-reset-ncq-object.patch diff --git a/debian/patches/CVE-2015-3209-pcnet-oob.patch b/debian/patches/CVE-2015-3209-pcnet-oob.patch new file mode 100644 index 0000000..53b0979 --- /dev/null +++ b/debian/patches/CVE-2015-3209-pcnet-oob.patch @@ -0,0 +1,49 @@ +From 9f7c594c006289ad41169b854d70f5da6e400a2a Mon Sep 17 00:00:00 2001 +From: Petr Matousek +Date: Sun, 24 May 2015 10:53:44 +0200 +Subject: [PATCH] pcnet: force the buffer access to be in bounds during tx + +4096 is the maximum length per TMD and it is also currently the size of +the relay buffer pcnet driver uses for sending the packet data to QEMU +for further processing. With packet spanning multiple TMDs it can +happen that the overall packet size will be bigger than sizeof(buffer), +which results in memory corruption. + +Fix this by only allowing to queue maximum sizeof(buffer) bytes. + +This is CVE-2015-3209. + +[Fixed 3-space indentation to QEMU's 4-space coding standard. +--Stefan] + +Signed-off-by: Petr Matousek +Reported-by: Matt Tait +Reviewed-by: Peter Maydell +Reviewed-by: Stefan Hajnoczi +Signed-off-by: Stefan Hajnoczi +--- + hw/net/pcnet.c | 8 ++++++++ + 1 file changed, 8 insertions(+) + +diff --git a/hw/net/pcnet.c b/hw/net/pcnet.c +index bdfd38f..68b9981 100644 +--- a/hw/net/pcnet.c ++++ b/hw/net/pcnet.c +@@ -1241,6 +1241,14 @@ static void pcnet_transmit(PCNetState *s) + } + + bcnt = 4096 - GET_FIELD(tmd.length, TMDL, BCNT); ++ ++ /* if multi-tmd packet outsizes s->buffer then skip it silently. ++ Note: this is not what real hw does */ ++ if (s->xmit_pos + bcnt > sizeof(s->buffer)) { ++ s->xmit_pos = -1; ++ goto txdone; ++ } ++ + s->phys_mem_read(s->dma_opaque, PHYSADDR(s, tmd.tbadr), + s->buffer + s->xmit_pos, bcnt, CSR_BSWP(s)); + s->xmit_pos += bcnt; +-- +2.1.4 + diff --git a/debian/patches/CVE-2015-7295-virtio-introduce-virtqueue_unmap_sg.patch b/debian/patches/CVE-2015-7295-virtio-introduce-virtqueue_unmap_sg.patch new file mode 100644 index 0000000..e73e1c0 --- /dev/null +++ b/debian/patches/CVE-2015-7295-virtio-introduce-virtqueue_unmap_sg.patch @@ -0,0 +1,153 @@ +From ce317461573bac12b10d67699b4ddf1f97cf066c Mon Sep 17 00:00:00 2001 +From: Jason Wang +Date: Fri, 25 Sep 2015 13:21:28 +0800 +Subject: [PATCH 1/3] virtio: introduce virtqueue_unmap_sg() + +Factor out sg unmapping logic. This will be reused by the patch that +can discard descriptor. + +Cc: Michael S. Tsirkin +Cc: Andrew James +Signed-off-by: Jason Wang +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Michael S. Tsirkin +--- + hw/virtio/virtio.c | 14 ++++++++++---- + 1 file changed, 10 insertions(+), 4 deletions(-) + +diff --git a/hw/virtio/virtio.c b/hw/virtio/virtio.c +index 7504f8b..6f2b96c 100644 +--- a/hw/virtio/virtio.c ++++ b/hw/virtio/virtio.c +@@ -244,14 +244,12 @@ int virtio_queue_empty(VirtQueue *vq) + return vring_avail_idx(vq) == vq->last_avail_idx; + } + +-void virtqueue_fill(VirtQueue *vq, const VirtQueueElement *elem, +- unsigned int len, unsigned int idx) ++static void virtqueue_unmap_sg(VirtQueue *vq, const VirtQueueElement *elem, ++ unsigned int len) + { + unsigned int offset; + int i; + +- trace_virtqueue_fill(vq, elem, len, idx); +- + offset = 0; + for (i = 0; i < elem->in_num; i++) { + size_t size = MIN(len - offset, elem->in_sg[i].iov_len); +@@ -267,6 +265,14 @@ void virtqueue_fill(VirtQueue *vq, const VirtQueueElement *elem, + cpu_physical_memory_unmap(elem->out_sg[i].iov_base, + elem->out_sg[i].iov_len, + 0, elem->out_sg[i].iov_len); ++} ++ ++void virtqueue_fill(VirtQueue *vq, const VirtQueueElement *elem, ++ unsigned int len, unsigned int idx) ++{ ++ trace_virtqueue_fill(vq, elem, len, idx); ++ ++ virtqueue_unmap_sg(vq, elem, len); + + idx = (idx + vring_used_idx(vq)) % vq->vring.num; + +-- +2.1.4 + +From 29b9f5efd78ae0f9cc02dd169b6e80d2c404bade Mon Sep 17 00:00:00 2001 +From: Jason Wang +Date: Fri, 25 Sep 2015 13:21:29 +0800 +Subject: [PATCH 2/3] virtio: introduce virtqueue_discard() + +This patch introduces virtqueue_discard() to discard a descriptor and +unmap the sgs. This will be used by the patch that will discard +descriptor when packet is truncated. + +Cc: Michael S. Tsirkin +Signed-off-by: Jason Wang +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Michael S. Tsirkin +--- + hw/virtio/virtio.c | 7 +++++++ + include/hw/virtio/virtio.h | 2 ++ + 2 files changed, 9 insertions(+) + +diff --git a/hw/virtio/virtio.c b/hw/virtio/virtio.c +index 6f2b96c..d0bc72e 100644 +--- a/hw/virtio/virtio.c ++++ b/hw/virtio/virtio.c +@@ -267,6 +267,13 @@ static void virtqueue_unmap_sg(VirtQueue *vq, const VirtQueueElement *elem, + 0, elem->out_sg[i].iov_len); + } + ++void virtqueue_discard(VirtQueue *vq, const VirtQueueElement *elem, ++ unsigned int len) ++{ ++ vq->last_avail_idx--; ++ virtqueue_unmap_sg(vq, elem, len); ++} ++ + void virtqueue_fill(VirtQueue *vq, const VirtQueueElement *elem, + unsigned int len, unsigned int idx) + { +diff --git a/include/hw/virtio/virtio.h b/include/hw/virtio/virtio.h +index 6201ee8..9d09115 100644 +--- a/include/hw/virtio/virtio.h ++++ b/include/hw/virtio/virtio.h +@@ -146,6 +146,8 @@ void virtio_del_queue(VirtIODevice *vdev, int n); + void virtqueue_push(VirtQueue *vq, const VirtQueueElement *elem, + unsigned int len); + void virtqueue_flush(VirtQueue *vq, unsigned int count); ++void virtqueue_discard(VirtQueue *vq, const VirtQueueElement *elem, ++ unsigned int len); + void virtqueue_fill(VirtQueue *vq, const VirtQueueElement *elem, + unsigned int len, unsigned int idx); + +-- +2.1.4 + +From 0cf33fb6b49a19de32859e2cdc6021334f448fb3 Mon Sep 17 00:00:00 2001 +From: Jason Wang +Date: Fri, 25 Sep 2015 13:21:30 +0800 +Subject: [PATCH 3/3] virtio-net: correctly drop truncated packets + +When packet is truncated during receiving, we drop the packets but +neither discard the descriptor nor add and signal used +descriptor. This will lead several issues: + +- sg mappings are leaked +- rx will be stalled if a lots of packets were truncated + +In order to be consistent with vhost, fix by discarding the descriptor +in this case. + +Cc: Michael S. Tsirkin +Signed-off-by: Jason Wang +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Michael S. Tsirkin +--- + hw/net/virtio-net.c | 8 +------- + 1 file changed, 1 insertion(+), 7 deletions(-) + +diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c +index d388c55..a877614 100644 +--- a/hw/net/virtio-net.c ++++ b/hw/net/virtio-net.c +@@ -1094,13 +1094,7 @@ static ssize_t virtio_net_receive(NetClientState *nc, const uint8_t *buf, size_t + * must have consumed the complete packet. + * Otherwise, drop it. */ + if (!n->mergeable_rx_bufs && offset < size) { +-#if 0 +- error_report("virtio-net truncated non-mergeable packet: " +- "i %zd mergeable %d offset %zd, size %zd, " +- "guest hdr len %zd, host hdr len %zd", +- i, n->mergeable_rx_bufs, +- offset, size, n->guest_hdr_len, n->host_hdr_len); +-#endif ++ virtqueue_discard(q->rx_vq, &elem, total); + return size; + } + +-- +2.1.4 + diff --git a/debian/patches/CVE-2015-7504-pcnet-validate-size.patch b/debian/patches/CVE-2015-7504-pcnet-validate-size.patch new file mode 100644 index 0000000..5c5874e --- /dev/null +++ b/debian/patches/CVE-2015-7504-pcnet-validate-size.patch @@ -0,0 +1,49 @@ +From 837f21aacf5a714c23ddaadbbc5212f9b661e3f7 Mon Sep 17 00:00:00 2001 +From: Prasad J Pandit +Date: Fri, 20 Nov 2015 11:50:31 +0530 +Subject: [PATCH] net: pcnet: add check to validate receive data + size(CVE-2015-7504) + +In loopback mode, pcnet_receive routine appends CRC code to the +receive buffer. If the data size given is same as the buffer size, +the appended CRC code overwrites 4 bytes after s->buffer. Added a +check to avoid that. + +Reported by: Qinghao Tang +Cc: qemu-stable@nongnu.org +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Prasad J Pandit +Signed-off-by: Jason Wang +--- + hw/net/pcnet.c | 8 +++++--- + 1 file changed, 5 insertions(+), 3 deletions(-) + +diff --git a/hw/net/pcnet.c b/hw/net/pcnet.c +index 0eb3cc4..309c40b 100644 +--- a/hw/net/pcnet.c ++++ b/hw/net/pcnet.c +@@ -1084,7 +1084,7 @@ ssize_t pcnet_receive(NetClientState *nc, const uint8_t *buf, size_t size_) + uint32_t fcs = ~0; + uint8_t *p = src; + +- while (p != &src[size-4]) ++ while (p != &src[size]) + CRC(fcs, *p++); + crc_err = (*(uint32_t *)p != htonl(fcs)); + } +@@ -1233,8 +1233,10 @@ static void pcnet_transmit(PCNetState *s) + bcnt = 4096 - GET_FIELD(tmd.length, TMDL, BCNT); + + /* if multi-tmd packet outsizes s->buffer then skip it silently. +- Note: this is not what real hw does */ +- if (s->xmit_pos + bcnt > sizeof(s->buffer)) { ++ * Note: this is not what real hw does. ++ * Last four bytes of s->buffer are used to store CRC FCS code. ++ */ ++ if (s->xmit_pos + bcnt > sizeof(s->buffer) - 4) { + s->xmit_pos = -1; + goto txdone; + } +-- +2.1.4 + diff --git a/debian/patches/CVE-2015-7512-pcnet-rx-buffer-overflow.patch b/debian/patches/CVE-2015-7512-pcnet-rx-buffer-overflow.patch new file mode 100644 index 0000000..e33a3b2 --- /dev/null +++ b/debian/patches/CVE-2015-7512-pcnet-rx-buffer-overflow.patch @@ -0,0 +1,37 @@ +From 8b98a2f07175d46c3f7217639bd5e03f2ec56343 Mon Sep 17 00:00:00 2001 +From: Jason Wang +Date: Mon, 30 Nov 2015 15:00:06 +0800 +Subject: [PATCH] pcnet: fix rx buffer overflow(CVE-2015-7512) + +Backends could provide a packet whose length is greater than buffer +size. Check for this and truncate the packet to avoid rx buffer +overflow in this case. + +Cc: Prasad J Pandit +Cc: qemu-stable@nongnu.org +Reviewed-by: Michael S. Tsirkin +Signed-off-by: Jason Wang +--- + hw/net/pcnet.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/hw/net/pcnet.c b/hw/net/pcnet.c +index 309c40b..1f4a3db 100644 +--- a/hw/net/pcnet.c ++++ b/hw/net/pcnet.c +@@ -1064,6 +1064,12 @@ ssize_t pcnet_receive(NetClientState *nc, const uint8_t *buf, size_t size_) + int pktcount = 0; + + if (!s->looptest) { ++ if (size > 4092) { ++#ifdef PCNET_DEBUG_RMD ++ fprintf(stderr, "pcnet: truncates rx packet.\n"); ++#endif ++ size = 4092; ++ } + memcpy(src, buf, size); + /* no need to compute the CRC */ + src[size] = 0; +-- +2.1.4 + diff --git a/debian/patches/CVE-2016-1568-ide-ahci-reset-ncq-object.patch b/debian/patches/CVE-2016-1568-ide-ahci-reset-ncq-object.patch new file mode 100644 index 0000000..d157819 --- /dev/null +++ b/debian/patches/CVE-2016-1568-ide-ahci-reset-ncq-object.patch @@ -0,0 +1,62 @@ +From 4ab0359a8ae182a7ac5c99609667273167703fab Mon Sep 17 00:00:00 2001 +From: Prasad J Pandit +Date: Mon, 11 Jan 2016 14:10:42 -0500 +Subject: [PATCH] ide: ahci: reset ncq object to unused on error + +When processing NCQ commands, AHCI device emulation prepares a +NCQ transfer object; To which an aio control block(aiocb) object +is assigned in 'execute_ncq_command'. In case, when the NCQ +command is invalid, the 'aiocb' object is not assigned, and NCQ +transfer object is left as 'used'. This leads to a use after +free kind of error in 'bdrv_aio_cancel_async' via 'ahci_reset_port'. +Reset NCQ transfer object to 'unused' to avoid it. + +[Maintainer edit: s/ACHI/AHCI/ in the commit message. --js] + +Reported-by: Qinghao Tang +Signed-off-by: Prasad J Pandit +Reviewed-by: John Snow +Message-id: 1452282511-4116-1-git-send-email-ppandit@redhat.com +Signed-off-by: John Snow +--- + hw/ide/ahci.c | 1 + + 1 file changed, 1 insertion(+) +# ide_state->error = ABRT_ERR; +# ide_state->status = READY_STAT | ERR_STAT; +# ncq_tfs->drive->port_regs.scr_err |= (1 << ncq_tfs->tag); +#+ ncq_tfs->used = 0; +# } +# +# static void ncq_finish(NCQTransferState *ncq_tfs) +-- +From Debian: + Mjt: + + In 2.1, the code is different. In particular, execute_ncq_command() + is part of process_ncq_command(), and there's no ncq_err() function + yet. We do the "used = 0" assignment in the exact place where the + invalid NCQ command is detected. +# default: +# DPRINTF(port, "error: tried to process non-NCQ command as NCQ\n"); +# qemu_sglist_destroy(&ncq_tfs->sglist); +#+ ncq_tfs->used = 0; +# break; +# } +# } +-- + In 2.2 the DPRINTF is split in two: +diff --git a/hw/ide/ahci.c b/hw/ide/ahci.c +index dd1912e..17f1cbd 100644 +--- a/hw/ide/ahci.c ++++ b/hw/ide/ahci.c +@@ -910,6 +910,7 @@ static void ncq_err(NCQTransferState *ncq_tfs) + "error: tried to process non-NCQ command as NCQ\n"); + } + qemu_sglist_destroy(&ncq_tfs->sglist); ++ ncq_tfs->used = 0; + } + } + +-- +2.1.4 + diff --git a/debian/patches/series b/debian/patches/series index 63b656a..2d3bceb 100644 --- a/debian/patches/series +++ b/debian/patches/series @@ -54,3 +54,8 @@ CVE-2015-8619-hmp-sendkey-oob-fix.patch CVE-2016-1714-fw_cfg-add-check-to-validate-current-entry.patch CVE-2016-1922-i386-avoid-null-pointer-dereference.patch CVE-2016-1981-e1000-eliminate-infinite-loop.patch +CVE-2016-1568-ide-ahci-reset-ncq-object.patch +CVE-2015-3209-pcnet-oob.patch +CVE-2015-7504-pcnet-validate-size.patch +CVE-2015-7512-pcnet-rx-buffer-overflow.patch +CVE-2015-7295-virtio-introduce-virtqueue_unmap_sg.patch -- 2.39.2