diff mbox series

watchdog: Fix kmemleak in watchdog_cdev_register

Message ID 20221116012714.102066-1-chenjun102@huawei.com
State New
Headers show
Series watchdog: Fix kmemleak in watchdog_cdev_register | expand

Commit Message

Chen Jun Nov. 16, 2022, 1:27 a.m. UTC
kmemleak reports memory leaks in watchdog_dev_register, as follows:
unreferenced object 0xffff888116233000 (size 2048):
  comm ""modprobe"", pid 28147, jiffies 4353426116 (age 61.741s)
  hex dump (first 32 bytes):
    80 fa b9 05 81 88 ff ff 08 30 23 16 81 88 ff ff  .........0#.....
    08 30 23 16 81 88 ff ff 00 00 00 00 00 00 00 00  .0#.............
  backtrace:
    [<000000007f001ffd>] __kmem_cache_alloc_node+0x157/0x220
    [<000000006a389304>] kmalloc_trace+0x21/0x110
    [<000000008d640eea>] watchdog_dev_register+0x4e/0x780 [watchdog]
    [<0000000053c9f248>] __watchdog_register_device+0x4f0/0x680 [watchdog]
    [<00000000b2979824>] watchdog_register_device+0xd2/0x110 [watchdog]
    [<000000001f730178>] 0xffffffffc10880ae
    [<000000007a1a8bcc>] do_one_initcall+0xcb/0x4d0
    [<00000000b98be325>] do_init_module+0x1ca/0x5f0
    [<0000000046d08e7c>] load_module+0x6133/0x70f0
    ...

unreferenced object 0xffff888105b9fa80 (size 16):
  comm ""modprobe"", pid 28147, jiffies 4353426116 (age 61.741s)
  hex dump (first 16 bytes):
    77 61 74 63 68 64 6f 67 31 00 b9 05 81 88 ff ff  watchdog1.......
  backtrace:
    [<000000007f001ffd>] __kmem_cache_alloc_node+0x157/0x220
    [<00000000486ab89b>] __kmalloc_node_track_caller+0x44/0x1b0
    [<000000005a39aab0>] kvasprintf+0xb5/0x140
    [<0000000024806f85>] kvasprintf_const+0x55/0x180
    [<000000009276cb7f>] kobject_set_name_vargs+0x56/0x150
    [<00000000a92e820b>] dev_set_name+0xab/0xe0
    [<00000000cec812c6>] watchdog_dev_register+0x285/0x780 [watchdog]
    [<0000000053c9f248>] __watchdog_register_device+0x4f0/0x680 [watchdog]
    [<00000000b2979824>] watchdog_register_device+0xd2/0x110 [watchdog]
    [<000000001f730178>] 0xffffffffc10880ae
    [<000000007a1a8bcc>] do_one_initcall+0xcb/0x4d0
    [<00000000b98be325>] do_init_module+0x1ca/0x5f0
    [<0000000046d08e7c>] load_module+0x6133/0x70f0
    ...

The reason is that put_device is not be called if cdev_device_add fails
and wdd->id != 0.

watchdog_cdev_register
  wd_data = kzalloc                             [1]
  err = dev_set_name                            [2]
  ..
  err = cdev_device_add
  if (err) {
    if (wdd->id == 0) {  // wdd->id != 0
      ..
    }
    return err;  // [1],[2] would be leaked

To fix it, call put_device in all wdd->id cases.

Fixes: 72139dfa2464 ("watchdog: Fix the race between the release of watchdog_core_data and cdev")
Signed-off-by: Chen Jun <chenjun102@huawei.com>
---
 drivers/watchdog/watchdog_dev.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

Comments

Guenter Roeck Nov. 16, 2022, 1:52 p.m. UTC | #1
On Wed, Nov 16, 2022 at 01:27:14AM +0000, Chen Jun wrote:
> kmemleak reports memory leaks in watchdog_dev_register, as follows:
> unreferenced object 0xffff888116233000 (size 2048):
>   comm ""modprobe"", pid 28147, jiffies 4353426116 (age 61.741s)
>   hex dump (first 32 bytes):
>     80 fa b9 05 81 88 ff ff 08 30 23 16 81 88 ff ff  .........0#.....
>     08 30 23 16 81 88 ff ff 00 00 00 00 00 00 00 00  .0#.............
>   backtrace:
>     [<000000007f001ffd>] __kmem_cache_alloc_node+0x157/0x220
>     [<000000006a389304>] kmalloc_trace+0x21/0x110
>     [<000000008d640eea>] watchdog_dev_register+0x4e/0x780 [watchdog]
>     [<0000000053c9f248>] __watchdog_register_device+0x4f0/0x680 [watchdog]
>     [<00000000b2979824>] watchdog_register_device+0xd2/0x110 [watchdog]
>     [<000000001f730178>] 0xffffffffc10880ae
>     [<000000007a1a8bcc>] do_one_initcall+0xcb/0x4d0
>     [<00000000b98be325>] do_init_module+0x1ca/0x5f0
>     [<0000000046d08e7c>] load_module+0x6133/0x70f0
>     ...
> 
> unreferenced object 0xffff888105b9fa80 (size 16):
>   comm ""modprobe"", pid 28147, jiffies 4353426116 (age 61.741s)
>   hex dump (first 16 bytes):
>     77 61 74 63 68 64 6f 67 31 00 b9 05 81 88 ff ff  watchdog1.......
>   backtrace:
>     [<000000007f001ffd>] __kmem_cache_alloc_node+0x157/0x220
>     [<00000000486ab89b>] __kmalloc_node_track_caller+0x44/0x1b0
>     [<000000005a39aab0>] kvasprintf+0xb5/0x140
>     [<0000000024806f85>] kvasprintf_const+0x55/0x180
>     [<000000009276cb7f>] kobject_set_name_vargs+0x56/0x150
>     [<00000000a92e820b>] dev_set_name+0xab/0xe0
>     [<00000000cec812c6>] watchdog_dev_register+0x285/0x780 [watchdog]
>     [<0000000053c9f248>] __watchdog_register_device+0x4f0/0x680 [watchdog]
>     [<00000000b2979824>] watchdog_register_device+0xd2/0x110 [watchdog]
>     [<000000001f730178>] 0xffffffffc10880ae
>     [<000000007a1a8bcc>] do_one_initcall+0xcb/0x4d0
>     [<00000000b98be325>] do_init_module+0x1ca/0x5f0
>     [<0000000046d08e7c>] load_module+0x6133/0x70f0
>     ...
> 
> The reason is that put_device is not be called if cdev_device_add fails
> and wdd->id != 0.
> 
> watchdog_cdev_register
>   wd_data = kzalloc                             [1]
>   err = dev_set_name                            [2]
>   ..
>   err = cdev_device_add
>   if (err) {
>     if (wdd->id == 0) {  // wdd->id != 0
>       ..
>     }
>     return err;  // [1],[2] would be leaked
> 
> To fix it, call put_device in all wdd->id cases.
> 
> Fixes: 72139dfa2464 ("watchdog: Fix the race between the release of watchdog_core_data and cdev")
> Signed-off-by: Chen Jun <chenjun102@huawei.com>

Reviewed-by: Guenter Roeck <linux@roeck-us.net>

> ---
>  drivers/watchdog/watchdog_dev.c | 2 +-
>  1 file changed, 1 insertion(+), 1 deletion(-)
> 
> diff --git a/drivers/watchdog/watchdog_dev.c b/drivers/watchdog/watchdog_dev.c
> index 55574ed42504..fdffa6859dde 100644
> --- a/drivers/watchdog/watchdog_dev.c
> +++ b/drivers/watchdog/watchdog_dev.c
> @@ -1061,8 +1061,8 @@ static int watchdog_cdev_register(struct watchdog_device *wdd)
>  		if (wdd->id == 0) {
>  			misc_deregister(&watchdog_miscdev);
>  			old_wd_data = NULL;
> -			put_device(&wd_data->dev);
>  		}
> +		put_device(&wd_data->dev);
>  		return err;
>  	}
>  
> -- 
> 2.17.1
>
diff mbox series

Patch

diff --git a/drivers/watchdog/watchdog_dev.c b/drivers/watchdog/watchdog_dev.c
index 55574ed42504..fdffa6859dde 100644
--- a/drivers/watchdog/watchdog_dev.c
+++ b/drivers/watchdog/watchdog_dev.c
@@ -1061,8 +1061,8 @@  static int watchdog_cdev_register(struct watchdog_device *wdd)
 		if (wdd->id == 0) {
 			misc_deregister(&watchdog_miscdev);
 			old_wd_data = NULL;
-			put_device(&wd_data->dev);
 		}
+		put_device(&wd_data->dev);
 		return err;
 	}