]> git.ipfire.org Git - thirdparty/elfutils.git/commitdiff
libdw: Fix possibly unbounded stack usage in __libdw_intern_expression.
authorMark Wielaard <mjw@redhat.com>
Tue, 19 May 2015 09:52:58 +0000 (11:52 +0200)
committerMark Wielaard <mjw@redhat.com>
Wed, 27 May 2015 21:04:31 +0000 (23:04 +0200)
Create a stack allocated array to hold locs. Allocate locs bigger than
the array with malloc and free them when done.

Signed-off-by: Mark Wielaard <mjw@redhat.com>
libdw/ChangeLog
libdw/dwarf_getlocation.c

index f8eca492c6fad1a6894fa0ed3be82a7f570d57ae..b833ab2f6e8450038cf332124b19400d489dc3dd 100644 (file)
@@ -1,3 +1,9 @@
+2015-05-19  Mark Wielaard <mjw@redhat.com>
+
+       * dwarf_getlocation.c (__libdw_intern_expression): Create a stack
+       allocated array to hold locs. Allocate locs bigger than the array
+       with malloc and free them when done.
+
 2015-05-11  Jonathan Lebon  <jlebon@redhat.com>
 
        * libdwP.h (DWARF_E_COMPRESSED_ERROR): New enumerator.
index a3a5bd43655035cca8e830768b1d71f05c53d074..f1dda683d036e8cfd1371f9413422d005483d994 100644 (file)
@@ -239,18 +239,28 @@ __libdw_intern_expression (Dwarf *dbg, bool other_byte_order,
   struct loclist *loclist = NULL;
   unsigned int n = 0;
 
+  /* Stack allocate at most this many locs.  */
+#define MAX_STACK_LOCS 256
+  struct loclist stack_locs[MAX_STACK_LOCS];
+#define NEW_LOC() ({ struct loclist *ll;                       \
+                    ll = (likely (n < MAX_STACK_LOCS)          \
+                          ? &stack_locs[n]                     \
+                          : malloc (sizeof (struct loclist))); \
+                    if (unlikely (ll == NULL))                 \
+                      goto nomem;                              \
+                    n++;                                       \
+                    ll->next = loclist;                        \
+                    loclist = ll;                              \
+                    ll; })
+
   if (cfap)
     {
       /* Synthesize the operation to push the CFA before the expression.  */
-      struct loclist *newloc;
-      newloc = (struct loclist *) alloca (sizeof (struct loclist));
+      struct loclist *newloc = NEW_LOC ();
       newloc->atom = DW_OP_call_frame_cfa;
       newloc->number = 0;
       newloc->number2 = 0;
       newloc->offset = -1;
-      newloc->next = loclist;
-      loclist = newloc;
-      ++n;
     }
 
   /* Decode the opcodes.  It is possible in some situations to have a
@@ -258,13 +268,10 @@ __libdw_intern_expression (Dwarf *dbg, bool other_byte_order,
   while (data < end_data)
     {
       struct loclist *newloc;
-      newloc = (struct loclist *) alloca (sizeof (struct loclist));
+      newloc = NEW_LOC ();
       newloc->number = 0;
       newloc->number2 = 0;
       newloc->offset = data - block->data;
-      newloc->next = loclist;
-      loclist = newloc;
-      ++n;
 
       switch ((newloc->atom = *data++))
        {
@@ -348,6 +355,15 @@ __libdw_intern_expression (Dwarf *dbg, bool other_byte_order,
            {
            invalid:
              __libdw_seterrno (DWARF_E_INVALID_DWARF);
+           returnmem:
+             /* Free any dynamicly allocated loclists, if any.  */
+             while (n > MAX_STACK_LOCS)
+               {
+                 struct loclist *loc = loclist;
+                 loclist = loc->next;
+                 free (loc);
+                 n--;
+               }
              return -1;
            }
 
@@ -503,15 +519,11 @@ __libdw_intern_expression (Dwarf *dbg, bool other_byte_order,
 
   if (valuep)
     {
-      struct loclist *newloc;
-      newloc = (struct loclist *) alloca (sizeof (struct loclist));
+      struct loclist *newloc = NEW_LOC ();
       newloc->atom = DW_OP_stack_value;
       newloc->number = 0;
       newloc->number2 = 0;
       newloc->offset = data - block->data;
-      newloc->next = loclist;
-      loclist = newloc;
-      ++n;
     }
 
   /* Allocate the array.  */
@@ -525,7 +537,7 @@ __libdw_intern_expression (Dwarf *dbg, bool other_byte_order,
        {
        nomem:
          __libdw_seterrno (DWARF_E_NOMEM);
-         return -1;
+         goto returnmem;
        }
     }
 
@@ -545,7 +557,10 @@ __libdw_intern_expression (Dwarf *dbg, bool other_byte_order,
       if (result[n].atom == DW_OP_implicit_value)
        store_implicit_value (dbg, cache, &result[n]);
 
+      struct loclist *loc = loclist;
       loclist = loclist->next;
+      if (unlikely (n + 1 > MAX_STACK_LOCS))
+       free (loc);
     }
   while (n > 0);