device: fix segfault when recreating devices
authorFelix Fietkau <nbd@nbd.name>
Mon, 17 Apr 2023 11:11:53 +0000 (13:11 +0200)
committerFelix Fietkau <nbd@nbd.name>
Mon, 17 Apr 2023 11:13:25 +0000 (13:13 +0200)
Depending on the configuration, the callback on device_release could end up
deleting the device_dep from the list. If that happens, it must not be added
back to the recreated device, since that leads to use-after-free issues.
Check dep->dev before adding it back.

Signed-off-by: Felix Fietkau <nbd@nbd.name>
device.c

index d6610c704b87674aaa43d2abc71971179e8a3996..1e892191d0ec95203b65b601e16be25a2e5762d3 100644 (file)
--- a/device.c
+++ b/device.c
@@ -1037,14 +1037,18 @@ device_apply_config(struct device *dev, struct device_type *type,
 static void
 device_replace(struct device *dev, struct device *odev)
 {
-       struct device_user *dep, *tmp;
+       struct device_user *dep;
 
        __devlock++;
        if (odev->present)
                device_set_present(odev, false);
 
-       list_for_each_entry_safe(dep, tmp, &odev->users.list, list.list) {
+       while (!list_empty(&odev->users.list)) {
+               dep = list_first_entry(&odev->users.list, struct device_user, list.list);
                device_release(dep);
+               if (!dep->dev)
+                       continue;
+
                safe_list_del(&dep->list);
                __device_add_user(dep, dev);
        }