regulator_unregister() stops rdev->disable_work with flush_work(&dw->work), which is a no-op for a delayed_work pending on the timer wheel: flush_work() only waits for a queued or running work item. A disable deferred by a consumer's regulator_disable_deferred() therefore survives the provider's unbind, and regulator_disable_work() fires after device_unregister() has freed the rdev, dereferencing it via container_of(). Use-after-free. The in-tree users are ASoC DAPM regulator widgets with a 20 ms power-down delay (sound/soc/soc-dapm.c): the window is the entire deferral period, not a race between adjacent instructions. Use cancel_delayed_work_sync(), which also dequeues a timer-pending instance, waits for a running callback and blocks re-arming. Found by static analysis. Cc: stable@vger.kernel.org Signed-off-by: Chengyu Liu --- drivers/regulator/core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c index 6a4008f387..032b7298a5 100644 --- a/drivers/regulator/core.c +++ b/drivers/regulator/core.c @@ -6300,7 +6300,7 @@ void regulator_unregister(struct regulator_dev *rdev) regulator_put(rdev->supply); } - flush_work(&rdev->disable_work.work); + cancel_delayed_work_sync(&rdev->disable_work); mutex_lock(®ulator_list_mutex); -- 2.25.1