diff options
author | Alan Stern <stern@rowland.harvard.edu> | 2010-03-06 15:04:03 -0500 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@suse.de> | 2010-04-01 19:01:36 -0400 |
commit | 55fe2557940e0cd1d88aa89ef580089698a7dac1 (patch) | |
tree | 38d2421b71fa68ccaed236cb6e63f37268455474 | |
parent | 27f5d838191d05b6d8d6e96b3e1e9e1a75d54cad (diff) |
USB: fix usbfs regression
commit 7152b592593b9d48b33f8997b1dfd6df9143f7ec upstream.
This patch (as1352) fixes a bug in the way isochronous input data is
returned to userspace for usbfs transfers. The entire buffer must be
copied, not just the first actual_length bytes, because the individual
packets will be discontiguous if any of them are short.
Reported-by: Markus Rechberger <mrechberger@gmail.com>
Signed-off-by: Alan Stern <stern@rowland.harvard.edu>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
-rw-r--r-- | drivers/usb/core/devio.c | 17 |
1 files changed, 14 insertions, 3 deletions
diff --git a/drivers/usb/core/devio.c b/drivers/usb/core/devio.c index a678186f218f..4fd67d69b830 100644 --- a/drivers/usb/core/devio.c +++ b/drivers/usb/core/devio.c | |||
@@ -1176,6 +1176,13 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb, | |||
1176 | free_async(as); | 1176 | free_async(as); |
1177 | return -ENOMEM; | 1177 | return -ENOMEM; |
1178 | } | 1178 | } |
1179 | /* Isochronous input data may end up being discontiguous | ||
1180 | * if some of the packets are short. Clear the buffer so | ||
1181 | * that the gaps don't leak kernel data to userspace. | ||
1182 | */ | ||
1183 | if (is_in && uurb->type == USBDEVFS_URB_TYPE_ISO) | ||
1184 | memset(as->urb->transfer_buffer, 0, | ||
1185 | uurb->buffer_length); | ||
1179 | } | 1186 | } |
1180 | as->urb->dev = ps->dev; | 1187 | as->urb->dev = ps->dev; |
1181 | as->urb->pipe = (uurb->type << 30) | | 1188 | as->urb->pipe = (uurb->type << 30) | |
@@ -1312,10 +1319,14 @@ static int processcompl(struct async *as, void __user * __user *arg) | |||
1312 | void __user *addr = as->userurb; | 1319 | void __user *addr = as->userurb; |
1313 | unsigned int i; | 1320 | unsigned int i; |
1314 | 1321 | ||
1315 | if (as->userbuffer && urb->actual_length) | 1322 | if (as->userbuffer && urb->actual_length) { |
1316 | if (copy_to_user(as->userbuffer, urb->transfer_buffer, | 1323 | if (urb->number_of_packets > 0) /* Isochronous */ |
1317 | urb->actual_length)) | 1324 | i = urb->transfer_buffer_length; |
1325 | else /* Non-Isoc */ | ||
1326 | i = urb->actual_length; | ||
1327 | if (copy_to_user(as->userbuffer, urb->transfer_buffer, i)) | ||
1318 | goto err_out; | 1328 | goto err_out; |
1329 | } | ||
1319 | if (put_user(as->status, &userurb->status)) | 1330 | if (put_user(as->status, &userurb->status)) |
1320 | goto err_out; | 1331 | goto err_out; |
1321 | if (put_user(urb->actual_length, &userurb->actual_length)) | 1332 | if (put_user(urb->actual_length, &userurb->actual_length)) |