[PATCH v2 1/2] watchdog: pika_wdt: fix timer leak and close race
From: Rosen Penev
Date: Wed Jun 03 2026 - 00:04:14 EST
Two timer lifecycle bugs in the PIKA watchdog driver:
1. pikawdt_exit() unmaps the FPGA IO memory without stopping the ping
timer. A timer tick after iounmap executes pikawdt_ping() on freed
memory. Add timer_delete_sync() before iounmap.
2. pikawdt_release() uses timer_delete() which does not synchronize with
a concurrently executing timer handler. If pikawdt_ping() runs on
another CPU after timer_delete() marks the timer as deleted but before
the open bit is cleared, it can call mod_timer() and re-arm itself.
Once the open bit is subsequently cleared, the condition
(!nowayout && !open) becomes true and the timer keeps patting the
watchdog forever, defeating the intended reset-on-unexpected-close.
Fix by clearing the open bit before calling timer_delete_sync(), which
waits for any in-flight handler to complete.
Assisted-by: opencode:big-pickle
Signed-off-by: Rosen Penev <rosenp@xxxxxxxxx>
---
drivers/watchdog/pika_wdt.c | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)
diff --git a/drivers/watchdog/pika_wdt.c b/drivers/watchdog/pika_wdt.c
index 87b8988d2520..60a846cb3601 100644
--- a/drivers/watchdog/pika_wdt.c
+++ b/drivers/watchdog/pika_wdt.c
@@ -127,11 +127,12 @@ static int pikawdt_open(struct inode *inode, struct file *file)
*/
static int pikawdt_release(struct inode *inode, struct file *file)
{
+ clear_bit(0, &pikawdt_private.open);
+
/* stop internal ping */
if (!pikawdt_private.expect_close)
- timer_delete(&pikawdt_private.timer);
+ timer_delete_sync(&pikawdt_private.timer);
- clear_bit(0, &pikawdt_private.open);
pikawdt_private.expect_close = 0;
return 0;
}
@@ -291,6 +292,7 @@ static void __exit pikawdt_exit(void)
{
misc_deregister(&pikawdt_miscdev);
+ timer_delete_sync(&pikawdt_private.timer);
iounmap(pikawdt_private.fpga);
}
--
2.54.0