diff options
author | Oliver Neukum <oneukum@suse.de> | 2013-03-12 09:52:42 -0400 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2013-03-12 19:33:05 -0400 |
commit | c0f5ecee4e741667b2493c742b60b6218d40b3aa (patch) | |
tree | 64f1a695a53a28eaaebe90a0816746d28ab63511 /drivers/usb/class | |
parent | a57e82a18779ab8a5e5a1f5841cef937cf578913 (diff) |
USB: cdc-wdm: fix buffer overflow
The buffer for responses must not overflow.
If this would happen, set a flag, drop the data and return
an error after user space has read all remaining data.
Signed-off-by: Oliver Neukum <oliver@neukum.org>
CC: stable@kernel.org
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers/usb/class')
-rw-r--r-- | drivers/usb/class/cdc-wdm.c | 23 |
1 files changed, 20 insertions, 3 deletions
diff --git a/drivers/usb/class/cdc-wdm.c b/drivers/usb/class/cdc-wdm.c index 5f0cb417b736..122d056d96d5 100644 --- a/drivers/usb/class/cdc-wdm.c +++ b/drivers/usb/class/cdc-wdm.c | |||
@@ -56,6 +56,7 @@ MODULE_DEVICE_TABLE (usb, wdm_ids); | |||
56 | #define WDM_RESPONDING 7 | 56 | #define WDM_RESPONDING 7 |
57 | #define WDM_SUSPENDING 8 | 57 | #define WDM_SUSPENDING 8 |
58 | #define WDM_RESETTING 9 | 58 | #define WDM_RESETTING 9 |
59 | #define WDM_OVERFLOW 10 | ||
59 | 60 | ||
60 | #define WDM_MAX 16 | 61 | #define WDM_MAX 16 |
61 | 62 | ||
@@ -155,6 +156,7 @@ static void wdm_in_callback(struct urb *urb) | |||
155 | { | 156 | { |
156 | struct wdm_device *desc = urb->context; | 157 | struct wdm_device *desc = urb->context; |
157 | int status = urb->status; | 158 | int status = urb->status; |
159 | int length = urb->actual_length; | ||
158 | 160 | ||
159 | spin_lock(&desc->iuspin); | 161 | spin_lock(&desc->iuspin); |
160 | clear_bit(WDM_RESPONDING, &desc->flags); | 162 | clear_bit(WDM_RESPONDING, &desc->flags); |
@@ -185,9 +187,17 @@ static void wdm_in_callback(struct urb *urb) | |||
185 | } | 187 | } |
186 | 188 | ||
187 | desc->rerr = status; | 189 | desc->rerr = status; |
188 | desc->reslength = urb->actual_length; | 190 | if (length + desc->length > desc->wMaxCommand) { |
189 | memmove(desc->ubuf + desc->length, desc->inbuf, desc->reslength); | 191 | /* The buffer would overflow */ |
190 | desc->length += desc->reslength; | 192 | set_bit(WDM_OVERFLOW, &desc->flags); |
193 | } else { | ||
194 | /* we may already be in overflow */ | ||
195 | if (!test_bit(WDM_OVERFLOW, &desc->flags)) { | ||
196 | memmove(desc->ubuf + desc->length, desc->inbuf, length); | ||
197 | desc->length += length; | ||
198 | desc->reslength = length; | ||
199 | } | ||
200 | } | ||
191 | skip_error: | 201 | skip_error: |
192 | wake_up(&desc->wait); | 202 | wake_up(&desc->wait); |
193 | 203 | ||
@@ -435,6 +445,11 @@ retry: | |||
435 | rv = -ENODEV; | 445 | rv = -ENODEV; |
436 | goto err; | 446 | goto err; |
437 | } | 447 | } |
448 | if (test_bit(WDM_OVERFLOW, &desc->flags)) { | ||
449 | clear_bit(WDM_OVERFLOW, &desc->flags); | ||
450 | rv = -ENOBUFS; | ||
451 | goto err; | ||
452 | } | ||
438 | i++; | 453 | i++; |
439 | if (file->f_flags & O_NONBLOCK) { | 454 | if (file->f_flags & O_NONBLOCK) { |
440 | if (!test_bit(WDM_READ, &desc->flags)) { | 455 | if (!test_bit(WDM_READ, &desc->flags)) { |
@@ -478,6 +493,7 @@ retry: | |||
478 | spin_unlock_irq(&desc->iuspin); | 493 | spin_unlock_irq(&desc->iuspin); |
479 | goto retry; | 494 | goto retry; |
480 | } | 495 | } |
496 | |||
481 | if (!desc->reslength) { /* zero length read */ | 497 | if (!desc->reslength) { /* zero length read */ |
482 | dev_dbg(&desc->intf->dev, "%s: zero length - clearing WDM_READ\n", __func__); | 498 | dev_dbg(&desc->intf->dev, "%s: zero length - clearing WDM_READ\n", __func__); |
483 | clear_bit(WDM_READ, &desc->flags); | 499 | clear_bit(WDM_READ, &desc->flags); |
@@ -1004,6 +1020,7 @@ static int wdm_post_reset(struct usb_interface *intf) | |||
1004 | struct wdm_device *desc = wdm_find_device(intf); | 1020 | struct wdm_device *desc = wdm_find_device(intf); |
1005 | int rv; | 1021 | int rv; |
1006 | 1022 | ||
1023 | clear_bit(WDM_OVERFLOW, &desc->flags); | ||
1007 | clear_bit(WDM_RESETTING, &desc->flags); | 1024 | clear_bit(WDM_RESETTING, &desc->flags); |
1008 | rv = recover_from_urb_loss(desc); | 1025 | rv = recover_from_urb_loss(desc); |
1009 | mutex_unlock(&desc->wlock); | 1026 | mutex_unlock(&desc->wlock); |