firewire: core: fix possible memory leak in create_units()
authorYang Yingliang <yangyingliang@huawei.com>
Wed, 29 Nov 2023 09:34:08 +0000 (17:34 +0800)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Fri, 8 Dec 2023 07:52:15 +0000 (08:52 +0100)
commit 891e0eab32a57fca4d36c5162628eb0bcb1f0edf upstream.

If device_register() fails, the refcount of device is not 0, the name
allocated in dev_set_name() is leaked. To fix this by calling put_device(),
so that it will be freed in callback function kobject_cleanup().

unreferenced object 0xffff9d99035c7a90 (size 8):
  comm "systemd-udevd", pid 168, jiffies 4294672386 (age 152.089s)
  hex dump (first 8 bytes):
    66 77 30 2e 30 00 ff ff                          fw0.0...
  backtrace:
    [<00000000e1d62bac>] __kmem_cache_alloc_node+0x1e9/0x360
    [<00000000bbeaff31>] __kmalloc_node_track_caller+0x44/0x1a0
    [<00000000491f2fb4>] kvasprintf+0x67/0xd0
    [<000000005b960ddc>] kobject_set_name_vargs+0x1e/0x90
    [<00000000427ac591>] dev_set_name+0x4e/0x70
    [<000000003b4e447d>] create_units+0xc5/0x110

fw_unit_release() will be called in the error path, move fw_device_get()
before calling device_register() to keep balanced with fw_device_put() in
fw_unit_release().

Cc: stable@vger.kernel.org
Fixes: 1fa5ae857bb1 ("driver core: get rid of struct device's bus_id string array")
Fixes: a1f64819fe9f ("firewire: struct device - replace bus_id with dev_name(), dev_set_name()")
Signed-off-by: Yang Yingliang <yangyingliang@huawei.com>
Signed-off-by: Takashi Sakamoto <o-takashi@sakamocchi.jp>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
drivers/firewire/core-device.c

index aa597cda0d88741334c68bf1f9f23fcf8e43c292..2828e9573e90be5bbf74941df10681bbc6c09fbf 100644 (file)
@@ -717,14 +717,11 @@ static void create_units(struct fw_device *device)
                                        fw_unit_attributes,
                                        &unit->attribute_group);
 
-               if (device_register(&unit->device) < 0)
-                       goto skip_unit;
-
                fw_device_get(device);
-               continue;
-
-       skip_unit:
-               kfree(unit);
+               if (device_register(&unit->device) < 0) {
+                       put_device(&unit->device);
+                       continue;
+               }
        }
 }