2014-01-02 19:22:22

by Alan Stern

[permalink] [raw]
Subject: RE: [PATCH] usb/core: fix NULL pointer dereference in recursively_mark_NOTATTACHED

On Thu, 26 Dec 2013, Du, ChangbinX wrote:

> I can reproduce issue by adding a delay just after usb_set_intfdata(intf, NULL)
> (echo -1 > bConfigurationValue to trigger hub_dissconnect())without your patch.
>
> After patch applied, cannot reproduce and didn't found any other issue. Patch works well.
>
> Alan, need I update patch to v2 or you will do it?

Changbin, after looking more closely I realized there was a second
aspect to this race: recursively_mark_NOTATTACHED uses hub->ports[i]
while hub_disconnect removes the port devices. You ought to be
able to cause an oops by inserting a delay just after the loop where
usb_hub_remove_port_device is called.

The updated patch below should fix both problems. Can you test it?

Alan Stern



Index: usb-3.13/drivers/usb/core/hub.c
===================================================================
--- usb-3.13.orig/drivers/usb/core/hub.c
+++ usb-3.13/drivers/usb/core/hub.c
@@ -1607,7 +1607,7 @@ static void hub_disconnect(struct usb_in
{
struct usb_hub *hub = usb_get_intfdata(intf);
struct usb_device *hdev = interface_to_usbdev(intf);
- int i;
+ int port1;

/* Take the hub off the event list and don't let it be added again */
spin_lock_irq(&hub_event_lock);
@@ -1622,11 +1622,15 @@ static void hub_disconnect(struct usb_in
hub->error = 0;
hub_quiesce(hub, HUB_DISCONNECT);

- usb_set_intfdata (intf, NULL);
+ /* Avoid races with recursively_mark_NOTATTACHED() */
+ spin_lock_irq(&device_state_lock);
+ port1 = hdev->maxchild;
+ hdev->maxchild = 0;
+ usb_set_intfdata(intf, NULL);
+ spin_unlock_irq(&device_state_lock);

- for (i = 0; i < hdev->maxchild; i++)
- usb_hub_remove_port_device(hub, i + 1);
- hub->hdev->maxchild = 0;
+ for (; port1 > 0; --port1)
+ usb_hub_remove_port_device(hub, port1);

if (hub->hdev->speed == USB_SPEED_HIGH)
highspeed_hubs--;


2014-01-03 01:44:26

by Du, ChangbinX

[permalink] [raw]
Subject: RE: [PATCH] usb/core: fix NULL pointer dereference in recursively_mark_NOTATTACHED

> On Thu, 26 Dec 2013, Du, ChangbinX wrote:
>
> > I can reproduce issue by adding a delay just after
> > usb_set_intfdata(intf, NULL) (echo -1 > bConfigurationValue to trigger
> hub_dissconnect())without your patch.
> >
> > After patch applied, cannot reproduce and didn't found any other issue.
> Patch works well.
> >
> > Alan, need I update patch to v2 or you will do it?
>
> Changbin, after looking more closely I realized there was a second aspect to
> this race: recursively_mark_NOTATTACHED uses hub->ports[i] while
> hub_disconnect removes the port devices. You ought to be able to cause
> an oops by inserting a delay just after the loop where
> usb_hub_remove_port_device is called.
>
> The updated patch below should fix both problems. Can you test it?
>
> Alan Stern
>

Ok, I'll test it today or tomorrow. Please wait my response.

2014-01-07 09:16:55

by Du, ChangbinX

[permalink] [raw]
Subject: RE: [PATCH] usb/core: fix NULL pointer dereference in recursively_mark_NOTATTACHED

> > Changbin, after looking more closely I realized there was a second
> > aspect to this race: recursively_mark_NOTATTACHED uses hub->ports[i]
> > while hub_disconnect removes the port devices. You ought to be able
> > to cause an oops by inserting a delay just after the loop where
> > usb_hub_remove_port_device is called.
> >
> > The updated patch below should fix both problems. Can you test it?
> >
> > Alan Stern
> >
>
> Ok, I'll test it today or tomorrow. Please wait my response.

Alan, I cannot cause a panic after inserting a delay just after
usb_hub_remove_port_device is called, even move the delay after
kfree(hub->ports). recursively_mark_NOTATTACHED will not access
hub->ports[i] since maxchild has been set to 0.

Alan, I think your last patch can fix this issue.

2014-01-07 15:35:00

by Alan Stern

[permalink] [raw]
Subject: RE: [PATCH] usb/core: fix NULL pointer dereference in recursively_mark_NOTATTACHED

On Tue, 7 Jan 2014, Du, ChangbinX wrote:

> > > Changbin, after looking more closely I realized there was a second
> > > aspect to this race: recursively_mark_NOTATTACHED uses hub->ports[i]
> > > while hub_disconnect removes the port devices. You ought to be able
> > > to cause an oops by inserting a delay just after the loop where
> > > usb_hub_remove_port_device is called.
> > >
> > > The updated patch below should fix both problems. Can you test it?
> > >
> > > Alan Stern
> > >
> >
> > Ok, I'll test it today or tomorrow. Please wait my response.
>
> Alan, I cannot cause a panic after inserting a delay just after
> usb_hub_remove_port_device is called, even move the delay after
> kfree(hub->ports). recursively_mark_NOTATTACHED will not access
> hub->ports[i] since maxchild has been set to 0.
>
> Alan, I think your last patch can fix this issue.

Okay, thanks for testing. I will submit the patch.

Alan Stern