diff options
author | Pete Zaitcev <zaitcev@redhat.com> | 2007-08-14 16:19:16 -0400 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@suse.de> | 2007-10-12 17:55:15 -0400 |
commit | 42cb967fd01b1f50374fdfa811f86db103eea532 (patch) | |
tree | 01edefaaa9ab8ca7ede7f912ed83dab4d14a92c4 /drivers/usb/class/usblp.c | |
parent | c36d54ab380fb8edeaa22776af869c64bfda43bd (diff) |
usblp: Fix a double kfree
If submit fails, slab hits a BUG() because of a double kfree.
The today's lesson is, you cannot just slap USB_FREE_BUFFER on code
without adjusting the error paths.
The patch is made bigger by opportunistic refactoring.
Signed-Off-By: Pete Zaitcev <zaitcev@redhat.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers/usb/class/usblp.c')
-rw-r--r-- | drivers/usb/class/usblp.c | 35 |
1 files changed, 23 insertions, 12 deletions
diff --git a/drivers/usb/class/usblp.c b/drivers/usb/class/usblp.c index 3a0f8186d4bf..ad632f2d6f94 100644 --- a/drivers/usb/class/usblp.c +++ b/drivers/usb/class/usblp.c | |||
@@ -686,10 +686,30 @@ done: | |||
686 | return retval; | 686 | return retval; |
687 | } | 687 | } |
688 | 688 | ||
689 | static struct urb *usblp_new_writeurb(struct usblp *usblp, int transfer_length) | ||
690 | { | ||
691 | struct urb *urb; | ||
692 | char *writebuf; | ||
693 | |||
694 | if ((writebuf = kmalloc(transfer_length, GFP_KERNEL)) == NULL) | ||
695 | return NULL; | ||
696 | if ((urb = usb_alloc_urb(0, GFP_KERNEL)) == NULL) { | ||
697 | kfree(writebuf); | ||
698 | return NULL; | ||
699 | } | ||
700 | |||
701 | usb_fill_bulk_urb(urb, usblp->dev, | ||
702 | usb_sndbulkpipe(usblp->dev, | ||
703 | usblp->protocol[usblp->current_protocol].epwrite->bEndpointAddress), | ||
704 | writebuf, transfer_length, usblp_bulk_write, usblp); | ||
705 | urb->transfer_flags |= URB_FREE_BUFFER; | ||
706 | |||
707 | return urb; | ||
708 | } | ||
709 | |||
689 | static ssize_t usblp_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos) | 710 | static ssize_t usblp_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos) |
690 | { | 711 | { |
691 | struct usblp *usblp = file->private_data; | 712 | struct usblp *usblp = file->private_data; |
692 | char *writebuf; | ||
693 | struct urb *writeurb; | 713 | struct urb *writeurb; |
694 | int rv; | 714 | int rv; |
695 | int transfer_length; | 715 | int transfer_length; |
@@ -710,18 +730,11 @@ static ssize_t usblp_write(struct file *file, const char __user *buffer, size_t | |||
710 | transfer_length = USBLP_BUF_SIZE; | 730 | transfer_length = USBLP_BUF_SIZE; |
711 | 731 | ||
712 | rv = -ENOMEM; | 732 | rv = -ENOMEM; |
713 | if ((writebuf = kmalloc(USBLP_BUF_SIZE, GFP_KERNEL)) == NULL) | 733 | if ((writeurb = usblp_new_writeurb(usblp, transfer_length)) == NULL) |
714 | goto raise_buf; | ||
715 | if ((writeurb = usb_alloc_urb(0, GFP_KERNEL)) == NULL) | ||
716 | goto raise_urb; | 734 | goto raise_urb; |
717 | usb_fill_bulk_urb(writeurb, usblp->dev, | ||
718 | usb_sndbulkpipe(usblp->dev, | ||
719 | usblp->protocol[usblp->current_protocol].epwrite->bEndpointAddress), | ||
720 | writebuf, transfer_length, usblp_bulk_write, usblp); | ||
721 | writeurb->transfer_flags |= URB_FREE_BUFFER; | ||
722 | usb_anchor_urb(writeurb, &usblp->urbs); | 735 | usb_anchor_urb(writeurb, &usblp->urbs); |
723 | 736 | ||
724 | if (copy_from_user(writebuf, | 737 | if (copy_from_user(writeurb->transfer_buffer, |
725 | buffer + writecount, transfer_length)) { | 738 | buffer + writecount, transfer_length)) { |
726 | rv = -EFAULT; | 739 | rv = -EFAULT; |
727 | goto raise_badaddr; | 740 | goto raise_badaddr; |
@@ -780,8 +793,6 @@ raise_badaddr: | |||
780 | usb_unanchor_urb(writeurb); | 793 | usb_unanchor_urb(writeurb); |
781 | usb_free_urb(writeurb); | 794 | usb_free_urb(writeurb); |
782 | raise_urb: | 795 | raise_urb: |
783 | kfree(writebuf); | ||
784 | raise_buf: | ||
785 | raise_wait: | 796 | raise_wait: |
786 | collect_error: /* Out of raise sequence */ | 797 | collect_error: /* Out of raise sequence */ |
787 | mutex_unlock(&usblp->wmut); | 798 | mutex_unlock(&usblp->wmut); |