Skip to content

Commit

Permalink
USB: UDC core: fix double-free in usb_add_gadget_udc_release
Browse files Browse the repository at this point in the history
commit 7ae2c3c 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 <[email protected]>
Reported-by: Fengguang Wu <[email protected]>
Reviewed-by: Peter Chen <[email protected]>
Acked-by: Felipe Balbi <[email protected]>
Signed-off-by: Greg Kroah-Hartman <[email protected]>
  • Loading branch information
AlanStern authored and gregkh committed Jan 17, 2018
1 parent 204d8fb commit 2817c4c
Showing 1 changed file with 13 additions and 15 deletions.
28 changes: 13 additions & 15 deletions drivers/usb/gadget/udc/core.c
Original file line number Diff line number Diff line change
Expand Up @@ -1158,11 +1158,7 @@ int usb_add_gadget_udc_release(struct device *parent, struct usb_gadget *gadget,

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;
Expand All @@ -1171,7 +1167,11 @@ int usb_add_gadget_udc_release(struct device *parent, struct usb_gadget *gadget,
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;
gadget->udc = udc;
Expand All @@ -1181,35 +1181,33 @@ int usb_add_gadget_udc_release(struct device *parent, struct usb_gadget *gadget,

ret = device_add(&udc->dev);
if (ret)
goto err4;
goto err_unlist_udc;

usb_gadget_set_state(gadget, USB_STATE_NOTATTACHED);
udc->vbus = true;

/* pick up one of pending gadget drivers */
ret = check_pending_gadget_drivers(udc);
if (ret)
goto err5;
goto err_del_udc;

mutex_unlock(&udc_lock);

return 0;

err5:
err_del_udc:
device_del(&udc->dev);

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;
}
Expand Down

0 comments on commit 2817c4c

Please sign in to comment.