Commit c4c0e236 authored by Jim Paris's avatar Jim Paris Committed by Anthony Liguori
Browse files

usb-linux.c: fix buffer overflow

In usb-linux.c:usb_host_handle_control, we pass a 1024-byte buffer and
length to the kernel.  However, the length was provided by the caller
of dev->handle_packet, and is not checked, so the kernel might provide
too much data and overflow our buffer.

For example, hw/usb-uhci.c could set the length to 2047.
hw/usb-ohci.c looks like it might go up to 4096 or 8192.

This causes a qemu crash, as reported here:
  http://www.mail-archive.com/kvm@vger.kernel.org/msg18447.html



This patch increases the usb-linux.c buffer size to 2048 to fix the
specific device reported, and adds a check to avoid the overflow in
any case.

Signed-off-by: default avatarJim Paris <jim@jtan.com>
Signed-off-by: default avatarAnthony Liguori <aliguori@us.ibm.com>
parent aeec26d3
Loading
Loading
Loading
Loading
+10 −2
Original line number Diff line number Diff line
@@ -115,7 +115,7 @@ struct ctrl_struct {
    uint16_t offset;
    uint8_t  state;
    struct   usb_ctrlrequest req;
    uint8_t  buffer[1024];
    uint8_t  buffer[2048];
};

typedef struct USBHostDevice {
@@ -552,6 +552,7 @@ static int usb_host_handle_control(USBHostDevice *s, USBPacket *p)
    struct usbdevfs_urb *urb;
    AsyncURB *aurb;
    int ret, value, index;
    int buffer_len;

    /* 
     * Process certain standard device requests.
@@ -580,6 +581,13 @@ static int usb_host_handle_control(USBHostDevice *s, USBPacket *p)

    /* The rest are asynchronous */

    buffer_len = 8 + s->ctrl.len;
    if (buffer_len > sizeof(s->ctrl.buffer)) {
	    fprintf(stderr, "husb: ctrl buffer too small (%u > %lu)\n",
		    buffer_len, sizeof(s->ctrl.buffer));
	    return USB_RET_STALL;
    }

    aurb = async_alloc();
    aurb->hdev   = s;
    aurb->packet = p;
@@ -596,7 +604,7 @@ static int usb_host_handle_control(USBHostDevice *s, USBPacket *p)
    urb->endpoint = p->devep;

    urb->buffer        = &s->ctrl.req;
    urb->buffer_length = 8 + s->ctrl.len;
    urb->buffer_length = buffer_len;

    urb->usercontext = s;