[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [Xen-changelog] [linux-2.6.18-xen] usbback: copy only filled buffers to guest
# HG changeset patch # User Juergen Gross <jgross@xxxxxxxx> # Date 1425994647 -3600 # Node ID 72387b3c2252e38b55ff2c943388c32f0ae338e6 # Parent a8382d70a4a6205bd0fe67f04717ff32b3ed9605 usbback: copy only filled buffers to guest Copy only filled buffers to guest in usbback. After finishing a read I/O don't copy the complete I/O buffer to the guest, but only the parts which were filled by the I/O. Otherwise Dom0 kernel data might leak into the guest. Note that this includes dropping the urb->status == 0 check because it was wrong: There are status != 0 cases where some data has already been written to the buffer (e.g. in case of exact length requested and only part of the buffer filled). The actual_length is always correct and will be 0 if no data has been transferred. This is CVE-2015-0777. Signed-off-by: Juergen Gross <jgross@xxxxxxxx> Committed-by: Jan Beulich <jbeulich@xxxxxxxx> --- diff -r a8382d70a4a6 -r 72387b3c2252 drivers/xen/usbback/usbback.c --- a/drivers/xen/usbback/usbback.c Tue Mar 10 14:06:26 2015 +0100 +++ b/drivers/xen/usbback/usbback.c Tue Mar 10 14:37:27 2015 +0100 @@ -197,16 +197,29 @@ static void fast_flush_area(pending_req_ } static void copy_buff_to_pages(void *buff, pending_req_t *pending_req, - int start, int nr_pages) + unsigned int start, unsigned int nr_pages, + unsigned int offset, unsigned int length) { - unsigned long copied = 0; - int i; + const struct pending_req_segment *seg = pending_req->seg + start; + unsigned int i, off, len, buf_off = 0; - for (i = start; i < start + nr_pages; i++) { - memcpy((void *) vaddr(pending_req, i) + pending_req->seg[i].offset, - buff + copied, - pending_req->seg[i].length); - copied += pending_req->seg[i].length; + for (i = start; i < start + nr_pages; i++, seg++) { + len = seg->length; + off = seg->offset; + if (buf_off + len > offset) { + if (buf_off < offset) { + len -= offset - buf_off; + off += offset - buf_off; + buf_off += offset - buf_off; + } + if (buf_off + len > offset + length) + len -= offset + length - buf_off; + memcpy((void *)vaddr(pending_req, i) + off, + buff + buf_off, len); + } + buf_off += len; + if (buf_off >= offset + length) + break; } } @@ -320,17 +333,39 @@ static void usbbk_do_response(pending_re notify_remote_via_irq(usbif->irq); } +static void usbbk_copy_isoc_to_pages(struct urb *urb) +{ + pending_req_t *pending_req = urb->context; + struct usb_iso_packet_descriptor *isoc = &urb->iso_frame_desc[0]; + unsigned int n_isoc = urb->number_of_packets; + + copy_buff_to_pages(isoc, pending_req, + pending_req->nr_buffer_segs, + pending_req->nr_extra_segs, 0, + n_isoc * sizeof(*isoc)); + + if (!usb_pipein(urb->pipe)) + return; + + while (n_isoc--) { + copy_buff_to_pages(pending_req->buffer, + pending_req, 0, + pending_req->nr_buffer_segs, + isoc->offset, isoc->actual_length); + isoc++; + } +} + static void usbbk_urb_complete(struct urb *urb, struct pt_regs *regs) { pending_req_t *pending_req = (pending_req_t *)urb->context; - if (usb_pipein(urb->pipe) && urb->status == 0 && urb->actual_length > 0) + if (usb_pipeisoc(urb->pipe)) + usbbk_copy_isoc_to_pages(urb); + else if (usb_pipein(urb->pipe) && urb->actual_length > 0) copy_buff_to_pages(pending_req->buffer, pending_req, - 0, pending_req->nr_buffer_segs); - - if (usb_pipeisoc(urb->pipe)) - copy_buff_to_pages(&urb->iso_frame_desc[0], pending_req, - pending_req->nr_buffer_segs, pending_req->nr_extra_segs); + 0, pending_req->nr_buffer_segs, + 0, urb->actual_length); barrier(); _______________________________________________ Xen-changelog mailing list Xen-changelog@xxxxxxxxxxxxx http://lists.xensource.com/xen-changelog
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |