From: Mark Wielaard Date: Tue, 19 May 2015 09:52:58 +0000 (+0200) Subject: libdw: Fix possibly unbounded stack usage in __libdw_intern_expression. X-Git-Tag: elfutils-0.162~41 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=720f83a563fd3d550cdc7a14be9fb13269022b91;p=thirdparty%2Felfutils.git libdw: Fix possibly unbounded stack usage in __libdw_intern_expression. 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 --- diff --git a/libdw/ChangeLog b/libdw/ChangeLog index f8eca492c..b833ab2f6 100644 --- a/libdw/ChangeLog +++ b/libdw/ChangeLog @@ -1,3 +1,9 @@ +2015-05-19 Mark Wielaard + + * 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 * libdwP.h (DWARF_E_COMPRESSED_ERROR): New enumerator. diff --git a/libdw/dwarf_getlocation.c b/libdw/dwarf_getlocation.c index a3a5bd436..f1dda683d 100644 --- a/libdw/dwarf_getlocation.c +++ b/libdw/dwarf_getlocation.c @@ -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);