]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
ubi: Free the normal volumes in error paths of ubi_attach_mtd_dev()
authorHou Tao <houtao1@huawei.com>
Sat, 30 Nov 2019 09:48:25 +0000 (17:48 +0800)
committerRichard Weinberger <richard@nod.at>
Thu, 16 Jan 2020 22:35:59 +0000 (23:35 +0100)
The allocated normal volumes saved in ubi->volumes are not freed
in the error paths in ubi_attach_mtd_dev() and its callees (e.g.
ubi_attach() and ubi_read_volume_table()).

These normal volumes should be freed through kill_volumes() and
vol_release(), but ubi_attach_mtd_dev() may fail before
calling uif_init(), and there will be memory leaks.

So adding a new helper ubi_free_all_volumes() to free the normal
and the internal volumes. And in order to prevent double-free
of volume, reset ubi->volumes[i] to NULL after freeing.

Signed-off-by: Hou Tao <houtao1@huawei.com>
Signed-off-by: Richard Weinberger <richard@nod.at>
drivers/mtd/ubi/attach.c
drivers/mtd/ubi/build.c
drivers/mtd/ubi/ubi.h
drivers/mtd/ubi/vtbl.c

index 10b2459f8951e7a75eb54fb053872e33b81c8ff2..ea7440ac913b9e3595a90d4ba88bdfd60ee697e0 100644 (file)
@@ -1640,7 +1640,7 @@ int ubi_attach(struct ubi_device *ubi, int force_scan)
 out_wl:
        ubi_wl_close(ubi);
 out_vtbl:
-       ubi_free_internal_volumes(ubi);
+       ubi_free_all_volumes(ubi);
        vfree(ubi->vtbl);
 out_ai:
        destroy_ai(ai);
index d636bbe214cb9943eadcc3d8f47683f96c893440..25fb72b2efa01a93285f30839ee6643024799e51 100644 (file)
@@ -503,21 +503,42 @@ static void uif_close(struct ubi_device *ubi)
 }
 
 /**
- * ubi_free_internal_volumes - free internal volumes.
+ * ubi_free_volumes_from - free volumes from specific index.
  * @ubi: UBI device description object
+ * @from: the start index used for volume free.
  */
-void ubi_free_internal_volumes(struct ubi_device *ubi)
+static void ubi_free_volumes_from(struct ubi_device *ubi, int from)
 {
        int i;
 
-       for (i = ubi->vtbl_slots;
-            i < ubi->vtbl_slots + UBI_INT_VOL_COUNT; i++) {
+       for (i = from; i < ubi->vtbl_slots + UBI_INT_VOL_COUNT; i++) {
+               if (!ubi->volumes[i])
+                       continue;
                ubi_eba_replace_table(ubi->volumes[i], NULL);
                ubi_fastmap_destroy_checkmap(ubi->volumes[i]);
                kfree(ubi->volumes[i]);
+               ubi->volumes[i] = NULL;
        }
 }
 
+/**
+ * ubi_free_all_volumes - free all volumes.
+ * @ubi: UBI device description object
+ */
+void ubi_free_all_volumes(struct ubi_device *ubi)
+{
+       ubi_free_volumes_from(ubi, 0);
+}
+
+/**
+ * ubi_free_internal_volumes - free internal volumes.
+ * @ubi: UBI device description object
+ */
+void ubi_free_internal_volumes(struct ubi_device *ubi)
+{
+       ubi_free_volumes_from(ubi, ubi->vtbl_slots);
+}
+
 static int get_bad_peb_limit(const struct ubi_device *ubi, int max_beb_per1024)
 {
        int limit, device_pebs;
@@ -1013,7 +1034,7 @@ out_uif:
 out_detach:
        ubi_devices[ubi_num] = NULL;
        ubi_wl_close(ubi);
-       ubi_free_internal_volumes(ubi);
+       ubi_free_all_volumes(ubi);
        vfree(ubi->vtbl);
 out_free:
        vfree(ubi->peb_buf);
index 9688b411c930ea6f09da7cd3d6ce43bd3df92bcb..73c67e5c08f85d804852f55a5daa30fa04bfa159 100644 (file)
@@ -950,6 +950,7 @@ int ubi_volume_notify(struct ubi_device *ubi, struct ubi_volume *vol,
 int ubi_notify_all(struct ubi_device *ubi, int ntype,
                   struct notifier_block *nb);
 int ubi_enumerate_volumes(struct notifier_block *nb);
+void ubi_free_all_volumes(struct ubi_device *ubi);
 void ubi_free_internal_volumes(struct ubi_device *ubi);
 
 /* kapi.c */
index 8a2a0f091598cf9d7cacd7049f5fb168e29e843f..f700f0e4f2ec4d7c700a2428fd83e54129992c24 100644 (file)
@@ -782,7 +782,7 @@ static int check_attaching_info(const struct ubi_device *ubi,
  */
 int ubi_read_volume_table(struct ubi_device *ubi, struct ubi_attach_info *ai)
 {
-       int i, err;
+       int err;
        struct ubi_ainf_volume *av;
 
        empty_vtbl_record.crc = cpu_to_be32(0xf116c36b);
@@ -851,13 +851,7 @@ int ubi_read_volume_table(struct ubi_device *ubi, struct ubi_attach_info *ai)
 
 out_free:
        vfree(ubi->vtbl);
-       for (i = 0; i < ubi->vtbl_slots + UBI_INT_VOL_COUNT; i++) {
-               if (!ubi->volumes[i])
-                       continue;
-               ubi_fastmap_destroy_checkmap(ubi->volumes[i]);
-               kfree(ubi->volumes[i]);
-               ubi->volumes[i] = NULL;
-       }
+       ubi_free_all_volumes(ubi);
        return err;
 }