3.16.55-rc1 review patch. If anyone has any objections, please let me know. ------------------ From: Alan Stern <stern@xxxxxxxxxxxxxxxxxxx> commit 7ae2c3c280db183ca9ada2675c34ec2f7378abfa upstream. The error-handling pathways in usb_add_gadget_udc_release() are messed up. Aside from the uninformative statement labels, they can deallocate the udc structure after calling put_device(), which is a double-free. This was observed by KASAN in automatic testing. This patch cleans up the routine. It preserves the requirement that when any failure occurs, we call put_device(&gadget->dev). Signed-off-by: Alan Stern <stern@xxxxxxxxxxxxxxxxxxx> Reported-by: Fengguang Wu <fengguang.wu@xxxxxxxxx> Reviewed-by: Peter Chen <peter.chen@xxxxxxx> Acked-by: Felipe Balbi <felipe.balbi@xxxxxxxxxxxxxxx> Signed-off-by: Greg Kroah-Hartman <gregkh@xxxxxxxxxxxxxxxxxxx> [bwh: Backported to 3.16: - The err5 path is not presnet - Adjust filename] Signed-off-by: Ben Hutchings <ben@xxxxxxxxxxxxxxx> --- --- a/drivers/usb/gadget/udc-core.c +++ b/drivers/usb/gadget/udc-core.c @@ -219,11 +219,7 @@ int usb_add_gadget_udc_release(struct de udc = kzalloc(sizeof(*udc), GFP_KERNEL); if (!udc) - goto err1; - - ret = device_add(&gadget->dev); - if (ret) - goto err2; + goto err_put_gadget; device_initialize(&udc->dev); udc->dev.release = usb_udc_release; @@ -232,7 +228,11 @@ int usb_add_gadget_udc_release(struct de udc->dev.parent = parent; ret = dev_set_name(&udc->dev, "%s", kobject_name(&parent->kobj)); if (ret) - goto err3; + goto err_put_udc; + + ret = device_add(&gadget->dev); + if (ret) + goto err_put_udc; udc->gadget = gadget; @@ -241,7 +241,7 @@ int usb_add_gadget_udc_release(struct de ret = device_add(&udc->dev); if (ret) - goto err4; + goto err_unlist_udc; usb_gadget_set_state(gadget, USB_STATE_NOTATTACHED); @@ -249,18 +249,16 @@ int usb_add_gadget_udc_release(struct de return 0; -err4: + err_unlist_udc: list_del(&udc->list); mutex_unlock(&udc_lock); -err3: - put_device(&udc->dev); device_del(&gadget->dev); -err2: - kfree(udc); + err_put_udc: + put_device(&udc->dev); -err1: + err_put_gadget: put_device(&gadget->dev); return ret; }