From: Wolfgang Bumiller Date: Wed, 24 Feb 2016 12:56:30 +0000 (+0100) Subject: Fix CVE-2016-2538 X-Git-Url: https://git.proxmox.com/?p=pve-qemu-kvm.git;a=commitdiff_plain;h=6207d5007882c4587fcd50e1fd2b2304750408d2 Fix CVE-2016-2538 usb: check RNDIS message length usb: check RNDIS buffer offsets & length --- diff --git a/debian/patches/extra/CVE-2016-2538-usb-check-RNDIS-message-length.patch b/debian/patches/extra/CVE-2016-2538-usb-check-RNDIS-message-length.patch new file mode 100644 index 0000000..57491ef --- /dev/null +++ b/debian/patches/extra/CVE-2016-2538-usb-check-RNDIS-message-length.patch @@ -0,0 +1,111 @@ +From 56ed8c01f949f8a0ee45bfe91aed3a973c79a5db Mon Sep 17 00:00:00 2001 +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 + +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 +--- + hw/usb/core.c | 18 +++++++++--------- + hw/usb/dev-network.c | 9 ++++++--- + 2 files changed, 15 insertions(+), 12 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/hw/usb/dev-network.c b/hw/usb/dev-network.c +index 8a4ff49..180adce 100644 +--- a/hw/usb/dev-network.c ++++ b/hw/usb/dev-network.c +@@ -915,8 +915,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, +@@ -961,8 +962,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); +@@ -1212,8 +1214,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); +-- +2.1.4 + diff --git a/debian/patches/series b/debian/patches/series index 379f0d1..744a756 100644 --- a/debian/patches/series +++ b/debian/patches/series @@ -55,3 +55,4 @@ extra/CVE-2016-2198-ehci-null-pointer.patch extra/CVE-2016-2391-usb-ohci-avoid-multiple-eof-timers.patch extra/CVE-2016-2392-check-USB-configuration-descriptor-object.patch extra/fw_cfg-unbreak-migration-compatibility-for-2.4.patch +extra/CVE-2016-2538-usb-check-RNDIS-message-length.patch