Skip to content

Commit 5c9ecd8

Browse files
2045geminirafaeljw
authored andcommitted
PM: sleep: wakeirq: harden dev_pm_clear_wake_irq() against races
dev_pm_clear_wake_irq() currently uses a dangerous pattern where dev->power.wakeirq is read and checked for NULL outside the lock. If two callers invoke this function concurrently, both might see a valid pointer and proceed. This could result in a double-free when the second caller acquires the lock and tries to release the same object. Address this by removing the lockless check of dev->power.wakeirq. Instead, acquire dev->power.lock immediately to ensure the check and the subsequent operations are atomic. If dev->power.wakeirq is NULL under the lock, simply unlock and return. This guarantees that concurrent calls cannot race to free the same object. Based on a quick scan of current users, I did not find an actual bug as drivers seem to rely on their own synchronization. However, since asynchronous usage patterns exist (e.g., in drivers/net/wireless/ti/wlcore), I believe a race is theoretically possible if the API is used less carefully in the future. This change hardens the API to be robust against such cases. Fixes: 4990d4f ("PM / Wakeirq: Add automated device wake IRQ handling") Signed-off-by: Gui-Dong Han <hanguidong02@gmail.com> Link: https://patch.msgid.link/20260203031943.1924-1-hanguidong02@gmail.com Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
1 parent 75ce02f commit 5c9ecd8

1 file changed

Lines changed: 6 additions & 3 deletions

File tree

drivers/base/power/wakeirq.c

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -83,13 +83,16 @@ EXPORT_SYMBOL_GPL(dev_pm_set_wake_irq);
8383
*/
8484
void dev_pm_clear_wake_irq(struct device *dev)
8585
{
86-
struct wake_irq *wirq = dev->power.wakeirq;
86+
struct wake_irq *wirq;
8787
unsigned long flags;
8888

89-
if (!wirq)
89+
spin_lock_irqsave(&dev->power.lock, flags);
90+
wirq = dev->power.wakeirq;
91+
if (!wirq) {
92+
spin_unlock_irqrestore(&dev->power.lock, flags);
9093
return;
94+
}
9195

92-
spin_lock_irqsave(&dev->power.lock, flags);
9396
device_wakeup_detach_irq(dev);
9497
dev->power.wakeirq = NULL;
9598
spin_unlock_irqrestore(&dev->power.lock, flags);

0 commit comments

Comments
 (0)