|
[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 |