USB: composite: Hold spinlock before calling usb_func_wakeup_int() API

There is a chance that composite_resume might race with android_disable
if composition switch happens and at the same time, reset interrupt is
triggered. In this case, it could lead to accessing invalid address as
composite_resume() not calling usb_func_wakeup_int() without holding
spinlock. Hence modfiy usb_func_wakeup_int() such that caller of this
function should call it with spinlock holding to fix the issue.

CRs-Fixed: 799332
Change-Id: I97ef374923504977ac8fc32954dd7de834a01041
Signed-off-by: Vijayavardhan Vennapusa <vvreddy@codeaurora.org>
Signed-off-by: Azhar Shaikh <azhars@codeaurora.org>
This commit is contained in:
Vijayavardhan Vennapusa 2015-02-25 10:56:20 +05:30 committed by David Keitel
parent 7010bdba62
commit 15d49a1051

View file

@ -367,9 +367,7 @@ EXPORT_SYMBOL_GPL(usb_interface_id);
static int usb_func_wakeup_int(struct usb_function *func) static int usb_func_wakeup_int(struct usb_function *func)
{ {
int ret; int ret;
unsigned long flags;
struct usb_gadget *gadget; struct usb_gadget *gadget;
struct usb_composite_dev *cdev;
pr_debug("%s - %s function wakeup\n", pr_debug("%s - %s function wakeup\n",
__func__, func->name ? func->name : ""); __func__, func->name ? func->name : "");
@ -388,11 +386,7 @@ static int usb_func_wakeup_int(struct usb_function *func)
return -ENOTSUPP; return -ENOTSUPP;
} }
cdev = get_gadget_data(gadget);
spin_lock_irqsave(&cdev->lock, flags);
ret = usb_gadget_func_wakeup(gadget, func->intf_id); ret = usb_gadget_func_wakeup(gadget, func->intf_id);
spin_unlock_irqrestore(&cdev->lock, flags);
return ret; return ret;
} }
@ -400,10 +394,12 @@ static int usb_func_wakeup_int(struct usb_function *func)
int usb_func_wakeup(struct usb_function *func) int usb_func_wakeup(struct usb_function *func)
{ {
int ret; int ret;
unsigned long flags;
pr_debug("%s function wakeup\n", pr_debug("%s function wakeup\n",
func->name ? func->name : ""); func->name ? func->name : "");
spin_lock_irqsave(&func->config->cdev->lock, flags);
ret = usb_func_wakeup_int(func); ret = usb_func_wakeup_int(func);
if (ret == -EAGAIN) { if (ret == -EAGAIN) {
DBG(func->config->cdev, DBG(func->config->cdev,
@ -416,6 +412,7 @@ int usb_func_wakeup(struct usb_function *func)
func->name ? func->name : "", ret); func->name ? func->name : "", ret);
} }
spin_unlock_irqrestore(&func->config->cdev->lock, flags);
return ret; return ret;
} }
EXPORT_SYMBOL_GPL(usb_func_wakeup); EXPORT_SYMBOL_GPL(usb_func_wakeup);
@ -2251,6 +2248,7 @@ void composite_resume(struct usb_gadget *gadget)
struct usb_function *f; struct usb_function *f;
u16 maxpower; u16 maxpower;
int ret; int ret;
unsigned long flags;
/* REVISIT: should we have config level /* REVISIT: should we have config level
* suspend/resume callbacks? * suspend/resume callbacks?
@ -2259,6 +2257,7 @@ void composite_resume(struct usb_gadget *gadget)
if (cdev->driver->resume) if (cdev->driver->resume)
cdev->driver->resume(cdev); cdev->driver->resume(cdev);
spin_lock_irqsave(&cdev->lock, flags);
if (cdev->config) { if (cdev->config) {
list_for_each_entry(f, &cdev->config->functions, list) { list_for_each_entry(f, &cdev->config->functions, list) {
ret = usb_func_wakeup_int(f); ret = usb_func_wakeup_int(f);
@ -2286,6 +2285,7 @@ void composite_resume(struct usb_gadget *gadget)
maxpower : CONFIG_USB_GADGET_VBUS_DRAW); maxpower : CONFIG_USB_GADGET_VBUS_DRAW);
} }
spin_unlock_irqrestore(&cdev->lock, flags);
cdev->suspended = 0; cdev->suspended = 0;
} }