diff options
author | Mark Wielaard <mark@klomp.org> | 2018-06-15 16:25:15 +0200 |
---|---|---|
committer | Mark Wielaard <mark@klomp.org> | 2018-06-17 20:32:06 +0200 |
commit | 62aed3f99ce6229a7bf6b1a6e66c49d9e676680f (patch) | |
tree | 1e3e44993805bf35d44cf79234d0c62b87a4b359 /libdw | |
parent | 58ed0e647f1012f8b75eda47967d849aeb619ec2 (diff) | |
download | elfutils-62aed3f99ce6229a7bf6b1a6e66c49d9e676680f.tar.gz |
libdw, readelf: Don't handle DW_FORM_data16 as expression block/location.
Also found by afl-fuzz on the varlocs testcase.
DW_FORM_data16 is constant form according to the DWARF5 spec.
But since it is 128bits it isn't really representable as Dwarf_Word.
So we treat it as block form. But we cannot treat it as an expression
block. Make sure readelf prints it as a regular block and that
dwarf_getlocation[s|_addr] doesn't treat it as location expression.
Signed-off-by: Mark Wielaard <mark@klomp.org>
Diffstat (limited to 'libdw')
-rw-r--r-- | libdw/ChangeLog | 8 | ||||
-rw-r--r-- | libdw/dwarf_getlocation.c | 44 |
2 files changed, 39 insertions, 13 deletions
diff --git a/libdw/ChangeLog b/libdw/ChangeLog index 6492c976..329a994d 100644 --- a/libdw/ChangeLog +++ b/libdw/ChangeLog @@ -1,3 +1,11 @@ +2018-06-15 Mark Wielaard <mark@klomp.org> + + * dwarf_getlocation.c (check_constant_offset): Clarify DW_FORM_data16 + isn't really a constant. + (dwarf_getlocation): Don't handle DW_FORM_data16 as block. + (dwarf_getlocation_addr): Likewise. + (dwarf_getlocations): Likewise. + 2018-06-12 Mark Wielaard <mark@klomp.org> * memory-access.h (read_3ubyte_unaligned_inc): New define. diff --git a/libdw/dwarf_getlocation.c b/libdw/dwarf_getlocation.c index 7f294fe3..fc59a2ab 100644 --- a/libdw/dwarf_getlocation.c +++ b/libdw/dwarf_getlocation.c @@ -174,6 +174,8 @@ check_constant_offset (Dwarf_Attribute *attr, default: return 1; + /* Note, we don't regard DW_FORM_data16 as a constant form, + even though technically it is according to the standard. */ case DW_FORM_data1: case DW_FORM_data2: case DW_FORM_data4: @@ -665,7 +667,13 @@ dwarf_getlocation (Dwarf_Attribute *attr, Dwarf_Op **llbuf, size_t *listlen) if (result != 1) return result; - /* If it has a block form, it's a single location expression. */ + /* If it has a block form, it's a single location expression. + Except for DW_FORM_data16, which is a 128bit constant. */ + if (attr->form == DW_FORM_data16) + { + __libdw_seterrno (DWARF_E_NO_BLOCK); + return -1; + } Dwarf_Block block; if (INTUSE(dwarf_formblock) (attr, &block) != 0) return -1; @@ -863,9 +871,11 @@ dwarf_getlocation_addr (Dwarf_Attribute *attr, Dwarf_Addr address, if (llbufs == NULL) maxlocs = SIZE_MAX; - /* If it has a block form, it's a single location expression. */ + /* If it has a block form, it's a single location expression. + Except for DW_FORM_data16, which is a 128bit constant. */ Dwarf_Block block; - if (INTUSE(dwarf_formblock) (attr, &block) == 0) + if (attr->form != DW_FORM_data16 + && INTUSE(dwarf_formblock) (attr, &block) == 0) { if (maxlocs == 0) return 0; @@ -876,11 +886,14 @@ dwarf_getlocation_addr (Dwarf_Attribute *attr, Dwarf_Addr address, return listlens[0] == 0 ? 0 : 1; } - int error = INTUSE(dwarf_errno) (); - if (unlikely (error != DWARF_E_NO_BLOCK)) + if (attr->form != DW_FORM_data16) { - __libdw_seterrno (error); - return -1; + int error = INTUSE(dwarf_errno) (); + if (unlikely (error != DWARF_E_NO_BLOCK)) + { + __libdw_seterrno (error); + return -1; + } } int result = check_constant_offset (attr, &llbufs[0], &listlens[0]); @@ -938,9 +951,11 @@ dwarf_getlocations (Dwarf_Attribute *attr, ptrdiff_t offset, Dwarf_Addr *basep, if (offset == 0) { - /* If it has a block form, it's a single location expression. */ + /* If it has a block form, it's a single location expression. + Except for DW_FORM_data16, which is a 128bit constant. */ Dwarf_Block block; - if (INTUSE(dwarf_formblock) (attr, &block) == 0) + if (attr->form != DW_FORM_data16 + && INTUSE(dwarf_formblock) (attr, &block) == 0) { if (getlocation (attr->cu, &block, expr, exprlen, cu_sec_idx (attr->cu)) != 0) @@ -952,11 +967,14 @@ dwarf_getlocations (Dwarf_Attribute *attr, ptrdiff_t offset, Dwarf_Addr *basep, return 1; } - int error = INTUSE(dwarf_errno) (); - if (unlikely (error != DWARF_E_NO_BLOCK)) + if (attr->form != DW_FORM_data16) { - __libdw_seterrno (error); - return -1; + int error = INTUSE(dwarf_errno) (); + if (unlikely (error != DWARF_E_NO_BLOCK)) + { + __libdw_seterrno (error); + return -1; + } } int result = check_constant_offset (attr, expr, exprlen); |