diff options
author | Oliver Neukum <oliver@neukum.org> | 2012-04-26 15:59:10 -0400 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2012-05-07 11:56:36 -0400 |
commit | 197d1155b07b582d9969f456f61ee07d632af7e1 (patch) | |
tree | 54e9966a3010df457cfbbd0f44bfdc83d4b84e22 | |
parent | ca288ca1de5957cb50e170dcdb5375c0e6467405 (diff) |
USB: cdc-wdm: fix race leading leading to memory corruption
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>
-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 { |