print_debug_macinfo_section and print_debug_macro_section called alloca
for each CU that has a macro attribute, and print_debug_macinfo_section
also allocated an array with one entry per CU. The number of CUs is
bounded only by the size of the input file, so a large .debug_info
exhausts the stack.

Use xmalloc. The macinfo list is freed as it is copied into the array.
The array is freed through its base pointer, because the array pointer
is advanced while parsing. The macro list is freed by free_mac_culist.
Both functions free their allocations on every exit path.

Signed-off-by: Mohammed Mustafa <[email protected]>
---
v2: Don't use the cleanup attribute. Free explicitly on all exit paths.
    Free the original array pointer, not the advanced one. Drop the
    free_ptr move.

 src/readelf.c | 40 ++++++++++++++++++++++++++++++----------
 1 file changed, 30 insertions(+), 10 deletions(-)

diff --git a/src/readelf.c b/src/readelf.c
--- a/src/readelf.c
+++ b/src/readelf.c
@@ -10068,6 +10068,16 @@ struct mac_culist
   struct mac_culist *next;
 };

+static void
+free_mac_culist (struct mac_culist *culist)
+{
+  while (culist != NULL)
+    {
+      struct mac_culist *next = culist->next;
+      free (culist);
+      culist = next;
+    }
+}

 static int
 mac_compare (const void *p1, const void *p2)
@@ -10122,7 +10132,7 @@ print_debug_macinfo_section (Dwfl_Module
*dwflmod __attribute__ ((unused)),
       if (dwarf_formudata (&attr, &macoff) != 0)
        continue;

-      struct mac_culist *newp = (struct mac_culist *) alloca (sizeof (*newp));
+      struct mac_culist *newp = xmalloc (sizeof (*newp));
       newp->die = cudie;
       newp->offset = macoff;
       newp->files = NULL;
@@ -10132,8 +10142,8 @@ print_debug_macinfo_section (Dwfl_Module
*dwflmod __attribute__ ((unused)),
     }

   /* Convert the list into an array for easier consumption.  */
-  struct mac_culist *cus = (struct mac_culist *) alloca ((nculist + 1)
-                                                        * sizeof (*cus));
+  struct mac_culist *cus_base = xmalloc ((nculist + 1) * sizeof (*cus_base));
+  struct mac_culist *cus = cus_base;
   /* Add sentinel.  */
   cus[nculist].offset = data->d_size;
   cus[nculist].files = (Dwarf_Files *) -1l;
@@ -10142,8 +10152,10 @@ print_debug_macinfo_section (Dwfl_Module
*dwflmod __attribute__ ((unused)),
       for (size_t cnt = nculist - 1; culist != NULL; --cnt)
        {
          assert (cnt < nculist);
+         struct mac_culist *next = culist->next;
          cus[cnt] = *culist;
-         culist = culist->next;
+         free (culist);
+         culist = next;
        }

       /* Sort the array according to the offset in the .debug_macinfo
@@ -10172,7 +10184,7 @@ print_debug_macinfo_section (Dwfl_Module
*dwflmod __attribute__ ((unused)),
              printf (_("\
 %*s*** non-terminated string at end of section"),
                      level, "");
-             return;
+             goto out;
            }

          if (opcode == DW_MACINFO_define)
@@ -10199,7 +10211,7 @@ print_debug_macinfo_section (Dwfl_Module
*dwflmod __attribute__ ((unused)),
              printf (_("\
 %*s*** missing DW_MACINFO_start_file argument at end of section"),
                      level, "");
-             return;
+             goto out;
            }
          get_uleb128 (u128_2, readp, readendp);

@@ -10241,6 +10253,9 @@ print_debug_macinfo_section (Dwfl_Module
*dwflmod __attribute__ ((unused)),
          break;
        }
     }
+
+ out:
+  free (cus_base);
 }

@@ -10282,7 +10297,7 @@ print_debug_macro_section (Dwfl_Module
*dwflmod __attribute__ ((unused)),
       if (dwarf_formudata (&attr, &lineoff) != 0)
        continue;

-      struct mac_culist *newp = (struct mac_culist *) alloca (sizeof (*newp));
+      struct mac_culist *newp = xmalloc (sizeof (*newp));
       newp->die = cudie;
       newp->offset = lineoff;
       newp->files = NULL;
@@ -10304,7 +10319,7 @@ print_debug_macro_section (Dwfl_Module
*dwflmod __attribute__ ((unused)),
        {
        invalid_data:
          error (0, 0, _("invalid data"));
-         return;
+         goto out;
        }
       const uint16_t vers = read_2ubyte_unaligned_inc (dbg, readp);
       printf (_(" Version:            %" PRIu16 "\n"), vers);
@@ -10314,7 +10329,7 @@ print_debug_macro_section (Dwfl_Module
*dwflmod __attribute__ ((unused)),
       if (vers != 4 && vers != 5)
        {
          printf (_("  unknown version, cannot parse section\n"));
-         return;
+         goto out;
        }

       if (readp + 1 > readendp)
@@ -10526,6 +10541,9 @@ print_debug_macro_section (Dwfl_Module
*dwflmod __attribute__ ((unused)),
            putchar_unlocked ('\n');
        }
     }
+
+ out:
+  free_mac_culist (culist);
 }

Reply via email to