Fix memory leaks in make_vg() with new helper functions, free_pv()
and free_lv(). Additionally, correct a check after allocating
comp->segments->nodes that mistakenly checked lv->segments->nodes
instead, likely due to a copy-paste error.

Fixes: CID 473878
Fixes: CID 473884
Fixes: CID 473889
Fixes: CID 473890

Signed-off-by: Lidong Chen <lidong.c...@oracle.com>
---
 grub-core/disk/ldm.c | 180 +++++++++++++++++++------------------------
 1 file changed, 80 insertions(+), 100 deletions(-)

diff --git a/grub-core/disk/ldm.c b/grub-core/disk/ldm.c
index 048e29cd0..0f4f22aaa 100644
--- a/grub-core/disk/ldm.c
+++ b/grub-core/disk/ldm.c
@@ -179,6 +179,36 @@ gpt_ldm_sector (grub_disk_t dsk)
   return sector;
 }
 
+static void
+free_pv (struct grub_diskfilter_pv *pv)
+{
+  if (pv == NULL)
+    return;
+
+  grub_free (pv->internal_id);
+  grub_free (pv->id.uuid);
+  grub_free (pv);
+}
+
+static void
+free_lv (struct grub_diskfilter_lv *lv)
+{
+  if (lv == NULL)
+    return;
+
+  grub_free (lv->internal_id);
+  grub_free (lv->name);
+  grub_free (lv->fullname);
+  if (lv->segments)
+    {
+      unsigned int i;
+      for (i = 0; i < lv->segment_count; i++)
+       grub_free (lv->segments[i].nodes);
+      grub_free (lv->segments);
+    }
+  grub_free (lv);
+}
+
 static struct grub_diskfilter_vg *
 make_vg (grub_disk_t disk,
         const struct grub_ldm_label *label)
@@ -196,12 +226,8 @@ make_vg (grub_disk_t disk,
   vg->name = grub_malloc (LDM_NAME_STRLEN + 1);
   vg->uuid = grub_malloc (LDM_GUID_STRLEN + 1);
   if (! vg->uuid || !vg->name)
-    {
-      grub_free (vg->uuid);
-      grub_free (vg->name);
-      grub_free (vg);
-      return NULL;
-    }
+    goto fail1;
+
   grub_memcpy (vg->uuid, label->group_guid, LDM_GUID_STRLEN);
   grub_memcpy (vg->name, label->group_name, LDM_NAME_STRLEN);
   vg->name[LDM_NAME_STRLEN] = 0;
@@ -261,7 +287,7 @@ make_vg (grub_disk_t disk,
          pv->internal_id = grub_malloc (sz);
          if (!pv->internal_id)
            {
-             grub_free (pv);
+             free_pv (pv);
              goto fail2;
            }
          grub_memcpy (pv->internal_id, ptr, (grub_size_t) ptr[0] + 1);
@@ -271,7 +297,7 @@ make_vg (grub_disk_t disk,
          if (ptr + *ptr + 1 >= vblk[i].dynamic
              + sizeof (vblk[i].dynamic))
            {
-             grub_free (pv);
+             free_pv (pv);
              goto fail2;
            }
          /* ptr = name.  */
@@ -279,23 +305,21 @@ make_vg (grub_disk_t disk,
          if (ptr + *ptr + 1
              >= vblk[i].dynamic + sizeof (vblk[i].dynamic))
            {
-             grub_free (pv);
+             free_pv (pv);
              goto fail2;
            }
          pv->id.uuidlen = *ptr;
 
          if (grub_add (pv->id.uuidlen, 1, &sz))
            {
-             grub_free (pv->internal_id);
-             grub_free (pv);
+             free_pv (pv);
              goto fail2;
            }
 
          pv->id.uuid = grub_malloc (sz);
          if (pv->id.uuid == NULL)
            {
-             grub_free (pv->internal_id);
-             grub_free (pv);
+             free_pv (pv);
              goto fail2;
            }
          grub_memcpy (pv->id.uuid, ptr + 1, pv->id.uuidlen);
@@ -343,7 +367,7 @@ make_vg (grub_disk_t disk,
          lv->segments = grub_zalloc (sizeof (*lv->segments));
          if (!lv->segments)
            {
-             grub_free (lv);
+             free_lv (lv);
              goto fail2;
            }
          lv->segments->start_extent = 0;
@@ -354,26 +378,25 @@ make_vg (grub_disk_t disk,
                                             sizeof (*lv->segments->nodes));
          if (!lv->segments->nodes)
            {
-             grub_free (lv);
+             free_lv (lv);
              goto fail2;
            }
          ptr = vblk[i].dynamic;
          if (ptr + *ptr + 1 >= vblk[i].dynamic
              + sizeof (vblk[i].dynamic))
            {
-             grub_free (lv);
+             free_lv (lv);
              goto fail2;
            }
          if (grub_add (ptr[0], 2, &sz))
            {
-             grub_free (lv->segments);
-             grub_free (lv);
+             free_lv (lv);
              goto fail2;
            }
          lv->internal_id = grub_malloc (sz);
          if (!lv->internal_id)
            {
-             grub_free (lv);
+             free_lv (lv);
              goto fail2;
            }
          grub_memcpy (lv->internal_id, ptr, ptr[0] + 1);
@@ -383,20 +406,18 @@ make_vg (grub_disk_t disk,
          if (ptr + *ptr + 1 >= vblk[i].dynamic
              + sizeof (vblk[i].dynamic))
            {
-             grub_free (lv);
+             free_lv (lv);
              goto fail2;
            }
          if (grub_add (*ptr, 1, &sz))
            {
-             grub_free (lv->internal_id);
-             grub_free (lv);
+             free_lv (lv);
              goto fail2;
            }
          lv->name = grub_malloc (sz);
          if (!lv->name)
            {
-             grub_free (lv->internal_id);
-             grub_free (lv);
+             free_lv (lv);
              goto fail2;
            }
          grub_memcpy (lv->name, ptr + 1, *ptr);
@@ -405,36 +426,28 @@ make_vg (grub_disk_t disk,
                                         vg->uuid, lv->name);
          if (!lv->fullname)
            {
-             grub_free (lv->internal_id);
-             grub_free (lv->name);
-             grub_free (lv);
+             free_lv (lv);
              goto fail2;
            }
          ptr += *ptr + 1;
          if (ptr + *ptr + 1
              >= vblk[i].dynamic + sizeof (vblk[i].dynamic))
            {
-             grub_free (lv->internal_id);
-             grub_free (lv->name);
-             grub_free (lv);
+             free_lv (lv);
              goto fail2;
            }
          /* ptr = volume type.  */
          ptr += *ptr + 1;
          if (ptr >= vblk[i].dynamic + sizeof (vblk[i].dynamic))
            {
-             grub_free (lv->internal_id);
-             grub_free (lv->name);
-             grub_free (lv);
+             free_lv (lv);
              goto fail2;
            }
          /* ptr = flags.  */
          ptr += *ptr + 1;
          if (ptr >= vblk[i].dynamic + sizeof (vblk[i].dynamic))
            {
-             grub_free (lv->internal_id);
-             grub_free (lv->name);
-             grub_free (lv);
+             free_lv (lv);
              goto fail2;
            }
 
@@ -443,17 +456,13 @@ make_vg (grub_disk_t disk,
          /* ptr = number of children.  */
          if (ptr >= vblk[i].dynamic + sizeof (vblk[i].dynamic))
            {
-             grub_free (lv->internal_id);
-             grub_free (lv->name);
-             grub_free (lv);
+             free_lv (lv);
              goto fail2;
            }
          ptr += *ptr + 1;
          if (ptr >= vblk[i].dynamic + sizeof (vblk[i].dynamic))
            {
-             grub_free (lv->internal_id);
-             grub_free (lv->name);
-             grub_free (lv);
+             free_lv (lv);
              goto fail2;
            }
 
@@ -463,9 +472,7 @@ make_vg (grub_disk_t disk,
              || ptr + *ptr + 1>= vblk[i].dynamic
              + sizeof (vblk[i].dynamic))
            {
-             grub_free (lv->internal_id);
-             grub_free (lv->name);
-             grub_free (lv);
+             free_lv (lv);
              goto fail2;
            }
          lv->size = read_int (ptr + 1, *ptr);
@@ -515,18 +522,18 @@ make_vg (grub_disk_t disk,
          ptr = vblk[i].dynamic;
          if (ptr + *ptr + 1 >= vblk[i].dynamic + sizeof (vblk[i].dynamic))
            {
-             grub_free (comp);
+             free_lv (comp);
              goto fail2;
            }
          if (grub_add (ptr[0], 2, &sz))
            {
-             grub_free (comp);
+             free_lv (comp);
              goto fail2;
            }
          comp->internal_id = grub_malloc (sz);
          if (!comp->internal_id)
            {
-             grub_free (comp);
+             free_lv (comp);
              goto fail2;
            }
          grub_memcpy (comp->internal_id, ptr, ptr[0] + 1);
@@ -535,16 +542,14 @@ make_vg (grub_disk_t disk,
          ptr += *ptr + 1;
          if (ptr + *ptr + 1 >= vblk[i].dynamic + sizeof (vblk[i].dynamic))
            {
-             grub_free (comp->internal_id);
-             grub_free (comp);
+             free_lv (comp);
              goto fail2;
            }
          /* ptr = name.  */
          ptr += *ptr + 1;
          if (ptr + *ptr + 1 >= vblk[i].dynamic + sizeof (vblk[i].dynamic))
            {
-             grub_free (comp->internal_id);
-             grub_free (comp);
+             free_lv (comp);
              goto fail2;
            }
          /* ptr = state.  */
@@ -554,8 +559,7 @@ make_vg (grub_disk_t disk,
          ptr += 4;
          if (ptr >= vblk[i].dynamic + sizeof (vblk[i].dynamic))
            {
-             grub_free (comp->internal_id);
-             grub_free (comp);
+             free_lv (comp);
              goto fail2;
            }
 
@@ -563,16 +567,14 @@ make_vg (grub_disk_t disk,
          ptr += *ptr + 1;
          if (ptr >= vblk[i].dynamic + sizeof (vblk[i].dynamic))
            {
-             grub_free (comp->internal_id);
-             grub_free (comp);
+             free_lv (comp);
              goto fail2;
            }
          ptr += 8 + 8;
          if (ptr + *ptr + 1 >= vblk[i].dynamic
              + sizeof (vblk[i].dynamic))
            {
-             grub_free (comp->internal_id);
-             grub_free (comp);
+             free_lv (comp);
              goto fail2;
            }
          for (lv = vg->lvs; lv; lv = lv->next)
@@ -583,8 +585,7 @@ make_vg (grub_disk_t disk,
            }
          if (!lv)
            {
-             grub_free (comp->internal_id);
-             grub_free (comp);
+             free_lv (comp);
              continue;
            }
          comp->size = lv->size;
@@ -596,8 +597,7 @@ make_vg (grub_disk_t disk,
                                            sizeof (*comp->segments));
              if (!comp->segments)
                {
-                 grub_free (comp->internal_id);
-                 grub_free (comp);
+                 free_lv (comp);
                  goto fail2;
                }
            }
@@ -608,8 +608,7 @@ make_vg (grub_disk_t disk,
              comp->segments = grub_malloc (sizeof (*comp->segments));
              if (!comp->segments)
                {
-                 grub_free (comp->internal_id);
-                 grub_free (comp);
+                 free_lv (comp);
                  goto fail2;
                }
              comp->segments->start_extent = 0;
@@ -624,27 +623,21 @@ make_vg (grub_disk_t disk,
                }
              else
                {
-                 grub_free (comp->segments);
-                 grub_free (comp->internal_id);
-                 grub_free (comp);
+                 free_lv (comp);
                  goto fail2;
                }
              ptr += *ptr + 1;
              ptr++;
              if (!(vblk[i].flags & 0x10))
                {
-                 grub_free (comp->segments);
-                 grub_free (comp->internal_id);
-                 grub_free (comp);
+                 free_lv (comp);
                  goto fail2;
                }
              if (ptr >= vblk[i].dynamic + sizeof (vblk[i].dynamic)
                  || ptr + *ptr + 1 >= vblk[i].dynamic
                  + sizeof (vblk[i].dynamic))
                {
-                 grub_free (comp->segments);
-                 grub_free (comp->internal_id);
-                 grub_free (comp);
+                 free_lv (comp);
                  goto fail2;
                }
              comp->segments->stripe_size = read_int (ptr + 1, *ptr);
@@ -652,20 +645,16 @@ make_vg (grub_disk_t disk,
              if (ptr + *ptr + 1 >= vblk[i].dynamic
                  + sizeof (vblk[i].dynamic))
                {
-                 grub_free (comp->segments);
-                 grub_free (comp->internal_id);
-                 grub_free (comp);
+                 free_lv (comp);
                  goto fail2;
                }
              comp->segments->node_count = read_int (ptr + 1, *ptr);
              comp->segments->node_alloc = comp->segments->node_count;
              comp->segments->nodes = grub_calloc (comp->segments->node_alloc,
                                                   sizeof 
(*comp->segments->nodes));
-             if (!lv->segments->nodes)
+             if (comp->segments->nodes == NULL)
                {
-                 grub_free (comp->segments);
-                 grub_free (comp->internal_id);
-                 grub_free (comp);
+                 free_lv (comp);
                  goto fail2;
                }
            }
@@ -677,20 +666,14 @@ make_vg (grub_disk_t disk,
              if (grub_mul (lv->segments->node_alloc, 2, 
&lv->segments->node_alloc) ||
                  grub_mul (lv->segments->node_alloc, sizeof 
(*lv->segments->nodes), &sz))
                {
-                 grub_free (comp->segments->nodes);
-                 grub_free (comp->segments);
-                 grub_free (comp->internal_id);
-                 grub_free (comp);
+                 free_lv (comp);
                  goto fail2;
                }
 
              t = grub_realloc (lv->segments->nodes, sz);
              if (!t)
                {
-                 grub_free (comp->segments->nodes);
-                 grub_free (comp->segments);
-                 grub_free (comp->internal_id);
-                 grub_free (comp);
+                 free_lv (comp);
                  goto fail2;
                }
              lv->segments->nodes = t;
@@ -830,7 +813,10 @@ make_vg (grub_disk_t disk,
              comp->segments[comp->segment_count].nodes
                = grub_malloc (sizeof 
(*comp->segments[comp->segment_count].nodes));
              if (!comp->segments[comp->segment_count].nodes)
-               goto fail2;
+               {
+                 grub_free (comp->segments);
+                 goto fail2;
+               }
              comp->segments[comp->segment_count].nodes[0] = part;
              comp->segment_count++;
            }
@@ -845,25 +831,19 @@ make_vg (grub_disk_t disk,
     struct grub_diskfilter_pv *pv, *next_pv;
     for (lv = vg->lvs; lv; lv = next_lv)
       {
-       unsigned i;
-       for (i = 0; i < lv->segment_count; i++)
-         grub_free (lv->segments[i].nodes);
-
        next_lv = lv->next;
-       grub_free (lv->segments);
-       grub_free (lv->internal_id);
-       grub_free (lv->name);
-       grub_free (lv->fullname);
-       grub_free (lv);
+       free_lv (lv);
+
       }
     for (pv = vg->pvs; pv; pv = next_pv)
       {
        next_pv = pv->next;
-       grub_free (pv->id.uuid);
-       grub_free (pv);
+       free_pv (pv);
       }
   }
+ fail1:
   grub_free (vg->uuid);
+  grub_free (vg->name);
   grub_free (vg);
   return NULL;
 }
-- 
2.34.1


_______________________________________________
Grub-devel mailing list
Grub-devel@gnu.org
https://lists.gnu.org/mailman/listinfo/grub-devel

Reply via email to