[pve-devel] [PATCH kvm] Fix CVE-2016-2538

Wolfgang Bumiller w.bumiller at proxmox.com
Wed Feb 24 13:56:30 CET 2016


usb: check RNDIS message length
usb: check RNDIS buffer offsets & length
---
 ...-2016-2538-usb-check-RNDIS-message-length.patch | 111 +++++++++++++++++++++
 debian/patches/series                              |   1 +
 2 files changed, 112 insertions(+)
 create mode 100644 debian/patches/extra/CVE-2016-2538-usb-check-RNDIS-message-length.patch

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 <pjp at fedoraproject.org>
+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 <pjp at fedoraproject.org>
+
+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 <luodalongde at gmail.com>
+Signed-off-by: Prasad J Pandit <pjp at fedoraproject.org>
+---
+ 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
-- 
2.1.4





More information about the pve-devel mailing list