Skip to content

Commit

Permalink
USB: cdc-wdm: fix buffer overflow
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Oliver Neukum authored and Greg Kroah-Hartman committed Mar 12, 2013
1 parent a57e82a commit c0f5ece
Showing 1 changed file with 20 additions and 3 deletions.
23 changes: 20 additions & 3 deletions drivers/usb/class/cdc-wdm.c
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ MODULE_DEVICE_TABLE (usb, wdm_ids);
#define WDM_RESPONDING 7
#define WDM_SUSPENDING 8
#define WDM_RESETTING 9
#define WDM_OVERFLOW 10

#define WDM_MAX 16

Expand Down Expand Up @@ -155,6 +156,7 @@ static void wdm_in_callback(struct urb *urb)
{
struct wdm_device *desc = urb->context;
int status = urb->status;
int length = urb->actual_length;

spin_lock(&desc->iuspin);
clear_bit(WDM_RESPONDING, &desc->flags);
Expand Down Expand Up @@ -185,9 +187,17 @@ static void wdm_in_callback(struct urb *urb)
}

desc->rerr = status;
desc->reslength = urb->actual_length;
memmove(desc->ubuf + desc->length, desc->inbuf, desc->reslength);
desc->length += desc->reslength;
if (length + desc->length > desc->wMaxCommand) {
/* The buffer would overflow */
set_bit(WDM_OVERFLOW, &desc->flags);
} else {
/* we may already be in overflow */
if (!test_bit(WDM_OVERFLOW, &desc->flags)) {
memmove(desc->ubuf + desc->length, desc->inbuf, length);
desc->length += length;
desc->reslength = length;
}
}
skip_error:
wake_up(&desc->wait);

Expand Down Expand Up @@ -435,6 +445,11 @@ static ssize_t wdm_read
rv = -ENODEV;
goto err;
}
if (test_bit(WDM_OVERFLOW, &desc->flags)) {
clear_bit(WDM_OVERFLOW, &desc->flags);
rv = -ENOBUFS;
goto err;
}
i++;
if (file->f_flags & O_NONBLOCK) {
if (!test_bit(WDM_READ, &desc->flags)) {
Expand Down Expand Up @@ -478,6 +493,7 @@ static ssize_t wdm_read
spin_unlock_irq(&desc->iuspin);
goto retry;
}

if (!desc->reslength) { /* zero length read */
dev_dbg(&desc->intf->dev, "%s: zero length - clearing WDM_READ\n", __func__);
clear_bit(WDM_READ, &desc->flags);
Expand Down Expand Up @@ -1004,6 +1020,7 @@ static int wdm_post_reset(struct usb_interface *intf)
struct wdm_device *desc = wdm_find_device(intf);
int rv;

clear_bit(WDM_OVERFLOW, &desc->flags);
clear_bit(WDM_RESETTING, &desc->flags);
rv = recover_from_urb_loss(desc);
mutex_unlock(&desc->wlock);
Expand Down

0 comments on commit c0f5ece

Please sign in to comment.