All of lore.kernel.org
 help / color / mirror / Atom feed
From: Olivier Sobrie <olivier@sobrie.be>
To: Oliver Neukum <oneukum@suse.de>
Cc: Jan Dumon <j.dumon@option.com>,
	Greg Kroah-Hartman <gregkh@linuxfoundation.org>,
	linux-kernel@vger.kernel.org, linux-usb@vger.kernel.org,
	netdev@vger.kernel.org
Subject: Re: [PATCH 11/11] usb: core: fix a race with usb_queue_reset_device()
Date: Tue, 20 Jan 2015 16:10:01 +0100	[thread overview]
Message-ID: <20150120151001.GA5681@hposo> (raw)
In-Reply-To: <1421761717.29486.24.camel@linux-0dmf.site>

Hi Oliver,

On Tue, Jan 20, 2015 at 02:48:37PM +0100, Oliver Neukum wrote:
> On Tue, 2015-01-20 at 13:29 +0100, Olivier Sobrie wrote:
> > When usb_queue_reset() is called it schedules a work in view of
> > resetting the usb interface. When the reset work is running, it
> > can be scheduled again (e.g. by the usb disconnect method of
> > the driver).
> > 
> > Consider that the reset work is queued again while the reset work
> > is running and that this work leads to a forced unbinding of the
> > usb interface (e.g. because a driver is bound to the interface
> > and has no pre/post_reset methods - see usb_reset_device()).
> > In such condition, usb_unbind_interface() gets called and this
> > function calls usb_cancel_queued_reset() which does nothing
> > because the flag "reset_running" is set to 1. The second reset
> > work that has been scheduled is therefore not cancelled.
> > Later, the usb_reset_device() tries to rebind the interface.
> > If it fails, then the usb interface context which contain the
> > reset work struct is freed and it most likely crash when the
> > second reset work tries to be run.
> > 
> > The following flow shows the problem:
> > * usb_queue_reset_device()
> > * __usb_queue_reset_device() <- If the reset work is queued after here, then
> >     reset_running = 1           it will never be cancelled.
> >     usb_reset_device()
> >       usb_forced_unbind_intf()
> >         usb_driver_release_interface()
> >           usb_unbind_interface()
> >             driver->disconnect()
> >               usb_queue_reset_device() <- second reset
> 
> That is the sledgehammer approach. Wouldn't it be better to guarantee
> that usb_queue_reset_device() be a nop when reset_running==1 ?

If I'm right, we have to prevent that usb_queue_reset_device() shedules
the work a second time before the variable reset_running is set.
An other task can requeue a reset while the work __usb_queue_reset_device()
is busy but when the flag reset_running hasn't been set yet.

I see different other approaches to solve the problem:

 * Setting a flag in the usb_queue_reset_device() when a reset has been
   scheduled and resetting this flag when the reset is done. This implies
   a locking mechanism around the flag.

 * Avoid that the hso driver queues multiple resets by using a flag. It
   also requires locking. It comes more or less to the same solution
   as the previous one but the patch is done in the hso driver.

 * using get_device() and put_device() to avoid that the usb interface
   structure get freed before the second reset is run.
   I mean:
	void usb_queue_reset_device(struct usb_interface *iface)
	{
		get_device()
		if (!schedule_work(&iface->reset_ws))
			put_device()
	}

	static void __usb_queue_reset_device(struct work_struct *ws)
	{
		...
		put_device()
	}

   But this solution does not avoid the second reset...

If you have other better ideas, let me know.
Correct me if I'm wrong.

Thank you,

Olivier

> 
> >             usb_cancel_queued_reset() <- does nothing because
> >                                          the flag reset_running
> >                                          is set
> >       usb_unbind_and_rebind_marked_interfaces()
> >         usb_rebind_intf()
> >           device_attach()
> >             driver->probe() <- fails (no more drivers hold a reference to
> > 				      the usb interface)
> >     reset_running = 0
> > * hub_event()
> >     usb_disconnect()
> >       usb_disable_device()
> >         kobject_release()
> >           device_release()
> >             usb_release_interface()
> >               kfree(intf) <- usb interface context is released
> >                              while we still have a pending reset
> >                              work that should be run
> > 
> > To avoid this problem, we use a delayed work so that if the reset
> > work is currently run, we can avoid further call to
> > __usb_queue_reset_device() work by using cancel_delayed_work().
> > Unfortunately it increases the size of the usb_interface structure...
> 
> 	Regards
> 		Oliver
> 
> -- 
> Oliver Neukum <oneukum@suse.de>
> 

-- 
Olivier

  reply	other threads:[~2015-01-20 15:10 UTC|newest]

Thread overview: 40+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2015-01-20 12:29 [PATCH 00/11] hso: fix some problems with reset/disconnect path Olivier Sobrie
2015-01-20 12:29 ` [PATCH 01/11] hso: remove useless header file timer.h Olivier Sobrie
2015-01-20 12:29   ` [PATCH 02/11] hso: fix crash when device disappears while serial port is open Olivier Sobrie
2015-01-20 12:29     ` [PATCH 03/11] hso: fix memory leak when device disconnects Olivier Sobrie
2015-01-20 12:29       ` [PATCH 04/11] hso: fix memory leak in hso_create_rfkill() Olivier Sobrie
2015-01-20 12:29         ` [PATCH 05/11] hso: fix small indentation error Olivier Sobrie
2015-01-20 12:29           ` [PATCH 06/11] hso: rename hso_dev into serial in hso_free_interface() Olivier Sobrie
2015-01-20 12:29             ` Olivier Sobrie
2015-01-20 12:29             ` [PATCH 07/11] hso: replace reset_device work by usb_queue_reset_device() Olivier Sobrie
2015-01-20 12:29               ` [PATCH 08/11] hso: move tty_unregister outside hso_serial_common_free() Olivier Sobrie
2015-01-20 12:29                 ` [PATCH 09/11] hso: update serial_table in usb disconnect method Olivier Sobrie
2015-01-20 12:29                   ` [PATCH 10/11] hso: add missing cancel_work_sync in disconnect() Olivier Sobrie
2015-01-20 12:29                     ` [PATCH 11/11] usb: core: fix a race with usb_queue_reset_device() Olivier Sobrie
2015-01-20 13:48                       ` Oliver Neukum
2015-01-20 15:10                         ` Olivier Sobrie [this message]
2015-01-20 15:26                       ` Alan Stern
2015-01-20 16:30                         ` Olivier Sobrie
2015-01-21 13:55                         ` Olivier Sobrie
2015-01-21 18:52                           ` Alan Stern
2015-01-21 18:52                             ` Alan Stern
2015-01-20 13:13         ` [PATCH 04/11] hso: fix memory leak in hso_create_rfkill() Oliver Neukum
2015-01-20 15:10           ` Olivier Sobrie
2015-01-20 18:41           ` Dan Williams
2015-01-30 12:21 ` [PATCH v2 00/11] hso: fix some problems in the disconnect path Olivier Sobrie
2015-01-30 12:21   ` [PATCH v2 01/11] hso: remove useless header file timer.h Olivier Sobrie
2015-01-30 12:21     ` [PATCH v2 02/11] hso: fix crash when device disappears while serial port is open Olivier Sobrie
2015-01-30 12:21       ` [PATCH v2 03/11] hso: fix memory leak when device disconnects Olivier Sobrie
2015-01-30 12:21         ` [PATCH v2 04/11] hso: fix memory leak in hso_create_rfkill() Olivier Sobrie
2015-01-30 12:21           ` [PATCH v2 05/11] hso: fix small indentation error Olivier Sobrie
2015-01-30 12:21             ` [PATCH v2 06/11] hso: rename hso_dev into serial in hso_free_interface() Olivier Sobrie
2015-01-30 12:21               ` [PATCH v2 07/11] hso: replace reset_device work by usb_queue_reset_device() Olivier Sobrie
2015-01-30 12:22                 ` [PATCH v2 08/11] hso: move tty_unregister outside hso_serial_common_free() Olivier Sobrie
2015-01-30 12:22                   ` [PATCH v2 09/11] hso: update serial_table in usb disconnect method Olivier Sobrie
2015-01-30 12:22                     ` [PATCH v2 10/11] hso: add missing cancel_work_sync in disconnect() Olivier Sobrie
2015-01-30 12:22                       ` [PATCH v2 11/11] hso: fix rfkill name conflicts Olivier Sobrie
2015-01-30 15:47                         ` Dan Williams
2015-01-30 16:15                           ` Olivier Sobrie
2015-01-30 16:59                             ` Dan Williams
2015-02-01 20:33   ` [PATCH v2 00/11] hso: fix some problems in the disconnect path David Miller
2015-02-01 20:33     ` David Miller

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20150120151001.GA5681@hposo \
    --to=olivier@sobrie.be \
    --cc=gregkh@linuxfoundation.org \
    --cc=j.dumon@option.com \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-usb@vger.kernel.org \
    --cc=netdev@vger.kernel.org \
    --cc=oneukum@suse.de \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.