summaryrefslogtreecommitdiff
path: root/libdw
diff options
context:
space:
mode:
authorMark Wielaard <mark@klomp.org>2018-06-15 16:25:15 +0200
committerMark Wielaard <mark@klomp.org>2018-06-17 20:32:06 +0200
commit62aed3f99ce6229a7bf6b1a6e66c49d9e676680f (patch)
tree1e3e44993805bf35d44cf79234d0c62b87a4b359 /libdw
parent58ed0e647f1012f8b75eda47967d849aeb619ec2 (diff)
downloadelfutils-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/ChangeLog8
-rw-r--r--libdw/dwarf_getlocation.c44
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);