From 54cb1301c61f0be7b96e343902bb09be081b34fe Mon Sep 17 00:00:00 2001 From: Cole Robinson Date: Mar 17 2016 17:45:47 +0000 Subject: CVE-2016-2857: net: out of bounds read (bz #1309564) CVE-2016-2392: usb: null pointer dereference (bz #1307115) --- diff --git a/0103-usb-check-RNDIS-message-length.patch b/0103-usb-check-RNDIS-message-length.patch new file mode 100644 index 0000000..3cc986a --- /dev/null +++ b/0103-usb-check-RNDIS-message-length.patch @@ -0,0 +1,61 @@ +From: Prasad J Pandit +Date: Wed, 17 Feb 2016 00:23:40 +0530 +Subject: [PATCH] usb: check RNDIS message length + +When processing remote NDIS control message packets, the USB Net +device emulator uses a fixed length(4096) data buffer. The incoming +packet length could exceed this limit. Add a check to avoid it. + +Signed-off-by: Prasad J Pandit +Message-id: 1455648821-17340-2-git-send-email-ppandit@redhat.com +Signed-off-by: Gerd Hoffmann +(cherry picked from commit 64c9bc181fc78275596649f591302d72df2d3071) +--- + hw/usb/core.c | 18 +++++++++--------- + 1 file changed, 9 insertions(+), 9 deletions(-) + +diff --git a/hw/usb/core.c b/hw/usb/core.c +index d0025db..7f46370 100644 +--- a/hw/usb/core.c ++++ b/hw/usb/core.c +@@ -128,9 +128,16 @@ static void do_token_setup(USBDevice *s, USBPacket *p) + } + + usb_packet_copy(p, s->setup_buf, p->iov.size); ++ s->setup_index = 0; + p->actual_length = 0; + s->setup_len = (s->setup_buf[7] << 8) | s->setup_buf[6]; +- s->setup_index = 0; ++ if (s->setup_len > sizeof(s->data_buf)) { ++ fprintf(stderr, ++ "usb_generic_handle_packet: ctrl buffer too small (%d > %zu)\n", ++ s->setup_len, sizeof(s->data_buf)); ++ p->status = USB_RET_STALL; ++ return; ++ } + + request = (s->setup_buf[0] << 8) | s->setup_buf[1]; + value = (s->setup_buf[3] << 8) | s->setup_buf[2]; +@@ -151,13 +158,6 @@ static void do_token_setup(USBDevice *s, USBPacket *p) + } + s->setup_state = SETUP_STATE_DATA; + } else { +- if (s->setup_len > sizeof(s->data_buf)) { +- fprintf(stderr, +- "usb_generic_handle_packet: ctrl buffer too small (%d > %zu)\n", +- s->setup_len, sizeof(s->data_buf)); +- p->status = USB_RET_STALL; +- return; +- } + if (s->setup_len == 0) + s->setup_state = SETUP_STATE_ACK; + else +@@ -176,7 +176,7 @@ static void do_token_in(USBDevice *s, USBPacket *p) + request = (s->setup_buf[0] << 8) | s->setup_buf[1]; + value = (s->setup_buf[3] << 8) | s->setup_buf[2]; + index = (s->setup_buf[5] << 8) | s->setup_buf[4]; +- ++ + switch(s->setup_state) { + case SETUP_STATE_ACK: + if (!(s->setup_buf[0] & USB_DIR_IN)) { diff --git a/0104-usb-check-RNDIS-buffer-offsets-length.patch b/0104-usb-check-RNDIS-buffer-offsets-length.patch new file mode 100644 index 0000000..e989fec --- /dev/null +++ b/0104-usb-check-RNDIS-buffer-offsets-length.patch @@ -0,0 +1,56 @@ +From: Prasad J Pandit +Date: Wed, 17 Feb 2016 00:23:41 +0530 +Subject: [PATCH] usb: check RNDIS buffer offsets & length + +When processing remote NDIS control message packets, +the USB Net device emulator uses a fixed length(4096) data buffer. +The incoming informationBufferOffset & Length combination could +overflow and cross that range. Check control message buffer +offsets and length to avoid it. + +Reported-by: Qinghao Tang +Signed-off-by: Prasad J Pandit +Message-id: 1455648821-17340-3-git-send-email-ppandit@redhat.com +Signed-off-by: Gerd Hoffmann +(cherry picked from commit fe3c546c5ff2a6210f9a4d8561cc64051ca8603e) +--- + hw/usb/dev-network.c | 9 ++++++--- + 1 file changed, 6 insertions(+), 3 deletions(-) + +diff --git a/hw/usb/dev-network.c b/hw/usb/dev-network.c +index 7800cee..ba3c7a7 100644 +--- a/hw/usb/dev-network.c ++++ b/hw/usb/dev-network.c +@@ -914,8 +914,9 @@ static int rndis_query_response(USBNetState *s, + + bufoffs = le32_to_cpu(buf->InformationBufferOffset) + 8; + buflen = le32_to_cpu(buf->InformationBufferLength); +- if (bufoffs + buflen > length) ++ if (buflen > length || bufoffs >= length || bufoffs + buflen > length) { + return USB_RET_STALL; ++ } + + infobuflen = ndis_query(s, le32_to_cpu(buf->OID), + bufoffs + (uint8_t *) buf, buflen, infobuf, +@@ -960,8 +961,9 @@ static int rndis_set_response(USBNetState *s, + + bufoffs = le32_to_cpu(buf->InformationBufferOffset) + 8; + buflen = le32_to_cpu(buf->InformationBufferLength); +- if (bufoffs + buflen > length) ++ if (buflen > length || bufoffs >= length || bufoffs + buflen > length) { + return USB_RET_STALL; ++ } + + ret = ndis_set(s, le32_to_cpu(buf->OID), + bufoffs + (uint8_t *) buf, buflen); +@@ -1211,8 +1213,9 @@ static void usb_net_handle_dataout(USBNetState *s, USBPacket *p) + if (le32_to_cpu(msg->MessageType) == RNDIS_PACKET_MSG) { + uint32_t offs = 8 + le32_to_cpu(msg->DataOffset); + uint32_t size = le32_to_cpu(msg->DataLength); +- if (offs + size <= len) ++ if (offs < len && size < len && offs + size <= len) { + qemu_send_packet(qemu_get_queue(s->nic), s->out_buf + offs, size); ++ } + } + s->out_ptr -= len; + memmove(s->out_buf, &s->out_buf[len], s->out_ptr); diff --git a/0105-net-ne2000-check-ring-buffer-control-registers.patch b/0105-net-ne2000-check-ring-buffer-control-registers.patch new file mode 100644 index 0000000..4e2c64a --- /dev/null +++ b/0105-net-ne2000-check-ring-buffer-control-registers.patch @@ -0,0 +1,34 @@ +From: Prasad J Pandit +Date: Wed, 24 Feb 2016 11:41:33 +0530 +Subject: [PATCH] net: ne2000: check ring buffer control registers + +Ne2000 NIC uses ring buffer of NE2000_MEM_SIZE(49152) +bytes to process network packets. Registers PSTART & PSTOP +define ring buffer size & location. Setting these registers +to invalid values could lead to infinite loop or OOB r/w +access issues. Add check to avoid it. + +Reported-by: Yang Hongke +Tested-by: Yang Hongke +Signed-off-by: Prasad J Pandit +Signed-off-by: Jason Wang +(cherry picked from commit 415ab35a441eca767d033a2702223e785b9d5190) +--- + hw/net/ne2000.c | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/hw/net/ne2000.c b/hw/net/ne2000.c +index a3dffff..995115e 100644 +--- a/hw/net/ne2000.c ++++ b/hw/net/ne2000.c +@@ -154,6 +154,10 @@ static int ne2000_buffer_full(NE2000State *s) + { + int avail, index, boundary; + ++ if (s->stop <= s->start) { ++ return 1; ++ } ++ + index = s->curpag << 8; + boundary = s->boundary << 8; + if (index < boundary) diff --git a/0106-net-check-packet-payload-length.patch b/0106-net-check-packet-payload-length.patch new file mode 100644 index 0000000..a85831d --- /dev/null +++ b/0106-net-check-packet-payload-length.patch @@ -0,0 +1,44 @@ +From: Prasad J Pandit +Date: Wed, 2 Mar 2016 17:29:58 +0530 +Subject: [PATCH] net: check packet payload length + +While computing IP checksum, 'net_checksum_calculate' reads +payload length from the packet. It could exceed the given 'data' +buffer size. Add a check to avoid it. + +Reported-by: Liu Ling +Signed-off-by: Prasad J Pandit +Signed-off-by: Jason Wang +(cherry picked from commit 362786f14a753d8a5256ef97d7c10ed576d6572b) +--- + net/checksum.c | 10 ++++++++-- + 1 file changed, 8 insertions(+), 2 deletions(-) + +diff --git a/net/checksum.c b/net/checksum.c +index 14c0855..0942437 100644 +--- a/net/checksum.c ++++ b/net/checksum.c +@@ -59,6 +59,11 @@ void net_checksum_calculate(uint8_t *data, int length) + int hlen, plen, proto, csum_offset; + uint16_t csum; + ++ /* Ensure data has complete L2 & L3 headers. */ ++ if (length < 14 + 20) { ++ return; ++ } ++ + if ((data[14] & 0xf0) != 0x40) + return; /* not IPv4 */ + hlen = (data[14] & 0x0f) * 4; +@@ -76,8 +81,9 @@ void net_checksum_calculate(uint8_t *data, int length) + return; + } + +- if (plen < csum_offset+2) +- return; ++ if (plen < csum_offset + 2 || 14 + hlen + plen > length) { ++ return; ++ } + + data[14+hlen+csum_offset] = 0; + data[14+hlen+csum_offset+1] = 0; diff --git a/0107-usb-check-USB-configuration-descriptor-object.patch b/0107-usb-check-USB-configuration-descriptor-object.patch new file mode 100644 index 0000000..b5aeb24 --- /dev/null +++ b/0107-usb-check-USB-configuration-descriptor-object.patch @@ -0,0 +1,32 @@ +From: Prasad J Pandit +Date: Thu, 11 Feb 2016 16:31:20 +0530 +Subject: [PATCH] usb: check USB configuration descriptor object + +When processing remote NDIS control message packets, the USB Net +device emulator checks to see if the USB configuration descriptor +object is of RNDIS type(2). But it does not check if it is null, +which leads to a null dereference error. Add check to avoid it. + +Reported-by: Qinghao Tang +Signed-off-by: Prasad J Pandit +Message-id: 1455188480-14688-1-git-send-email-ppandit@redhat.com +Signed-off-by: Gerd Hoffmann +(cherry picked from commit 80eecda8e5d09c442c24307f340840a5b70ea3b9) +--- + hw/usb/dev-network.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/hw/usb/dev-network.c b/hw/usb/dev-network.c +index ba3c7a7..180adce 100644 +--- a/hw/usb/dev-network.c ++++ b/hw/usb/dev-network.c +@@ -653,7 +653,8 @@ typedef struct USBNetState { + + static int is_rndis(USBNetState *s) + { +- return s->dev.config->bConfigurationValue == DEV_RNDIS_CONFIG_VALUE; ++ return s->dev.config ? ++ s->dev.config->bConfigurationValue == DEV_RNDIS_CONFIG_VALUE : 0; + } + + static int ndis_query(USBNetState *s, uint32_t oid, diff --git a/0108-block-set-device_list.tqe_prev-to-NULL-on-BDS-remova.patch b/0108-block-set-device_list.tqe_prev-to-NULL-on-BDS-remova.patch new file mode 100644 index 0000000..d675dc2 --- /dev/null +++ b/0108-block-set-device_list.tqe_prev-to-NULL-on-BDS-remova.patch @@ -0,0 +1,114 @@ +From: Jeff Cody +Date: Mon, 1 Feb 2016 20:33:10 -0500 +Subject: [PATCH] block: set device_list.tqe_prev to NULL on BDS removal + +This fixes a regression introduced with commit 3f09bfbc7. Multiple +bugs arise in conjunction with live snapshots and mirroring operations +(which include active layer commit). + +After a live snapshot occurs, the active layer and the base layer both +have a non-NULL tqe_prev field in the device_list, although the base +node's tqe_prev field points to a NULL entry. This non-NULL tqe_prev +field occurs after the bdrv_append() in the external snapshot calls +change_parent_backing_link(). + +In change_parent_backing_link(), when the previous active layer is +removed from device_list, the device_list.tqe_prev pointer is not +set to NULL. + +The operating scheme in the block layer is to indicate that a BDS belongs +in the bdrv_states device_list iff the device_list.tqe_prev pointer +is non-NULL. + +This patch does two things: + +1.) Introduces a new block layer helper bdrv_device_remove() to remove a + BDS from the device_list, and +2.) uses that new API, which also fixes the regression once used in + change_parent_backing_link(). + +Signed-off-by: Jeff Cody +Message-id: 0cd51e11c0666c04ddb7c05293fe94afeb551e89.1454376655.git.jcody@redhat.com +Reviewed-by: Max Reitz +Signed-off-by: Max Reitz +(cherry picked from commit f8aa905a4fec89863c82de4186352447d851871e) +--- + block.c | 24 ++++++++++++++---------- + blockdev.c | 3 +-- + include/block/block.h | 1 + + 3 files changed, 16 insertions(+), 12 deletions(-) + +diff --git a/block.c b/block.c +index 3a7324b..3c172dd 100644 +--- a/block.c ++++ b/block.c +@@ -1976,21 +1976,25 @@ void bdrv_close_all(void) + } + } + ++/* Note that bs->device_list.tqe_prev is initially null, ++ * and gets set to non-null by QTAILQ_INSERT_TAIL(). Establish ++ * the useful invariant "bs in bdrv_states iff bs->tqe_prev" by ++ * resetting it to null on remove. */ ++void bdrv_device_remove(BlockDriverState *bs) ++{ ++ QTAILQ_REMOVE(&bdrv_states, bs, device_list); ++ bs->device_list.tqe_prev = NULL; ++} ++ + /* make a BlockDriverState anonymous by removing from bdrv_state and + * graph_bdrv_state list. + Also, NULL terminate the device_name to prevent double remove */ + void bdrv_make_anon(BlockDriverState *bs) + { +- /* +- * Take care to remove bs from bdrv_states only when it's actually +- * in it. Note that bs->device_list.tqe_prev is initially null, +- * and gets set to non-null by QTAILQ_INSERT_TAIL(). Establish +- * the useful invariant "bs in bdrv_states iff bs->tqe_prev" by +- * resetting it to null on remove. +- */ ++ /* Take care to remove bs from bdrv_states only when it's actually ++ * in it. */ + if (bs->device_list.tqe_prev) { +- QTAILQ_REMOVE(&bdrv_states, bs, device_list); +- bs->device_list.tqe_prev = NULL; ++ bdrv_device_remove(bs); + } + if (bs->node_name[0] != '\0') { + QTAILQ_REMOVE(&graph_bdrv_states, bs, node_list); +@@ -2031,7 +2035,7 @@ static void change_parent_backing_link(BlockDriverState *from, + if (!to->device_list.tqe_prev) { + QTAILQ_INSERT_BEFORE(from, to, device_list); + } +- QTAILQ_REMOVE(&bdrv_states, from, device_list); ++ bdrv_device_remove(from); + } + } + +diff --git a/blockdev.c b/blockdev.c +index 80932e8..c236126 100644 +--- a/blockdev.c ++++ b/blockdev.c +@@ -2384,8 +2384,7 @@ void qmp_x_blockdev_remove_medium(const char *device, Error **errp) + + /* This follows the convention established by bdrv_make_anon() */ + if (bs->device_list.tqe_prev) { +- QTAILQ_REMOVE(&bdrv_states, bs, device_list); +- bs->device_list.tqe_prev = NULL; ++ bdrv_device_remove(bs); + } + + blk_remove_bs(blk); +diff --git a/include/block/block.h b/include/block/block.h +index 3477328..d83d420 100644 +--- a/include/block/block.h ++++ b/include/block/block.h +@@ -196,6 +196,7 @@ int bdrv_create(BlockDriver *drv, const char* filename, + int bdrv_create_file(const char *filename, QemuOpts *opts, Error **errp); + BlockDriverState *bdrv_new_root(void); + BlockDriverState *bdrv_new(void); ++void bdrv_device_remove(BlockDriverState *bs); + void bdrv_make_anon(BlockDriverState *bs); + void bdrv_swap(BlockDriverState *bs_new, BlockDriverState *bs_old); + void bdrv_append(BlockDriverState *bs_new, BlockDriverState *bs_top); diff --git a/qemu.spec b/qemu.spec index 2fe9067..37a6347 100644 --- a/qemu.spec +++ b/qemu.spec @@ -42,7 +42,7 @@ Summary: QEMU is a FAST! processor emulator Name: qemu Version: 2.5.0 -Release: 9%{?dist} +Release: 11%{?dist} Epoch: 2 License: GPLv2+ and LGPLv2+ and BSD Group: Development/Tools @@ -110,6 +110,17 @@ Patch0019: 0019-target-ppc-kvm-fix-floating-point-registers-sync-on-.patch # Fix qemu-img vmdk images to work with VMware (bz #1299185) Patch0101: 0101-vmdk-Create-streamOptimized-as-version-3.patch Patch0102: 0102-vmdk-Fix-converting-to-streamOptimized.patch +# CVE-2016-2538: Integer overflow in usb module (bz #1305815) +Patch0103: 0103-usb-check-RNDIS-message-length.patch +Patch0104: 0104-usb-check-RNDIS-buffer-offsets-length.patch +# CVE-2016-2841: ne2000: infinite loop (bz #1304047) +Patch0105: 0105-net-ne2000-check-ring-buffer-control-registers.patch +# CVE-2016-2857: net: out of bounds read (bz #1309564) +Patch0106: 0106-net-check-packet-payload-length.patch +# CVE-2016-2392: usb: null pointer dereference (bz #1307115) +Patch0107: 0107-usb-check-USB-configuration-descriptor-object.patch +# Fix external snapshot any more after active committing (bz #1300209) +Patch0108: 0108-block-set-device_list.tqe_prev-to-NULL-on-BDS-remova.patch BuildRequires: SDL2-devel BuildRequires: zlib-devel @@ -1203,6 +1214,17 @@ getent passwd qemu >/dev/null || \ %changelog +* Thu Mar 17 2016 Cole Robinson - 2:2.5.0-11 +- CVE-2016-2857: net: out of bounds read (bz #1309564) +- CVE-2016-2392: usb: null pointer dereference (bz #1307115) + +* Thu Mar 17 2016 Cole Robinson - 2:2.5.0-10 +- CVE-2016-2538: Integer overflow in usb module (bz #1305815) +- CVE-2016-2841: ne2000: infinite loop (bz #1304047) +- CVE-2016-2857 net: out of bounds read (bz #1309564) +- CVE-2016-2392 usb: null pointer dereference (bz #1307115) +- Fix external snapshot any more after active committing (bz #1300209) + * Wed Mar 9 2016 Peter Robinson 2:2.5.0-9 - Rebuild for tcmalloc ifunc issues on non x86 arches (see rhbz 1312462)