Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit d1c6c030 authored by Ming Lei's avatar Ming Lei Committed by Greg Kroah-Hartman
Browse files

driver core: fix shutdown races with probe/remove(v3)



Firstly, .shutdown callback may touch a uninitialized hardware
if dev->driver is set and .probe is not completed.

Secondly, device_shutdown() may dereference a null pointer to cause
oops when dev->driver is cleared after it has been checked in
device_shutdown().

So just hold device lock and its parent lock(if it has) to
fix the races.

Cc: Alan Stern <stern@rowland.harvard.edu>
Signed-off-by: default avatarMing Lei <ming.lei@canonical.com>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent 6fbfd059
Loading
Loading
Loading
Loading
+18 −0
Original line number Diff line number Diff line
@@ -1812,6 +1812,13 @@ void device_shutdown(void)
	while (!list_empty(&devices_kset->list)) {
		dev = list_entry(devices_kset->list.prev, struct device,
				kobj.entry);

		/*
		 * hold reference count of device's parent to
		 * prevent it from being freed because parent's
		 * lock is to be held
		 */
		get_device(dev->parent);
		get_device(dev);
		/*
		 * Make sure the device is off the kset list, in the
@@ -1820,6 +1827,11 @@ void device_shutdown(void)
		list_del_init(&dev->kobj.entry);
		spin_unlock(&devices_kset->list_lock);

		/* hold lock to avoid race with probe/release */
		if (dev->parent)
			device_lock(dev->parent);
		device_lock(dev);

		/* Don't allow any more runtime suspends */
		pm_runtime_get_noresume(dev);
		pm_runtime_barrier(dev);
@@ -1831,7 +1843,13 @@ void device_shutdown(void)
			dev_dbg(dev, "shutdown\n");
			dev->driver->shutdown(dev);
		}

		device_unlock(dev);
		if (dev->parent)
			device_unlock(dev->parent);

		put_device(dev);
		put_device(dev->parent);

		spin_lock(&devices_kset->list_lock);
	}