mbox series

[v3,0/2] Fix syzkaller bug: hung task in hub_port_init

Message ID 20210813182508.28127-1-mail@anirudhrb.com
Headers show
Series Fix syzkaller bug: hung task in hub_port_init | expand

Message

Anirudh Rayabharam Aug. 13, 2021, 6:25 p.m. UTC
This series fixes the hung task bug in hub_port_init reported by
syzkaller at:

https://syzkaller.appspot.com/bug?id=08f12df95ae7da69814e64eb5515d5a85ed06b76

The first patch in the series fixes the issue and the second patch does
some refactoring to avoid duplicate code.

Changes in v3:
- Split the patch into two patches
- Remove the convenience wrappers as suggested by Shuah
- Remove the WARN as suggested by Greg

Changes in v2:
Use WARN_ON() instead of BUG() when unlink_list is neither unlink_tx nor
unlink_rx.
v2: https://lore.kernel.org/lkml/20210806181335.2078-1-mail@anirudhrb.com/

v1: https://lore.kernel.org/lkml/20210806164015.25263-1-mail@anirudhrb.com/

Anirudh Rayabharam (2):
  usbip: give back URBs for unsent unlink requests during cleanup
  usbip: eliminate duplicate code in vhci_device_unlink_cleanup

 drivers/usb/usbip/vhci_hcd.c | 31 ++++++++++++++++++-------------
 1 file changed, 18 insertions(+), 13 deletions(-)

Comments

Shuah Khan Aug. 17, 2021, 11:16 p.m. UTC | #1
On 8/13/21 12:25 PM, Anirudh Rayabharam wrote:
> In vhci_device_unlink_cleanup(), the URBs for unsent unlink requests are

> not given back. This sometimes causes usb_kill_urb to wait indefinitely

> for that urb to be given back. syzbot has reported a hung task issue [1]

> for this.

> 

> To fix this, give back the urbs corresponding to unsent unlink requests

> (unlink_tx list) similar to how urbs corresponding to unanswered unlink

> requests (unlink_rx list) are given back.

> 

> [1]: https://syzkaller.appspot.com/bug?id=08f12df95ae7da69814e64eb5515d5a85ed06b76

> 

> Reported-by: syzbot+74d6ef051d3d2eacf428@syzkaller.appspotmail.com

> Tested-by: syzbot+74d6ef051d3d2eacf428@syzkaller.appspotmail.com

> Signed-off-by: Anirudh Rayabharam <mail@anirudhrb.com>

> ---

>   drivers/usb/usbip/vhci_hcd.c | 26 ++++++++++++++++++++++++++

>   1 file changed, 26 insertions(+)

> 

> diff --git a/drivers/usb/usbip/vhci_hcd.c b/drivers/usb/usbip/vhci_hcd.c

> index 4ba6bcdaa8e9..6f3f374d4bbc 100644

> --- a/drivers/usb/usbip/vhci_hcd.c

> +++ b/drivers/usb/usbip/vhci_hcd.c

> @@ -957,8 +957,34 @@ static void vhci_device_unlink_cleanup(struct vhci_device *vdev)

>   	spin_lock(&vdev->priv_lock);

>   

>   	list_for_each_entry_safe(unlink, tmp, &vdev->unlink_tx, list) {

> +		struct urb *urb;

> +

> +		/* give back URB of unsent unlink request */

>   		pr_info("unlink cleanup tx %lu\n", unlink->unlink_seqnum);


I know this is an exiting one.
Let's make this pr_debug or remove it all together.

> +

> +		urb = pickup_urb_and_free_priv(vdev, unlink->unlink_seqnum);

> +		if (!urb) {

> +			pr_info("the urb (seqnum %lu) was already given back\n",

> +				unlink->unlink_seqnum);


Let's make this pr_debug or remove it all together.

> +			list_del(&unlink->list);

> +			kfree(unlink);

> +			continue;

> +		}

> +

> +		urb->status = -ENODEV;

> +

> +		usb_hcd_unlink_urb_from_ep(hcd, urb);

> +

>   		list_del(&unlink->list);

> +

> +		spin_unlock(&vdev->priv_lock);

> +		spin_unlock_irqrestore(&vhci->lock, flags);

> +

> +		usb_hcd_giveback_urb(hcd, urb, urb->status);

> +

> +		spin_lock_irqsave(&vhci->lock, flags);

> +		spin_lock(&vdev->priv_lock);

> +

>   		kfree(unlink);

>   	}

>   

> 


thanks,
-- Shuah
Greg Kroah-Hartman Aug. 18, 2021, 5:39 a.m. UTC | #2
On Tue, Aug 17, 2021 at 05:16:51PM -0600, Shuah Khan wrote:
> On 8/13/21 12:25 PM, Anirudh Rayabharam wrote:

> > In vhci_device_unlink_cleanup(), the URBs for unsent unlink requests are

> > not given back. This sometimes causes usb_kill_urb to wait indefinitely

> > for that urb to be given back. syzbot has reported a hung task issue [1]

> > for this.

> > 

> > To fix this, give back the urbs corresponding to unsent unlink requests

> > (unlink_tx list) similar to how urbs corresponding to unanswered unlink

> > requests (unlink_rx list) are given back.

> > 

> > [1]: https://syzkaller.appspot.com/bug?id=08f12df95ae7da69814e64eb5515d5a85ed06b76

> > 

> > Reported-by: syzbot+74d6ef051d3d2eacf428@syzkaller.appspotmail.com

> > Tested-by: syzbot+74d6ef051d3d2eacf428@syzkaller.appspotmail.com

> > Signed-off-by: Anirudh Rayabharam <mail@anirudhrb.com>

> > ---

> >   drivers/usb/usbip/vhci_hcd.c | 26 ++++++++++++++++++++++++++

> >   1 file changed, 26 insertions(+)

> > 

> > diff --git a/drivers/usb/usbip/vhci_hcd.c b/drivers/usb/usbip/vhci_hcd.c

> > index 4ba6bcdaa8e9..6f3f374d4bbc 100644

> > --- a/drivers/usb/usbip/vhci_hcd.c

> > +++ b/drivers/usb/usbip/vhci_hcd.c

> > @@ -957,8 +957,34 @@ static void vhci_device_unlink_cleanup(struct vhci_device *vdev)

> >   	spin_lock(&vdev->priv_lock);

> >   	list_for_each_entry_safe(unlink, tmp, &vdev->unlink_tx, list) {

> > +		struct urb *urb;

> > +

> > +		/* give back URB of unsent unlink request */

> >   		pr_info("unlink cleanup tx %lu\n", unlink->unlink_seqnum);

> 

> I know this is an exiting one.

> Let's make this pr_debug or remove it all together.

> 

> > +

> > +		urb = pickup_urb_and_free_priv(vdev, unlink->unlink_seqnum);

> > +		if (!urb) {

> > +			pr_info("the urb (seqnum %lu) was already given back\n",

> > +				unlink->unlink_seqnum);

> 

> Let's make this pr_debug or remove it all together.


As you have a struct device for all of these, please use dev_dbg() and
friends, not pr_*(), for all of these.

thanks,

greg k-h
Shuah Khan Aug. 18, 2021, 6:36 p.m. UTC | #3
On 8/17/21 11:39 PM, Greg KH wrote:
> On Tue, Aug 17, 2021 at 05:16:51PM -0600, Shuah Khan wrote:

>> On 8/13/21 12:25 PM, Anirudh Rayabharam wrote:

>>> In vhci_device_unlink_cleanup(), the URBs for unsent unlink requests are

>>> not given back. This sometimes causes usb_kill_urb to wait indefinitely

>>> for that urb to be given back. syzbot has reported a hung task issue [1]

>>> for this.

>>>

>>> To fix this, give back the urbs corresponding to unsent unlink requests

>>> (unlink_tx list) similar to how urbs corresponding to unanswered unlink

>>> requests (unlink_rx list) are given back.

>>>

>>> [1]: https://syzkaller.appspot.com/bug?id=08f12df95ae7da69814e64eb5515d5a85ed06b76

>>>

>>> Reported-by: syzbot+74d6ef051d3d2eacf428@syzkaller.appspotmail.com

>>> Tested-by: syzbot+74d6ef051d3d2eacf428@syzkaller.appspotmail.com

>>> Signed-off-by: Anirudh Rayabharam <mail@anirudhrb.com>

>>> ---

>>>    drivers/usb/usbip/vhci_hcd.c | 26 ++++++++++++++++++++++++++

>>>    1 file changed, 26 insertions(+)

>>>

>>> diff --git a/drivers/usb/usbip/vhci_hcd.c b/drivers/usb/usbip/vhci_hcd.c

>>> index 4ba6bcdaa8e9..6f3f374d4bbc 100644

>>> --- a/drivers/usb/usbip/vhci_hcd.c

>>> +++ b/drivers/usb/usbip/vhci_hcd.c

>>> @@ -957,8 +957,34 @@ static void vhci_device_unlink_cleanup(struct vhci_device *vdev)

>>>    	spin_lock(&vdev->priv_lock);

>>>    	list_for_each_entry_safe(unlink, tmp, &vdev->unlink_tx, list) {

>>> +		struct urb *urb;

>>> +

>>> +		/* give back URB of unsent unlink request */

>>>    		pr_info("unlink cleanup tx %lu\n", unlink->unlink_seqnum);

>>

>> I know this is an exiting one.

>> Let's make this pr_debug or remove it all together.

>>

>>> +

>>> +		urb = pickup_urb_and_free_priv(vdev, unlink->unlink_seqnum);

>>> +		if (!urb) {

>>> +			pr_info("the urb (seqnum %lu) was already given back\n",

>>> +				unlink->unlink_seqnum);

>>

>> Let's make this pr_debug or remove it all together.

> 

> As you have a struct device for all of these, please use dev_dbg() and

> friends, not pr_*(), for all of these.

> 


Yes. Makes perfect sense.

thanks,
-- Shuah
Anirudh Rayabharam Aug. 19, 2021, 6:09 p.m. UTC | #4
On Wed, Aug 18, 2021 at 12:36:11PM -0600, Shuah Khan wrote:
> On 8/17/21 11:39 PM, Greg KH wrote:

> > On Tue, Aug 17, 2021 at 05:16:51PM -0600, Shuah Khan wrote:

> > > On 8/13/21 12:25 PM, Anirudh Rayabharam wrote:

> > > > In vhci_device_unlink_cleanup(), the URBs for unsent unlink requests are

> > > > not given back. This sometimes causes usb_kill_urb to wait indefinitely

> > > > for that urb to be given back. syzbot has reported a hung task issue [1]

> > > > for this.

> > > > 

> > > > To fix this, give back the urbs corresponding to unsent unlink requests

> > > > (unlink_tx list) similar to how urbs corresponding to unanswered unlink

> > > > requests (unlink_rx list) are given back.

> > > > 

> > > > [1]: https://syzkaller.appspot.com/bug?id=08f12df95ae7da69814e64eb5515d5a85ed06b76

> > > > 

> > > > Reported-by: syzbot+74d6ef051d3d2eacf428@syzkaller.appspotmail.com

> > > > Tested-by: syzbot+74d6ef051d3d2eacf428@syzkaller.appspotmail.com

> > > > Signed-off-by: Anirudh Rayabharam <mail@anirudhrb.com>

> > > > ---

> > > >    drivers/usb/usbip/vhci_hcd.c | 26 ++++++++++++++++++++++++++

> > > >    1 file changed, 26 insertions(+)

> > > > 

> > > > diff --git a/drivers/usb/usbip/vhci_hcd.c b/drivers/usb/usbip/vhci_hcd.c

> > > > index 4ba6bcdaa8e9..6f3f374d4bbc 100644

> > > > --- a/drivers/usb/usbip/vhci_hcd.c

> > > > +++ b/drivers/usb/usbip/vhci_hcd.c

> > > > @@ -957,8 +957,34 @@ static void vhci_device_unlink_cleanup(struct vhci_device *vdev)

> > > >    	spin_lock(&vdev->priv_lock);

> > > >    	list_for_each_entry_safe(unlink, tmp, &vdev->unlink_tx, list) {

> > > > +		struct urb *urb;

> > > > +

> > > > +		/* give back URB of unsent unlink request */

> > > >    		pr_info("unlink cleanup tx %lu\n", unlink->unlink_seqnum);

> > > 

> > > I know this is an exiting one.

> > > Let's make this pr_debug or remove it all together.

> > > 

> > > > +

> > > > +		urb = pickup_urb_and_free_priv(vdev, unlink->unlink_seqnum);

> > > > +		if (!urb) {

> > > > +			pr_info("the urb (seqnum %lu) was already given back\n",

> > > > +				unlink->unlink_seqnum);

> > > 

> > > Let's make this pr_debug or remove it all together.

> > 

> > As you have a struct device for all of these, please use dev_dbg() and

> > friends, not pr_*(), for all of these.

> > 

> 

> Yes. Makes perfect sense.


Perhaps we should use usbip_dbg_vhci_hc() instead of dev_dbg()? It is
one of the custom macros defined by the usbip driver for printing debug
logs.

Thanks,

	Anirudh
Shuah Khan Aug. 19, 2021, 6:49 p.m. UTC | #5
On 8/19/21 12:09 PM, Anirudh Rayabharam wrote:
> On Wed, Aug 18, 2021 at 12:36:11PM -0600, Shuah Khan wrote:

>> On 8/17/21 11:39 PM, Greg KH wrote:

>>> On Tue, Aug 17, 2021 at 05:16:51PM -0600, Shuah Khan wrote:

>>>> On 8/13/21 12:25 PM, Anirudh Rayabharam wrote:

>>>>> In vhci_device_unlink_cleanup(), the URBs for unsent unlink requests are

>>>>> not given back. This sometimes causes usb_kill_urb to wait indefinitely

>>>>> for that urb to be given back. syzbot has reported a hung task issue [1]

>>>>> for this.

>>>>>

>>>>> To fix this, give back the urbs corresponding to unsent unlink requests

>>>>> (unlink_tx list) similar to how urbs corresponding to unanswered unlink

>>>>> requests (unlink_rx list) are given back.

>>>>>

>>>>> [1]: https://syzkaller.appspot.com/bug?id=08f12df95ae7da69814e64eb5515d5a85ed06b76

>>>>>

>>>>> Reported-by: syzbot+74d6ef051d3d2eacf428@syzkaller.appspotmail.com

>>>>> Tested-by: syzbot+74d6ef051d3d2eacf428@syzkaller.appspotmail.com

>>>>> Signed-off-by: Anirudh Rayabharam <mail@anirudhrb.com>

>>>>> ---

>>>>>     drivers/usb/usbip/vhci_hcd.c | 26 ++++++++++++++++++++++++++

>>>>>     1 file changed, 26 insertions(+)

>>>>>

>>>>> diff --git a/drivers/usb/usbip/vhci_hcd.c b/drivers/usb/usbip/vhci_hcd.c

>>>>> index 4ba6bcdaa8e9..6f3f374d4bbc 100644

>>>>> --- a/drivers/usb/usbip/vhci_hcd.c

>>>>> +++ b/drivers/usb/usbip/vhci_hcd.c

>>>>> @@ -957,8 +957,34 @@ static void vhci_device_unlink_cleanup(struct vhci_device *vdev)

>>>>>     	spin_lock(&vdev->priv_lock);

>>>>>     	list_for_each_entry_safe(unlink, tmp, &vdev->unlink_tx, list) {

>>>>> +		struct urb *urb;

>>>>> +

>>>>> +		/* give back URB of unsent unlink request */

>>>>>     		pr_info("unlink cleanup tx %lu\n", unlink->unlink_seqnum);

>>>>

>>>> I know this is an exiting one.

>>>> Let's make this pr_debug or remove it all together.

>>>>

>>>>> +

>>>>> +		urb = pickup_urb_and_free_priv(vdev, unlink->unlink_seqnum);

>>>>> +		if (!urb) {

>>>>> +			pr_info("the urb (seqnum %lu) was already given back\n",

>>>>> +				unlink->unlink_seqnum);

>>>>

>>>> Let's make this pr_debug or remove it all together.

>>>

>>> As you have a struct device for all of these, please use dev_dbg() and

>>> friends, not pr_*(), for all of these.

>>>

>>

>> Yes. Makes perfect sense.

> 

> Perhaps we should use usbip_dbg_vhci_hc() instead of dev_dbg()? It is

> one of the custom macros defined by the usbip driver for printing debug

> logs.

> 


Yes that macro could be used. However, let's just get rid of the messages.
I don't see much use for them.

thanks,
-- Shuah