lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite for Android: free password hash cracker in your pocket
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <20160926165121.GA5353@wunner.de>
Date:   Mon, 26 Sep 2016 18:51:21 +0200
From:   Lukas Wunner <lukas@...ner.de>
To:     "Rafael J. Wysocki" <rjw@...ysocki.net>
Cc:     Linux PM list <linux-pm@...r.kernel.org>,
        Greg Kroah-Hartman <gregkh@...uxfoundation.org>,
        Alan Stern <stern@...land.harvard.edu>,
        Linux Kernel Mailing List <linux-kernel@...r.kernel.org>,
        Tomeu Vizoso <tomeu.vizoso@...labora.com>,
        Mark Brown <broonie@...nel.org>,
        Marek Szyprowski <m.szyprowski@...sung.com>,
        Kevin Hilman <khilman@...nel.org>,
        Ulf Hansson <ulf.hansson@...aro.org>,
        "Luis R. Rodriguez" <mcgrof@...e.com>
Subject: Re: [Update][RFC/RFT][PATCH v3 2/5] driver core: Functional
 dependencies tracking support

On Fri, Sep 23, 2016 at 03:42:31PM +0200, Rafael J. Wysocki wrote:
> On Tuesday, September 20, 2016 12:46:30 AM Lukas Wunner wrote:
> > On Fri, Sep 16, 2016 at 02:33:55PM +0200, Rafael J. Wysocki wrote:
> > > +void device_links_no_driver(struct device *dev)
> > > +{
> > > +	struct device_link *link, *ln;
> > > +
> > > +	mutex_lock(&device_links_lock);
> > > +
> > > +	list_for_each_entry_safe_reverse(link, ln, &dev->links_to_suppliers, c_node) {
> > > +		if (link->flags & DEVICE_LINK_STATELESS)
> > > +			continue;
> > > +
> > > +		if (link->flags & DEVICE_LINK_AUTOREMOVE) {
> > > +			__device_link_del(link);
> > 
> > The link will be autoremoved not only when the consumer unbinds,
> > but also when probing the consumer fails.
> > 
> > Looks like a bug.
> 
> It really was intentional, because the use case I see for AUTOREMOVE (and
> the only one to be honest) is when the link is created by the consumer
> probe in which case it wants to avoid worrying about the cleanup part.
> 
> Which also is applicable to the cleanup when the probe fails IMO.

You're right, makes sense.


> > > +void device_links_unbind_consumers(struct device *dev)
> > > +{
> > > +	struct device_link *link;
> > > +	int idx;
> > > +
> > > + start:
> > > +	idx = device_links_read_lock();
> > > +
> > > +	list_for_each_entry_rcu(link, &dev->links_to_consumers, s_node) {
> > > +		enum device_link_status status;
> > > +
> > > +		if (link->flags & DEVICE_LINK_STATELESS)
> > > +			continue;
> > > +
> > > +		spin_lock(&link->lock);
> > > +		status = link->status;
> > > +		if (status == DEVICE_LINK_CONSUMER_PROBE) {
> > > +			spin_unlock(&link->lock);
> > > +
> > > +			device_links_read_unlock(idx);
> > > +
> > > +			wait_for_device_probe();
> > > +			goto start;
> > > +		}
> > > +		link->status = DEVICE_LINK_SUPPLIER_UNBIND;
> > > +		if (status == DEVICE_LINK_ACTIVE) {
> > > +			struct device *consumer = link->consumer;
> > > +
> > > +			get_device(consumer);
> > > +			spin_unlock(&link->lock);
> > 
> > The lock is released both at the beginning of this if-block and
> > immediately after the if-block (in case the if-condition is false).
> > Why not simply release the lock *before* the if-block?
> 
> Because the get_device() needs to be done under the lock.

According to the commit message, the spinlock only protects the status
field and the consumer device is prevented from disappearing with the RCU.
So the spin lock could be released before the if-block AFAICS.
(But perhaps there are style/readability reasons to have the unlock both
in the if-block and afterwards.)


> > > @@ -1233,6 +1680,7 @@ void device_del(struct device *dev)
> > >  {
> > >  	struct device *parent = dev->parent;
> > >  	struct class_interface *class_intf;
> > > +	struct device_link *link, *ln;
> > >  
> > >  	/* Notify clients of device removal.  This call must come
> > >  	 * before dpm_sysfs_remove().
> > > @@ -1240,6 +1688,30 @@ void device_del(struct device *dev)
> > >  	if (dev->bus)
> > >  		blocking_notifier_call_chain(&dev->bus->p->bus_notifier,
> > >  					     BUS_NOTIFY_DEL_DEVICE, dev);
> > > +
> > > +	/*
> > > +	 * Delete all of the remaining links from this device to any other
> > > +	 * devices (either consumers or suppliers).
> > > +	 *
> > > +	 * This requires that all links be dormant, so warn if that's no the
> > > +	 * case.
> > > +	 */
> > > +	mutex_lock(&device_links_lock);
> > > +
> > > +	list_for_each_entry_safe_reverse(link, ln, &dev->links_to_suppliers, c_node) {
> > > +		WARN_ON(link->status != DEVICE_LINK_DORMANT &&
> > > +			!(link->flags & DEVICE_LINK_STATELESS));
> > > +		__device_link_del(link);
> > > +	}
> > 
> > Shouldn't it also be legal for the supplier links to be in
> > DEVICE_LINK_AVAILABLE state upon removal of a consumer device?
> > 
> > (And perhaps also DEVICE_LINK_SUPPLIER_UNBIND?)
> > 
> > Looks like a bug.
> 
> But this is done after removing the supplier driver, so the state should be
> DORMANT (unless the link is stateless), shouldn't it?

The scenario I have in mind is that the supplier device is bound to a
driver and the consumer device has no driver and is being removed.
In that case the status will be DEVICE_LINK_AVAILABLE and the user
will get a WARN splat, which seems gratuitous because it should be legal.

And the other scenario is when the supplier is unbinding. It iterates
over the links to consumers and puts them in DEVICE_LINK_SUPPLIER_UNBIND.
Let's say the link to consumer A was put into that state, but there's
a consumer B remaining which is bound.  The RCU and spinlock are unlocked
before device_release_driver_internal() is called for that consumer.
If at that point consumer device A is removed for whatever reason,
the link will also be removed and the user will again get a gratuitous
WARN splat.


Thanks,

Lukas

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ