aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGuus Sliepen <guus@sliepen.org>2009-07-22 11:39:42 -0400
committerGreg Kroah-Hartman <gregkh@suse.de>2009-09-23 09:46:30 -0400
commit665d7662d15441b4b3e54131a9418a1a198d0d31 (patch)
tree029c210e11d5f9befee6a51457a9dcd79b7934b6
parenta9d43091c5be1e7a60d5abe84be4f3050236b26a (diff)
USB: usbtmc: sanity checks for DEV_DEP_MSG_IN urbs
According to the specifications, an instrument should not return more data in a DEV_DEP_MSG_IN urb than requested. However, some instruments can send more than requested. This could cause the kernel to write the extra data past the end of the buffer provided by read(). Fix this by checking that the value of the TranserSize field is not larger than the urb itself and not larger than the size of the userspace buffer. Also correctly decrement the remaining size of the buffer when userspace read()s more than USBTMC_SIZE_IOBUFFER. Signed-off-by: Guus Sliepen <guus@sliepen.org> Cc: stable <stable@kernel.org> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
-rw-r--r--drivers/usb/class/usbtmc.c22
1 files changed, 18 insertions, 4 deletions
diff --git a/drivers/usb/class/usbtmc.c b/drivers/usb/class/usbtmc.c
index 4f0858fbf980..5bab8e596c88 100644
--- a/drivers/usb/class/usbtmc.c
+++ b/drivers/usb/class/usbtmc.c
@@ -369,13 +369,13 @@ static ssize_t usbtmc_read(struct file *filp, char __user *buf,
369{ 369{
370 struct usbtmc_device_data *data; 370 struct usbtmc_device_data *data;
371 struct device *dev; 371 struct device *dev;
372 unsigned long int n_characters; 372 u32 n_characters;
373 u8 *buffer; 373 u8 *buffer;
374 int actual; 374 int actual;
375 int done; 375 size_t done;
376 int remaining; 376 size_t remaining;
377 int retval; 377 int retval;
378 int this_part; 378 size_t this_part;
379 379
380 /* Get pointer to private data structure */ 380 /* Get pointer to private data structure */
381 data = filp->private_data; 381 data = filp->private_data;
@@ -461,6 +461,18 @@ static ssize_t usbtmc_read(struct file *filp, char __user *buf,
461 (buffer[6] << 16) + 461 (buffer[6] << 16) +
462 (buffer[7] << 24); 462 (buffer[7] << 24);
463 463
464 /* Ensure the instrument doesn't lie about it */
465 if(n_characters > actual - 12) {
466 dev_err(dev, "Device lies about message size: %zu > %zu\n", n_characters, actual - 12);
467 n_characters = actual - 12;
468 }
469
470 /* Ensure the instrument doesn't send more back than requested */
471 if(n_characters > this_part) {
472 dev_err(dev, "Device returns more than requested: %zu > %zu\n", done + n_characters, done + this_part);
473 n_characters = this_part;
474 }
475
464 /* Copy buffer to user space */ 476 /* Copy buffer to user space */
465 if (copy_to_user(buf + done, &buffer[12], n_characters)) { 477 if (copy_to_user(buf + done, &buffer[12], n_characters)) {
466 /* There must have been an addressing problem */ 478 /* There must have been an addressing problem */
@@ -471,6 +483,8 @@ static ssize_t usbtmc_read(struct file *filp, char __user *buf,
471 done += n_characters; 483 done += n_characters;
472 if (n_characters < USBTMC_SIZE_IOBUFFER) 484 if (n_characters < USBTMC_SIZE_IOBUFFER)
473 remaining = 0; 485 remaining = 0;
486 else
487 remaining -= n_characters;
474 } 488 }
475 489
476 /* Update file position value */ 490 /* Update file position value */