mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
* [PATCH] rtc: atcrtc100: drain the alarm work before the RTC device is freed
@ 2026-11-07  6:37 hyunjungg
  0 siblings, 0 replies; only message in thread
From: hyunjungg @ 2026-11-07  6:37 UTC (permalink / raw)
  To: CL Wang, Alexandre Belloni, linux-rtc; +Cc: linux-kernel, Hyunjung Ko, stable

From: Hyunjung Ko <hj351016@gmail.com>

atcrtc_alarm_isr() schedules atcrtc_dev->rtc_work (atcrtc_alarm_clear),
whose handler obtains the atcrtc_dev via container_of() and dereferences
rtc->rtc_dev (guard(rtc_ops)(rtc->rtc_dev)).

atcrtc_probe() requested the alarm IRQ with devm_request_irq() *before*
allocating rtc_dev with devm_rtc_allocate_device(), and INIT_WORK()'d
rtc_work last with no teardown cancel.  Because devres unwinds in reverse
registration order, on unbind the RTC device is freed before the IRQ, and
rtc_work is never cancelled at all: an alarm interrupt arriving around
unbind can run atcrtc_alarm_clear() after rtc->rtc_dev (and the devm
driver data) have been freed -> use-after-free.

Allocate the RTC device first, then register rtc_work for device-managed
cancellation with devm_work_autocancel(), and only then request the IRQ.
devres now frees the IRQ first (so it can no longer schedule the work),
then drains the work while rtc_dev is still valid, then frees rtc_dev and
the driver data.

Found by code review; not reproduced (requires ATCRTC100 hardware and an
alarm interrupt racing device unbind).

Fixes: 7adca706fe16 ("rtc: atcrtc100: Add ATCRTC100 RTC driver")
Cc: stable@vger.kernel.org
Signed-off-by: Hyunjung Ko <hj351016@gmail.com>
---
 drivers/rtc/rtc-atcrtc100.c | 30 +++++++++++++++++++++---------
 1 file changed, 21 insertions(+), 9 deletions(-)

diff --git a/drivers/rtc/rtc-atcrtc100.c b/drivers/rtc/rtc-atcrtc100.c
index 2433df3..51a38f0 100644
--- a/drivers/rtc/rtc-atcrtc100.c
+++ b/drivers/rtc/rtc-atcrtc100.c
@@ -7,6 +7,7 @@
 
 #include <linux/bitfield.h>
 #include <linux/delay.h>
+#include <linux/devm-helpers.h>
 #include <linux/interrupt.h>
 #include <linux/math64.h>
 #include <linux/module.h>
@@ -301,6 +302,26 @@ static int atcrtc_probe(struct platform_device *pdev)
 				     "Failed to get IRQ for alarm\n");
 	atcrtc_dev->alarm_irq = ret;
 
+	atcrtc_dev->rtc_dev = devm_rtc_allocate_device(&pdev->dev);
+	if (IS_ERR(atcrtc_dev->rtc_dev))
+		return dev_err_probe(&pdev->dev, PTR_ERR(atcrtc_dev->rtc_dev),
+				     "Failed to allocate RTC device\n");
+
+	set_bit(RTC_FEATURE_ALARM, atcrtc_dev->rtc_dev->features);
+	atcrtc_dev->rtc_dev->ops = &rtc_ops;
+
+	/*
+	 * Register rtc_work for device-managed cancellation after the RTC
+	 * device it dereferences and before the IRQ that schedules it, so on
+	 * unbind devres frees the IRQ, then drains the work, then frees the
+	 * RTC device and driver data -- never the reverse (atcrtc_alarm_clear()
+	 * touches rtc->rtc_dev).
+	 */
+	ret = devm_work_autocancel(&pdev->dev, &atcrtc_dev->rtc_work,
+				   atcrtc_alarm_clear);
+	if (ret)
+		return ret;
+
 	ret = devm_request_irq(&pdev->dev,
 			       atcrtc_dev->alarm_irq,
 			       atcrtc_alarm_isr,
@@ -312,12 +333,6 @@ static int atcrtc_probe(struct platform_device *pdev)
 				     "Failed to request IRQ %d for alarm\n",
 				     atcrtc_dev->alarm_irq);
 
-	atcrtc_dev->rtc_dev = devm_rtc_allocate_device(&pdev->dev);
-	if (IS_ERR(atcrtc_dev->rtc_dev))
-		return dev_err_probe(&pdev->dev, PTR_ERR(atcrtc_dev->rtc_dev),
-				     "Failed to allocate RTC device\n");
-
-	set_bit(RTC_FEATURE_ALARM, atcrtc_dev->rtc_dev->features);
 	ret = device_init_wakeup(&pdev->dev, true);
 	if (ret)
 		return dev_err_probe(&pdev->dev, ret,
@@ -330,9 +345,6 @@ static int atcrtc_probe(struct platform_device *pdev)
 				     "Failed to set wake IRQ\n");
 	}
 
-	atcrtc_dev->rtc_dev->ops = &rtc_ops;
-
-	INIT_WORK(&atcrtc_dev->rtc_work, atcrtc_alarm_clear);
 	return devm_rtc_register_device(atcrtc_dev->rtc_dev);
 }
 
-- 
2.43.0


^ permalink raw reply	[flat|nested] only message in thread

only message in thread, other threads:[~2026-11-07  6:37 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-11-07  6:37 [PATCH] rtc: atcrtc100: drain the alarm work before the RTC device is freed hyunjungg

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox

all inboxes | Powered by JetHome®