diff options
| author | Oliver Neukum <oliver@neukum.org> | 2012-04-26 15:59:10 -0400 |
|---|---|---|
| committer | Luis Henriques <luis.henriques@canonical.com> | 2012-05-25 12:24:37 -0400 |
| commit | 10a4df90093cb4f1cf0ff104f40a6ccb2a1bacc2 (patch) | |
| tree | 0a95c37d0873b8a9798bdc15c0b4a466287cc010 /drivers/usb/class | |
| parent | 114390429dbac6b72d381ed56694eff5b4169aa7 (diff) | |
USB: cdc-wdm: fix race leading leading to memory corruption
BugLink: http://bugs.launchpad.net/bugs/996109
commit 5c22837adca7c30b66121cf18ad3e160134268d4 upstream.
This patch fixes a race whereby a pointer to a buffer
would be overwritten while the buffer was in use leading
to a double free and a memory leak. This causes crashes.
This bug was introduced in 2.6.34
Signed-off-by: Oliver Neukum <oneukum@suse.de>
Tested-by: Bjørn Mork <bjorn@mork.no>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers/usb/class')
| -rw-r--r-- | drivers/usb/class/cdc-wdm.c | 7 |
1 files changed, 5 insertions, 2 deletions
diff --git a/drivers/usb/class/cdc-wdm.c b/drivers/usb/class/cdc-wdm.c index 76f061375e1..00b7bf9a20c 100644 --- a/drivers/usb/class/cdc-wdm.c +++ b/drivers/usb/class/cdc-wdm.c | |||
| @@ -108,8 +108,9 @@ static void wdm_out_callback(struct urb *urb) | |||
| 108 | spin_lock(&desc->iuspin); | 108 | spin_lock(&desc->iuspin); |
| 109 | desc->werr = urb->status; | 109 | desc->werr = urb->status; |
| 110 | spin_unlock(&desc->iuspin); | 110 | spin_unlock(&desc->iuspin); |
| 111 | clear_bit(WDM_IN_USE, &desc->flags); | ||
| 112 | kfree(desc->outbuf); | 111 | kfree(desc->outbuf); |
| 112 | desc->outbuf = NULL; | ||
| 113 | clear_bit(WDM_IN_USE, &desc->flags); | ||
| 113 | wake_up(&desc->wait); | 114 | wake_up(&desc->wait); |
| 114 | } | 115 | } |
| 115 | 116 | ||
| @@ -312,7 +313,7 @@ static ssize_t wdm_write | |||
| 312 | if (we < 0) | 313 | if (we < 0) |
| 313 | return -EIO; | 314 | return -EIO; |
| 314 | 315 | ||
| 315 | desc->outbuf = buf = kmalloc(count, GFP_KERNEL); | 316 | buf = kmalloc(count, GFP_KERNEL); |
| 316 | if (!buf) { | 317 | if (!buf) { |
| 317 | rv = -ENOMEM; | 318 | rv = -ENOMEM; |
| 318 | goto outnl; | 319 | goto outnl; |
| @@ -376,10 +377,12 @@ static ssize_t wdm_write | |||
| 376 | req->wIndex = desc->inum; | 377 | req->wIndex = desc->inum; |
| 377 | req->wLength = cpu_to_le16(count); | 378 | req->wLength = cpu_to_le16(count); |
| 378 | set_bit(WDM_IN_USE, &desc->flags); | 379 | set_bit(WDM_IN_USE, &desc->flags); |
| 380 | desc->outbuf = buf; | ||
| 379 | 381 | ||
| 380 | rv = usb_submit_urb(desc->command, GFP_KERNEL); | 382 | rv = usb_submit_urb(desc->command, GFP_KERNEL); |
| 381 | if (rv < 0) { | 383 | if (rv < 0) { |
| 382 | kfree(buf); | 384 | kfree(buf); |
| 385 | desc->outbuf = NULL; | ||
| 383 | clear_bit(WDM_IN_USE, &desc->flags); | 386 | clear_bit(WDM_IN_USE, &desc->flags); |
| 384 | dev_err(&desc->intf->dev, "Tx URB error: %d\n", rv); | 387 | dev_err(&desc->intf->dev, "Tx URB error: %d\n", rv); |
| 385 | } else { | 388 | } else { |
