diff options
author | Mark Wielaard <mjw@redhat.com> | 2015-01-03 00:09:45 +0100 |
---|---|---|
committer | Mark Wielaard <mjw@redhat.com> | 2015-01-15 14:11:37 +0100 |
commit | 5316e412a4931d99ac5611e5f89ef187d4e9e335 (patch) | |
tree | f73de6527f8f4a736e17c2cc69cfec11c2accf88 /libdw/dwarf_getlocation.c | |
parent | cc62e378c292daaded19f1fe03681d63b7437ea0 (diff) | |
download | elfutils-5316e412a4931d99ac5611e5f89ef187d4e9e335.tar.gz |
libdw: Handle NULL dbg for call_ref, GNU_implicit_pointer and addr DW_OPs.
afl-fuzz pointed out that __libdw_intern_expression didn't handle CFI
containing DW_OP_call_ref, DW_OP_implicit_pointer or DW_OP_addr. Because
in that case the Dwarf dbg is NULL. Both DW_OP_call_ref and
DW_OP_implicit_pointer cannot be used in CFI. That is just an error.
But DW_OP_addr can be. Without a Dwarf dbg we'll need to read the address
argument directly. Don't use __libdw_read_address_inc which might do a
relocation of the value read. But in practice the relocation hook isn't
implemented anyway.
Signed-off-by: Mark Wielaard <mjw@redhat.com>
Diffstat (limited to 'libdw/dwarf_getlocation.c')
-rw-r--r-- | libdw/dwarf_getlocation.c | 42 |
1 files changed, 32 insertions, 10 deletions
diff --git a/libdw/dwarf_getlocation.c b/libdw/dwarf_getlocation.c index 068f3853..a3a5bd43 100644 --- a/libdw/dwarf_getlocation.c +++ b/libdw/dwarf_getlocation.c @@ -1,5 +1,5 @@ /* Return location expression list. - Copyright (C) 2000-2010, 2013, 2014 Red Hat, Inc. + Copyright (C) 2000-2010, 2013-2015 Red Hat, Inc. This file is part of elfutils. Written by Ulrich Drepper <drepper@redhat.com>, 2000. @@ -270,16 +270,36 @@ __libdw_intern_expression (Dwarf *dbg, bool other_byte_order, { case DW_OP_addr: /* Address, depends on address size of CU. */ - if (__libdw_read_address_inc (dbg, sec_index, &data, - address_size, &newloc->number)) - return -1; + if (dbg == NULL) + { + // XXX relocation? + if (address_size == 4) + { + if (unlikely (data + 4 > end_data)) + goto invalid; + else + newloc->number = read_4ubyte_unaligned_inc (&bo, data); + } + else + { + if (unlikely (data + 8 > end_data)) + goto invalid; + else + newloc->number = read_8ubyte_unaligned_inc (&bo, data); + } + } + else if (__libdw_read_address_inc (dbg, sec_index, &data, + address_size, &newloc->number)) + goto invalid; break; case DW_OP_call_ref: /* DW_FORM_ref_addr, depends on offset size of CU. */ - if (__libdw_read_offset_inc (dbg, sec_index, &data, ref_size, - &newloc->number, IDX_debug_info, 0)) - return -1; + if (dbg == NULL || __libdw_read_offset_inc (dbg, sec_index, &data, + ref_size, + &newloc->number, + IDX_debug_info, 0)) + goto invalid; break; case DW_OP_deref: @@ -435,9 +455,11 @@ __libdw_intern_expression (Dwarf *dbg, bool other_byte_order, case DW_OP_GNU_implicit_pointer: /* DW_FORM_ref_addr, depends on offset size of CU. */ - if (__libdw_read_offset_inc (dbg, sec_index, &data, ref_size, - &newloc->number, IDX_debug_info, 0)) - return -1; + if (dbg == NULL || __libdw_read_offset_inc (dbg, sec_index, &data, + ref_size, + &newloc->number, + IDX_debug_info, 0)) + goto invalid; if (unlikely (data >= end_data)) goto invalid; get_uleb128 (newloc->number2, data, end_data); /* Byte offset. */ |