Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

watchdog: set cdev owner before adding

When the new watchdog character device is registered, it becomes
available for opening. This creates a race where userspace may open the
device before the character device's owner is set. This results in an
imbalance in module_get calls as the cdev_get in cdev_open will not
increment the reference count on the watchdog driver module.

This causes problems when the watchdog character device is released as
the module loader's reference will also be released. This makes it
impossible to open the watchdog device later on as it now appears that
the module is being unloaded. The open will fail with -ENXIO from
chrdev_open.

The legacy watchdog device will fail with -EBUSY from the try_module_get
in watchdog_open because it's module owner is the watchdog core module
so it can still be opened but it will fail to get a refcount on the
underlying watchdog device driver.

Fixes: 72139dfa2464 ("watchdog: Fix the race between the release of watchdog_core_data and cdev")
Signed-off-by: Curtis Klein <curtis.klein@hpe.com>
Reviewed-by: Guenter Roeck <linux@roeck-us.net>
Link: https://lore.kernel.org/r/20231205190522.55153-1-curtis.klein@hpe.com
Signed-off-by: Guenter Roeck <linux@roeck-us.net>
Signed-off-by: Wim Van Sebroeck <wim@linux-watchdog.org>

authored by

Curtis Klein and committed by
Wim Van Sebroeck
38d75297 b85ea95d

+1 -2
+1 -2
drivers/watchdog/watchdog_dev.c
··· 1073 1073 1074 1074 /* Fill in the data structures */ 1075 1075 cdev_init(&wd_data->cdev, &watchdog_fops); 1076 + wd_data->cdev.owner = wdd->ops->owner; 1076 1077 1077 1078 /* Add the device */ 1078 1079 err = cdev_device_add(&wd_data->cdev, &wd_data->dev); ··· 1087 1086 put_device(&wd_data->dev); 1088 1087 return err; 1089 1088 } 1090 - 1091 - wd_data->cdev.owner = wdd->ops->owner; 1092 1089 1093 1090 /* Record time of most recent heartbeat as 'just before now'. */ 1094 1091 wd_data->last_hw_keepalive = ktime_sub(ktime_get(), 1);