[PATCH] readelf: DW_OP_call_ref and DW_OP_GNU_implicit_pointer are invalid for CFA.
by Mark Wielaard
print_cfa_program might call print_ops with zero offset size. We don't
need (and don't know) the DWARF offset size in that case. DW_OP_call_ref
and DW_OP_GNU_implicit_pointer need to know the offset size because they
reference a DIE. But they are invalid when used from CFA.
Signed-off-by: Mark Wielaard <mjw(a)redhat.com>
---
src/ChangeLog | 5 +++++
src/readelf.c | 4 ++++
2 files changed, 9 insertions(+)
diff --git a/src/ChangeLog b/src/ChangeLog
index c149a9c..ccbd6e8 100644
--- a/src/ChangeLog
+++ b/src/ChangeLog
@@ -1,3 +1,8 @@
+2014-12-07 Mark Wielaard <mjw(a)redhat.com>
+
+ * readelf.c (print_ops): Handle zero ref_size for DW_OP_call_ref
+ and DW_OP_GNU_implicit_pointer.
+
2014-12-04 Mark Wielaard <mjw(a)redhat.com>
* objdump.c (show_relocs_x): Make sure destshdr exists.
diff --git a/src/readelf.c b/src/readelf.c
index 89b1754..881bb45 100644
--- a/src/readelf.c
+++ b/src/readelf.c
@@ -3999,6 +3999,8 @@ print_ops (Dwfl_Module *dwflmod, Dwarf *dbg, int indent, int indentrest,
case DW_OP_call_ref:
/* Offset operand. */
+ if (ref_size == 0)
+ goto invalid; /* Cannot be used in CFA. */
NEED (ref_size);
if (ref_size == 4)
addr = read_4ubyte_unaligned (dbg, data);
@@ -4203,6 +4205,8 @@ print_ops (Dwfl_Module *dwflmod, Dwarf *dbg, int indent, int indentrest,
/* DIE offset operand. */
start = data;
NEED (ref_size + 1);
+ if (ref_size == 0)
+ goto invalid; /* Cannot be used in CFA. */
if (ref_size == 4)
addr = read_4ubyte_unaligned (dbg, data);
else
--
1.9.3
9 years, 4 months
[PATCH] libdwfl: Check actually used ehsize, shentsize and phentsize in relocate.c
by Mark Wielaard
In relocate_section we check relocation sections don't overlap any of the
ELF headers. We should check against the actually used ehsize, shentsize
and phentsize. Not the possibly bogus values in the file ehdr itself.
Signed-off-by: Mark Wielaard <mjw(a)redhat.com>
---
libdwfl/ChangeLog | 5 +++++
libdwfl/relocate.c | 11 +++++++----
2 files changed, 12 insertions(+), 4 deletions(-)
diff --git a/libdwfl/ChangeLog b/libdwfl/ChangeLog
index 6eec018..b882f20 100644
--- a/libdwfl/ChangeLog
+++ b/libdwfl/ChangeLog
@@ -1,5 +1,10 @@
2014-12-07 Mark Wielaard <mjw(a)redhat.com>
+ * relocate.c (relocate_section): Sanity check section overlap against
+ actually used ehsize, shentsize and phentsize.
+
+2014-12-07 Mark Wielaard <mjw(a)redhat.com>
+
* offline.c (dwfl_offline_section_address): Assert shndx is not zero.
* relocate.c (__libdwfl_relocate_value): Don't relocate against
section zero.
diff --git a/libdwfl/relocate.c b/libdwfl/relocate.c
index fc8ae23..fd7dbd5 100644
--- a/libdwfl/relocate.c
+++ b/libdwfl/relocate.c
@@ -309,8 +309,9 @@ relocate_section (Dwfl_Module *mod, Elf *relocated, const GElf_Ehdr *ehdr,
isn't illegal for ELF section data to overlap the header data,
but updating the (relocation) data might corrupt the in-memory
libelf headers causing strange corruptions or errors. */
- if (unlikely (shdr->sh_offset < ehdr->e_ehsize
- || tshdr->sh_offset < ehdr->e_ehsize))
+ size_t ehsize = gelf_fsize (relocated, ELF_T_EHDR, 1, EV_CURRENT);
+ if (unlikely (shdr->sh_offset < ehsize
+ || tshdr->sh_offset < ehsize))
return DWFL_E_BADELF;
GElf_Off shdrs_start = ehdr->e_shoff;
@@ -318,7 +319,8 @@ relocate_section (Dwfl_Module *mod, Elf *relocated, const GElf_Ehdr *ehdr,
if (elf_getshdrnum (relocated, &shnums) < 0)
return DWFL_E_LIBELF;
/* Overflows will have been checked by elf_getshdrnum/get|rawdata. */
- GElf_Off shdrs_end = shdrs_start + shnums * ehdr->e_shentsize;
+ size_t shentsize = gelf_fsize (relocated, ELF_T_SHDR, 1, EV_CURRENT);
+ GElf_Off shdrs_end = shdrs_start + shnums * shentsize;
if (unlikely ((shdrs_start < shdr->sh_offset + shdr->sh_size
&& shdr->sh_offset < shdrs_end)
|| (shdrs_start < tshdr->sh_offset + tshdr->sh_size
@@ -332,7 +334,8 @@ relocate_section (Dwfl_Module *mod, Elf *relocated, const GElf_Ehdr *ehdr,
if (phdrs_start != 0 && phnums != 0)
{
/* Overflows will have been checked by elf_getphdrnum/get|rawdata. */
- GElf_Off phdrs_end = phdrs_start + phnums * ehdr->e_phentsize;
+ size_t phentsize = gelf_fsize (relocated, ELF_T_PHDR, 1, EV_CURRENT);
+ GElf_Off phdrs_end = phdrs_start + phnums * phentsize;
if (unlikely ((phdrs_start < shdr->sh_offset + shdr->sh_size
&& shdr->sh_offset < phdrs_end)
|| (phdrs_start < tshdr->sh_offset + tshdr->sh_size
--
1.9.3
9 years, 4 months
[PATCH] libdwfl: Never relocate value against section zero (load address).
by Mark Wielaard
This really is just a robustify patch in case section zero got the
wrong section flags set. In that case __libdwfl_relocate_value might
call dwfl_offline_section_address which might assert (because it isn't
prepared to handle section zero). elf_nextscn will never see section zero.
So be explicit in dwfl_offline_section_address and immediately assert
when shndx is zero. And handle section zero immediately by not relocating
the value in __libdwfl_relocate_value.
Signed-off-by: Mark Wielaard <mjw(a)redhat.com>
---
libdwfl/ChangeLog | 6 ++++++
libdwfl/offline.c | 1 +
libdwfl/relocate.c | 6 ++++++
3 files changed, 13 insertions(+)
diff --git a/libdwfl/ChangeLog b/libdwfl/ChangeLog
index 03faecf..6eec018 100644
--- a/libdwfl/ChangeLog
+++ b/libdwfl/ChangeLog
@@ -1,3 +1,9 @@
+2014-12-07 Mark Wielaard <mjw(a)redhat.com>
+
+ * offline.c (dwfl_offline_section_address): Assert shndx is not zero.
+ * relocate.c (__libdwfl_relocate_value): Don't relocate against
+ section zero.
+
2014-11-29 Mark Wielaard <mjw(a)redhat.com>
* relocate.c (relocate_section): Check relocation section and target
diff --git a/libdwfl/offline.c b/libdwfl/offline.c
index 28d2782..982ceab 100644
--- a/libdwfl/offline.c
+++ b/libdwfl/offline.c
@@ -48,6 +48,7 @@ dwfl_offline_section_address (Dwfl_Module *mod,
assert (mod->e_type == ET_REL);
assert (shdr->sh_addr == 0);
assert (shdr->sh_flags & SHF_ALLOC);
+ assert (shndx != 0);
if (mod->debug.elf == NULL)
/* We are only here because sh_addr is zero even though layout is complete.
diff --git a/libdwfl/relocate.c b/libdwfl/relocate.c
index 6862189..fc8ae23 100644
--- a/libdwfl/relocate.c
+++ b/libdwfl/relocate.c
@@ -38,6 +38,12 @@ internal_function
__libdwfl_relocate_value (Dwfl_Module *mod, Elf *elf, size_t *shstrndx,
Elf32_Word shndx, GElf_Addr *value)
{
+ /* No adjustment needed for section zero, it is never loaded.
+ Handle it first, just in case the ELF file has strange section
+ zero flags set. */
+ if (shndx == 0)
+ return DWFL_E_NOERROR;
+
Elf_Scn *refscn = elf_getscn (elf, shndx);
GElf_Shdr refshdr_mem, *refshdr = gelf_getshdr (refscn, &refshdr_mem);
if (refshdr == NULL)
--
1.9.3
9 years, 4 months
[PATCH] libdw: Add overflow checking to __libdw_form_val_len.
by Mark Wielaard
This solves a couple of crashers reported by Alexander.
This will probably have some performance impact, but I haven't measured
it yet. It would be good to have some performance tests. We also need
some overflow check for leb128 reading.
Josh, which tests did you use last time when you did the performance
improvements of this code? I am afraid I won't be able to keep it as fast,
but it would be good to know how much this slows things down.
Pass endp as argument to __libdw_form_val_len and check we don't read
beyond the end of expected data and don't return lengths that would
overflow.
Signed-off-by: Mark Wielaard <mjw(a)redhat.com>
---
libdw/ChangeLog | 10 ++++++++++
libdw/dwarf_child.c | 7 ++++---
libdw/dwarf_getattrs.c | 13 +++++++------
libdw/dwarf_getmacros.c | 8 ++++++--
libdw/libdwP.h | 22 ++++++++++++++++------
libdw/libdw_form.c | 47 +++++++++++++++++++++++++++++++++--------------
6 files changed, 76 insertions(+), 31 deletions(-)
diff --git a/libdw/ChangeLog b/libdw/ChangeLog
index bab02e5..8786d7f 100644
--- a/libdw/ChangeLog
+++ b/libdw/ChangeLog
@@ -1,3 +1,13 @@
+2014-12-04 Mark Wielaard <mjw(a)redhat.com>
+
+ * libdwP.h (__libdw_form_val_compute_len): Add endp argument.
+ (__libdw_form_val_len): Likewise and check len doesn't overflow.
+ * libdw_form.c (__libdw_form_val_compute_len): Likewise.
+ * dwarf_child.c (__libdw_find_attr): Call __libdw_form_val_len
+ with endp.
+ * dwarf_getattrs.c (dwarf_getattrs): Likewise.
+ * dwarf_getmacros.c (read_macros): Likewise and check for errors.
+
2014-11-27 Mark Wielaard <mjw(a)redhat.com>
* Makefile.am (libdw.so): Use textrel_check.
diff --git a/libdw/dwarf_child.c b/libdw/dwarf_child.c
index 1d3a337..fa31600 100644
--- a/libdw/dwarf_child.c
+++ b/libdw/dwarf_child.c
@@ -1,5 +1,5 @@
/* Return child of current DIE.
- Copyright (C) 2003-2011 Red Hat, Inc.
+ Copyright (C) 2003-2011, 2014 Red Hat, Inc.
This file is part of elfutils.
Written by Ulrich Drepper <drepper(a)redhat.com>, 2003.
@@ -104,7 +104,8 @@ __libdw_find_attr (Dwarf_Die *die, unsigned int search_name,
/* Skip over the rest of this attribute (if there is any). */
if (attr_form != 0)
{
- size_t len = __libdw_form_val_len (dbg, die->cu, attr_form, readp);
+ size_t len = __libdw_form_val_len (dbg, die->cu, attr_form, readp,
+ endp);
if (unlikely (len == (size_t) -1l))
{
@@ -112,7 +113,7 @@ __libdw_find_attr (Dwarf_Die *die, unsigned int search_name,
break;
}
- // XXX We need better boundary checks.
+ // __libdw_form_val_len will have done a bounds check.
readp += len;
}
}
diff --git a/libdw/dwarf_getattrs.c b/libdw/dwarf_getattrs.c
index 82eb3f8..627a851 100644
--- a/libdw/dwarf_getattrs.c
+++ b/libdw/dwarf_getattrs.c
@@ -1,5 +1,5 @@
/* Get attributes of the DIE.
- Copyright (C) 2004, 2005, 2008, 2009 Red Hat, Inc.
+ Copyright (C) 2004, 2005, 2008, 2009, 2014 Red Hat, Inc.
This file is part of elfutils.
Written by Ulrich Drepper <drepper(a)redhat.com>, 2004.
@@ -67,12 +67,13 @@ dwarf_getattrs (Dwarf_Die *die, int (*callback) (Dwarf_Attribute *, void *),
/* Go over the list of attributes. */
Dwarf *dbg = die->cu->dbg;
+ const unsigned char *endp;
+ endp = ((const unsigned char *) dbg->sectiondata[IDX_debug_abbrev]->d_buf
+ + dbg->sectiondata[IDX_debug_abbrev]->d_size);
while (1)
{
/* Are we still in bounds? */
- if (unlikely (attrp
- >= ((unsigned char *) dbg->sectiondata[IDX_debug_abbrev]->d_buf
- + dbg->sectiondata[IDX_debug_abbrev]->d_size)))
+ if (unlikely (attrp >= endp))
goto invalid_dwarf;
/* Get attribute name and form. */
@@ -111,13 +112,13 @@ dwarf_getattrs (Dwarf_Die *die, int (*callback) (Dwarf_Attribute *, void *),
if (attr.form != 0)
{
size_t len = __libdw_form_val_len (dbg, die->cu, attr.form,
- die_addr);
+ die_addr, endp);
if (unlikely (len == (size_t) -1l))
/* Something wrong with the file. */
return -1l;
- // XXX We need better boundary checks.
+ // __libdw_form_val_len will have done a bounds check.
die_addr += len;
}
}
diff --git a/libdw/dwarf_getmacros.c b/libdw/dwarf_getmacros.c
index 8d9d78b..76f9de0 100644
--- a/libdw/dwarf_getmacros.c
+++ b/libdw/dwarf_getmacros.c
@@ -367,8 +367,12 @@ read_macros (Dwarf *dbg, int sec_index,
attributes[i].valp = (void *) readp;
attributes[i].cu = &fake_cu;
- readp += __libdw_form_val_len (dbg, &fake_cu,
- proto->forms[i], readp);
+ size_t len = __libdw_form_val_len (dbg, &fake_cu,
+ proto->forms[i], readp, endp);
+ if (len == (size_t) -1)
+ return -1;
+
+ readp += len;
}
Dwarf_Macro macro = {
diff --git a/libdw/libdwP.h b/libdw/libdwP.h
index 5ccb13c..351c5b4 100644
--- a/libdw/libdwP.h
+++ b/libdw/libdwP.h
@@ -458,14 +458,16 @@ extern Dwarf_Abbrev *__libdw_getabbrev (Dwarf *dbg, struct Dwarf_CU *cu,
/* Helper functions for form handling. */
extern size_t __libdw_form_val_compute_len (Dwarf *dbg, struct Dwarf_CU *cu,
unsigned int form,
- const unsigned char *valp)
- __nonnull_attribute__ (1, 2, 4) internal_function;
+ const unsigned char *valp,
+ const unsigned char *endp)
+ __nonnull_attribute__ (1, 2, 4, 5) internal_function;
/* Find the length of a form attribute. */
static inline size_t
-__nonnull_attribute__ (1, 2, 4)
+__nonnull_attribute__ (1, 2, 4, 5)
__libdw_form_val_len (Dwarf *dbg, struct Dwarf_CU *cu,
- unsigned int form, const unsigned char *valp)
+ unsigned int form, const unsigned char *valp,
+ const unsigned char *endp)
{
/* Small lookup table of forms with fixed lengths. Absent indexes are
initialized 0, so any truly desired 0 is set to 0x80 and masked. */
@@ -483,11 +485,19 @@ __libdw_form_val_len (Dwarf *dbg, struct Dwarf_CU *cu,
{
uint8_t len = form_lengths[form];
if (len != 0)
- return len & 0x7f; /* Mask to allow 0x80 -> 0. */
+ {
+ len &= 0x7f; /* Mask to allow 0x80 -> 0. */
+ if (unlikely (len > (size_t) (endp - valp)))
+ {
+ __libdw_seterrno (DWARF_E_INVALID_DWARF);
+ return -1;
+ }
+ return len;
+ }
}
/* Other forms require some computation. */
- return __libdw_form_val_compute_len (dbg, cu, form, valp);
+ return __libdw_form_val_compute_len (dbg, cu, form, valp, endp);
}
/* Helper function for DW_FORM_ref* handling. */
diff --git a/libdw/libdw_form.c b/libdw/libdw_form.c
index 5350556..65ac7de 100644
--- a/libdw/libdw_form.c
+++ b/libdw/libdw_form.c
@@ -1,5 +1,5 @@
/* Helper functions for form handling.
- Copyright (C) 2003-2009 Red Hat, Inc.
+ Copyright (C) 2003-2009, 2014 Red Hat, Inc.
This file is part of elfutils.
Written by Ulrich Drepper <drepper(a)redhat.com>, 2003.
@@ -40,9 +40,10 @@
size_t
internal_function
__libdw_form_val_compute_len (Dwarf *dbg, struct Dwarf_CU *cu,
- unsigned int form, const unsigned char *valp)
+ unsigned int form, const unsigned char *valp,
+ const unsigned char *endp)
{
- const unsigned char *saved;
+ const unsigned char *startp = valp;
Dwarf_Word u128;
size_t result;
@@ -66,49 +67,67 @@ __libdw_form_val_compute_len (Dwarf *dbg, struct Dwarf_CU *cu,
break;
case DW_FORM_block1:
+ if (unlikely ((size_t) (endp - startp) < 1))
+ goto invalid;
result = *valp + 1;
break;
case DW_FORM_block2:
+ if (unlikely ((size_t) (endp - startp) < 2))
+ goto invalid;
result = read_2ubyte_unaligned (dbg, valp) + 2;
break;
case DW_FORM_block4:
+ if (unlikely ((size_t) (endp - startp) < 4))
+ goto invalid;
result = read_4ubyte_unaligned (dbg, valp) + 4;
break;
case DW_FORM_block:
case DW_FORM_exprloc:
- saved = valp;
+ // XXX overflow check
get_uleb128 (u128, valp);
- result = u128 + (valp - saved);
+ result = u128 + (valp - startp);
break;
case DW_FORM_string:
- result = strlen ((char *) valp) + 1;
- break;
+ {
+ const unsigned char *endstrp = memchr (valp, '\0',
+ (size_t) (endp - startp));
+ if (unlikely (endstrp == NULL))
+ goto invalid;
+ result = (size_t) (endstrp - startp) + 1;
+ break;
+ }
case DW_FORM_sdata:
case DW_FORM_udata:
case DW_FORM_ref_udata:
- saved = valp;
+ // XXX overflow check
get_uleb128 (u128, valp);
- result = valp - saved;
+ result = valp - startp;
break;
case DW_FORM_indirect:
- saved = valp;
get_uleb128 (u128, valp);
// XXX Is this really correct?
- result = __libdw_form_val_len (dbg, cu, u128, valp);
+ result = __libdw_form_val_len (dbg, cu, u128, valp, endp);
if (result != (size_t) -1)
- result += valp - saved;
+ result += valp - startp;
+ else
+ return (size_t) -1;
break;
default:
+ goto invalid;
+ }
+
+ if (unlikely (result > (size_t) (endp - startp)))
+ {
+ invalid:
__libdw_seterrno (DWARF_E_INVALID_DWARF);
- result = (size_t) -1l;
- break;
+ result = (size_t) -1;
}
return result;
--
1.8.3.1
9 years, 4 months
[PATCH][V2] Change calling convention of dwarf_getmacros to allow opcode 0xff
by Petr Machata
The previous patch kept one extra bit for destinguishing .debug_macro
from .debug_macinfo iteration. That was a left-over from the first
proposals and it really makes no sense to keep that as a separate bit
now. Drop it, deduce the information from available context.
Thanks,
Petr
----8<----------------------------------------------------------------
We now require callers to pass DWARF_GETMACROS_START to start the
iteration. 0 is still accepted, but signals to libdw that the
iteration request comes from an old-style caller, and that opcode 0xff
should be rejected when iterating .debug_macro, to avoid confusion.
Signed-off-by: Petr Machata <pmachata(a)redhat.com>
---
NEWS | 2 -
libdw/ChangeLog | 7 ++
libdw/dwarf_getmacros.c | 157 +++++++++++++++++++++++------------------
libdw/libdw.h | 40 ++++++-----
tests/ChangeLog | 10 +++
tests/dwarf-getmacros.c | 27 +++++--
tests/run-dwarf-getmacros.sh | 11 +++
tests/testfile-macros-0xff.bz2 | Bin 0 -> 2844 bytes
tests/testfile-macros-0xff.s | 153 +++++++++++++++++++++++++++++++++++++++
9 files changed, 314 insertions(+), 93 deletions(-)
create mode 100755 tests/testfile-macros-0xff.bz2
create mode 100644 tests/testfile-macros-0xff.s
diff --git a/NEWS b/NEWS
index 8f0780b..a7ead0a 100644
--- a/NEWS
+++ b/NEWS
@@ -8,8 +8,6 @@ libdw: New function dwarf_peel_type. dwarf_aggregate_size now uses
dwarf_macro_getparamcnt, and dwarf_macro_param are available
for more generalized inspection of macros and their parameters.
-XXX: Fix serving of 0xff based on what ends up in Dwarf 5.
-
Version 0.160
libdw: New functions dwarf_cu_getdwarf, dwarf_cu_die.
diff --git a/libdw/ChangeLog b/libdw/ChangeLog
index 37f94df..7129eab 100644
--- a/libdw/ChangeLog
+++ b/libdw/ChangeLog
@@ -1,3 +1,10 @@
+2014-12-02 Petr Machata <pmachata(a)redhat.com>
+
+ * dwarf_getmacros.c (token_from_offset, offset_from_token): New
+ helper functions.
+ (do_dwarf_getmacros_die): Merge into dwarf_getmacros.
+ * libdw.h (DWARF_GETMACROS_START): New macro.
+
2014-11-24 Mark Wielaard <mjw(a)redhat.com>
* dwarf_getsrclines.c (read_srclines): Check line_range is not zero
diff --git a/libdw/dwarf_getmacros.c b/libdw/dwarf_getmacros.c
index 8d9d78b..0ba3854 100644
--- a/libdw/dwarf_getmacros.c
+++ b/libdw/dwarf_getmacros.c
@@ -384,13 +384,53 @@ read_macros (Dwarf *dbg, int sec_index,
return 0;
}
+/* Token layout:
+
+ - The highest bit is used for distinguishing between callers that
+ know that opcode 0xff may have one of two incompatible meanings.
+ The mask that we use for selecting this bit is
+ DWARF_GETMACROS_START.
+
+ - The rest of the token (31 or 63 bits) encodes address inside the
+ macro unit.
+
+ Besides, token value of 0 signals end of iteration and -1 is
+ reserved for signaling errors. That means it's impossible to
+ represent maximum offset of a .debug_macro unit to new-style
+ callers (which in practice decreases the permissible macro unit
+ size by another 1 byte). */
+
+static ptrdiff_t
+token_from_offset (ptrdiff_t offset, bool accept_0xff)
+{
+ if (offset == -1 || offset == 0)
+ return offset;
+
+ /* Make sure the offset didn't overflow into the flag bit. */
+ assert ((offset & DWARF_GETMACROS_START) == 0);
+
+ if (accept_0xff)
+ offset |= DWARF_GETMACROS_START;
+
+ return offset;
+}
+
+static ptrdiff_t
+offset_from_token (ptrdiff_t token, bool *accept_0xffp)
+{
+ *accept_0xffp = (token & DWARF_GETMACROS_START) != 0;
+ token &= ~DWARF_GETMACROS_START;
+
+ return token;
+}
+
static ptrdiff_t
gnu_macros_getmacros_off (Dwarf *dbg, Dwarf_Off macoff,
int (*callback) (Dwarf_Macro *, void *),
- void *arg, ptrdiff_t token, bool accept_0xff,
+ void *arg, ptrdiff_t offset, bool accept_0xff,
Dwarf_Die *cudie)
{
- assert (token <= 0);
+ assert (offset >= 0);
if (macoff >= dbg->sectiondata[IDX_debug_macro]->d_size)
{
@@ -398,23 +438,19 @@ gnu_macros_getmacros_off (Dwarf *dbg, Dwarf_Off macoff,
return -1;
}
- ptrdiff_t ret = read_macros (dbg, IDX_debug_macro, macoff,
- callback, arg, -token, accept_0xff, cudie);
- if (ret == -1)
- return -1;
- else
- return -ret;
+ return read_macros (dbg, IDX_debug_macro, macoff,
+ callback, arg, offset, accept_0xff, cudie);
}
static ptrdiff_t
macro_info_getmacros_off (Dwarf *dbg, Dwarf_Off macoff,
int (*callback) (Dwarf_Macro *, void *),
- void *arg, ptrdiff_t token, Dwarf_Die *cudie)
+ void *arg, ptrdiff_t offset, Dwarf_Die *cudie)
{
- assert (token >= 0);
+ assert (offset >= 0);
return read_macros (dbg, IDX_debug_macinfo, macoff,
- callback, arg, token, true, cudie);
+ callback, arg, offset, true, cudie);
}
ptrdiff_t
@@ -428,21 +464,22 @@ dwarf_getmacros_off (Dwarf *dbg, Dwarf_Off macoff,
return -1;
}
- /* We use token values > 0 for iteration through .debug_macinfo and
- values < 0 for iteration through .debug_macro. Return value of
- -1 also signifies an error, but that's fine, because .debug_macro
- always contains at least three bytes of headers and after
- iterating one opcode, we should never see anything above -4. */
- assert (token <= 0);
+ bool accept_0xff;
+ ptrdiff_t offset = offset_from_token (token, &accept_0xff);
+ assert (accept_0xff);
+
+ offset = gnu_macros_getmacros_off (dbg, macoff, callback, arg, offset,
+ accept_0xff, NULL);
- return gnu_macros_getmacros_off (dbg, macoff, callback, arg, token, true,
- NULL);
+ return token_from_offset (offset, accept_0xff);
}
-static ptrdiff_t
-do_dwarf_getmacros_die (Dwarf_Die *cudie, Dwarf_Off *macoffp,
- int (*callback) (Dwarf_Macro *, void *),
- void *arg, ptrdiff_t token, bool accept_0xff)
+ptrdiff_t
+dwarf_getmacros (cudie, callback, arg, token)
+ Dwarf_Die *cudie;
+ int (*callback) (Dwarf_Macro *, void *);
+ void *arg;
+ ptrdiff_t token;
{
if (cudie == NULL)
{
@@ -450,50 +487,6 @@ do_dwarf_getmacros_die (Dwarf_Die *cudie, Dwarf_Off *macoffp,
return -1;
}
- if (token > 0 && macoffp != NULL)
- /* A continuation call from DW_AT_macro_info iteration, meaning
- *MACOFF contains previously-cached offset. */
- return macro_info_getmacros_off (cudie->cu->dbg, *macoffp,
- callback, arg, token, cudie);
-
- /* A fresh start of DW_AT_macro_info iteration, or a continuation
- thereof without a cache. */
- if (token > 0
- || (token == 0 && dwarf_hasattr (cudie, DW_AT_macro_info)))
- {
- Dwarf_Word macoff;
- if (macoffp == NULL)
- macoffp = &macoff;
- if (get_offset_from (cudie, DW_AT_macro_info, macoffp) != 0)
- return -1;
- return macro_info_getmacros_off (cudie->cu->dbg, *macoffp,
- callback, arg, token, cudie);
- }
-
- if (token < 0 && macoffp != NULL)
- /* A continuation call from DW_AT_GNU_macros iteration. */
- return gnu_macros_getmacros_off (cudie->cu->dbg, *macoffp,
- callback, arg, token, accept_0xff,
- cudie);
-
- /* Likewise without cache, or iteration start. */
- Dwarf_Word macoff;
- if (macoffp == NULL)
- macoffp = &macoff;
- if (get_offset_from (cudie, DW_AT_GNU_macros, macoffp) != 0)
- return -1;
- return gnu_macros_getmacros_off (cudie->cu->dbg, *macoffp,
- callback, arg, token, accept_0xff,
- cudie);
-}
-
-ptrdiff_t
-dwarf_getmacros (die, callback, arg, offset)
- Dwarf_Die *die;
- int (*callback) (Dwarf_Macro *, void *);
- void *arg;
- ptrdiff_t offset;
-{
/* This function might be called from a code that expects to see
DW_MACINFO_* opcodes, not DW_MACRO_{GNU_,}* ones. It is fine to
serve most DW_MACRO_{GNU_,}* opcodes to such code, because those
@@ -511,7 +504,33 @@ dwarf_getmacros (die, callback, arg, offset)
some small probability that the two opcodes would look
superficially similar enough that a client would be confused and
misbehave as a result. For this reason, we refuse to serve
- through this interface 0xff's originating from .debug_macro. */
+ through this interface 0xff's originating from .debug_macro
+ unless the TOKEN that we obtained indicates the call originates
+ from a new-style caller. See above for details on what
+ information is encoded into tokens. */
+
+ bool accept_0xff;
+ ptrdiff_t offset = offset_from_token (token, &accept_0xff);
+
+ /* DW_AT_macro_info */
+ if (dwarf_hasattr (cudie, DW_AT_macro_info))
+ {
+ Dwarf_Word macoff;
+ if (get_offset_from (cudie, DW_AT_macro_info, &macoff) != 0)
+ return -1;
+ offset = macro_info_getmacros_off (cudie->cu->dbg, macoff,
+ callback, arg, offset, cudie);
+ }
+ else
+ {
+ /* DW_AT_GNU_macros, DW_AT_macros */
+ Dwarf_Word macoff;
+ if (get_offset_from (cudie, DW_AT_GNU_macros, &macoff) != 0)
+ return -1;
+ offset = gnu_macros_getmacros_off (cudie->cu->dbg, macoff,
+ callback, arg, offset, accept_0xff,
+ cudie);
+ }
- return do_dwarf_getmacros_die (die, NULL, callback, arg, offset, false);
+ return token_from_offset (offset, accept_0xff);
}
diff --git a/libdw/libdw.h b/libdw/libdw.h
index c0baa21..b2b2282 100644
--- a/libdw/libdw.h
+++ b/libdw/libdw.h
@@ -32,6 +32,7 @@
#include <gelf.h>
#include <stdbool.h>
#include <stddef.h>
+#include <stdint.h>
#if __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 3)
@@ -845,22 +846,24 @@ extern int dwarf_entry_breakpoints (Dwarf_Die *die, Dwarf_Addr **bkpts);
/* Iterate through the macro unit referenced by CUDIE and call
- CALLBACK for each macro information entry. Keeps iterating while
- CALLBACK returns DWARF_CB_OK. If the callback returns
- DWARF_CB_ABORT, it stops iterating and returns a continuation
- token, which can be used to restart the iteration at the point
- where it ended. A TOKEN of 0 starts the iteration. Returns -1 for
- errors or 0 if there are no more macro entries.
+ CALLBACK for each macro information entry. To start the iteration,
+ one would pass DWARF_GETMACROS_START for TOKEN.
+
+ The iteration continues while CALLBACK returns DWARF_CB_OK. If the
+ callback returns DWARF_CB_ABORT, the iteration stops and a
+ continuation token is returned, which can be used to restart the
+ iteration at the point where it ended. Returns -1 for errors or 0
+ if there are no more macro entries.
Note that the Dwarf_Macro pointer passed to the callback is only
valid for the duration of the callback invocation.
- Note that this interface will refuse to serve opcode 0xff from
- .debug_macro sections. Such opcode is considered invalid and will
- cause dwarf_getmacros to return with error. Note that this should
- be no limitation as of now, as DW_MACRO_GNU_* domain doesn't
- allocate 0xff. It is however a theoretical possibility with future
- Dwarf standards. */
+ For backward compatibility, a token of 0 is accepted for starting
+ the iteration as well, but in that case this interface will refuse
+ to serve opcode 0xff from .debug_macro sections. Such opcode would
+ be considered invalid and would cause dwarf_getmacros to return
+ with error. */
+#define DWARF_GETMACROS_START PTRDIFF_MIN
extern ptrdiff_t dwarf_getmacros (Dwarf_Die *cudie,
int (*callback) (Dwarf_Macro *, void *),
void *arg, ptrdiff_t token)
@@ -871,13 +874,16 @@ extern ptrdiff_t dwarf_getmacros (Dwarf_Die *cudie,
iterates .debug_macro. This can be used for handling
DW_MACRO_GNU_transparent_include's or similar opcodes.
+ TOKEN value of DWARF_GETMACROS_START can be used to start the
+ iteration.
+
It is not appropriate to obtain macro unit offset by hand from a CU
DIE and then request iteration through this interface. The reason
for this is that if a dwarf_macro_getsrcfiles is later called,
there would be no way to figure out what DW_AT_comp_dir was present
on the CU DIE, and file names referenced in either the macro unit
itself, or the .debug_line unit that it references, might be wrong.
- Use dwarf_getmacro. */
+ Use dwarf_getmacros. */
extern ptrdiff_t dwarf_getmacros_off (Dwarf *dbg, Dwarf_Off macoff,
int (*callback) (Dwarf_Macro *, void *),
void *arg, ptrdiff_t token)
@@ -895,9 +901,11 @@ extern int dwarf_macro_getsrcfiles (Dwarf *dbg, Dwarf_Macro *macro,
/* Return macro opcode. That's a constant that can be either from
DW_MACINFO_* domain or DW_MACRO_GNU_* domain. The two domains have
compatible values, so it's OK to use either of them for
- comparisons. The only differences is 0xff, which currently is
- never served from .debug_macro, and can thus be safely assumed to
- mean DW_MACINFO_vendor_ext. */
+ comparisons. The only differences is 0xff, which could be either
+ DW_MACINFO_vendor_ext or a vendor-defined DW_MACRO_* constant. One
+ would need to look if the CU DIE which the iteration was requested
+ for has attribute DW_AT_macro_info, or either of DW_AT_GNU_macros
+ or DW_AT_macros to differentiate the two interpretations. */
extern int dwarf_macro_opcode (Dwarf_Macro *macro, unsigned int *opcodep)
__nonnull_attribute__ (2);
diff --git a/tests/ChangeLog b/tests/ChangeLog
index 909a61e..eb77673 100644
--- a/tests/ChangeLog
+++ b/tests/ChangeLog
@@ -1,3 +1,13 @@
+2014-12-02 Petr Machata <pmachata(a)redhat.com>
+
+ * dwarf-getmacros.c (mac): Skip over DW_MACINFO_undef,
+ DW_MACRO_GNU_undef_indirect opcodes. Add a default branch.
+ (main): Initialize off to DWARF_GETMACROS_START when an extra
+ command line argument is passed.
+ * testfile-macros-0xff.bz2: New test case.
+ * testfile-macros-0xff.s: New file (source for the above).
+ * run-dwarf-getmacros.sh: Add two tests.
+
2014-11-21 Mark Wielaard <mjw(a)redhat.com>
* run-readelf-A.sh: New test.
diff --git a/tests/dwarf-getmacros.c b/tests/dwarf-getmacros.c
index f203d5b..92e093c 100644
--- a/tests/dwarf-getmacros.c
+++ b/tests/dwarf-getmacros.c
@@ -34,9 +34,9 @@ mac (Dwarf_Macro *macro, void *dbg)
{
static int level = 0;
- switch (({ unsigned int opcode;
- dwarf_macro_opcode (macro, &opcode);
- opcode; }))
+ unsigned int opcode;
+ dwarf_macro_opcode (macro, &opcode);
+ switch (opcode)
{
case DW_MACRO_GNU_transparent_include:
{
@@ -50,7 +50,7 @@ mac (Dwarf_Macro *macro, void *dbg)
printf ("%*sinclude %#" PRIx64 "\n", level, "", w);
++level;
- include (dbg, w, 0);
+ include (dbg, w, DWARF_GETMACROS_START);
--level;
printf ("%*s/include\n", level, "");
break;
@@ -88,6 +88,19 @@ mac (Dwarf_Macro *macro, void *dbg)
printf ("%*s%s\n", level, "", value);
break;
}
+
+ case DW_MACINFO_undef:
+ case DW_MACRO_GNU_undef_indirect:
+ break;
+
+ default:
+ {
+ size_t paramcnt;
+ dwarf_macro_getparamcnt (macro, ¶mcnt);
+ printf ("%*sopcode %u with %zd arguments\n",
+ level, "", opcode, paramcnt);
+ break;
+ }
}
return DWARF_CB_ABORT;
@@ -105,17 +118,19 @@ include (Dwarf *dbg, Dwarf_Off macoff, ptrdiff_t token)
}
int
-main (int argc __attribute__ ((unused)), char *argv[])
+main (int argc, char *argv[])
{
+ assert (argc >= 3);
const char *name = argv[1];
ptrdiff_t cuoff = strtol (argv[2], NULL, 0);
+ bool new_style = argc > 3;
int fd = open (name, O_RDONLY);
Dwarf *dbg = dwarf_begin (fd, DWARF_C_READ);
Dwarf_Die cudie_mem, *cudie = dwarf_offdie (dbg, cuoff, &cudie_mem);
- for (ptrdiff_t off = 0;
+ for (ptrdiff_t off = new_style ? DWARF_GETMACROS_START : 0;
(off = dwarf_getmacros (cudie, mac, dbg, off)); )
if (off == -1)
{
diff --git a/tests/run-dwarf-getmacros.sh b/tests/run-dwarf-getmacros.sh
index 8f7c4a8..0a488fa 100755
--- a/tests/run-dwarf-getmacros.sh
+++ b/tests/run-dwarf-getmacros.sh
@@ -696,4 +696,15 @@ file /home/mark/src/tests/macro.c
/file
EOF
+testfiles testfile-macros-0xff
+testrun_compare ${abs_builddir}/dwarf-getmacros testfile-macros-0xff 0xb <<\EOF
+invalid opcode
+EOF
+testrun_compare ${abs_builddir}/dwarf-getmacros testfile-macros-0xff 0xb '' <<\EOF
+opcode 255 with 0 arguments
+file /home/petr/proj/elfutils/master/elfutils/x.c
+ FOO 0
+/file
+EOF
+
exit 0
diff --git a/tests/testfile-macros-0xff.bz2 b/tests/testfile-macros-0xff.bz2
new file mode 100755
index 0000000000000000000000000000000000000000..a19662a3d43170f7200c50f2984693450fda79e4
GIT binary patch
literal 2844
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
literal 0
HcmV?d00001
diff --git a/tests/testfile-macros-0xff.s b/tests/testfile-macros-0xff.s
new file mode 100644
index 0000000..7fdd35c
--- /dev/null
+++ b/tests/testfile-macros-0xff.s
@@ -0,0 +1,153 @@
+ .file "x.c"
+ .text
+.Ltext0:
+ .globl main
+ .type main, @function
+main:
+.LFB0:
+ .file 1 "x.c"
+ .loc 1 3 0
+ .cfi_startproc
+ pushq %rbp
+ .cfi_def_cfa_offset 16
+ .cfi_offset 6, -16
+ movq %rsp, %rbp
+ .cfi_def_cfa_register 6
+ .loc 1 3 0
+ movl $0, %eax
+ popq %rbp
+ .cfi_def_cfa 7, 8
+ ret
+ .cfi_endproc
+.LFE0:
+ .size main, .-main
+.Letext0:
+ .section .debug_info,"",@progbits
+.Ldebug_info0:
+ .long 0x52
+ .value 0x4
+ .long .Ldebug_abbrev0
+ .byte 0x8
+ .uleb128 0x1
+ .long .LASF244
+ .byte 0x4
+ .string "x.c"
+ .long .LASF245
+ .quad .Ltext0
+ .quad .Letext0-.Ltext0
+ .long .Ldebug_line0
+ .long .Ldebug_macro0
+ .uleb128 0x2
+ .long .LASF246
+ .byte 0x1
+ .byte 0x3
+ .long 0x4e
+ .quad .LFB0
+ .quad .LFE0-.LFB0
+ .uleb128 0x1
+ .byte 0x9c
+ .uleb128 0x3
+ .byte 0x4
+ .byte 0x5
+ .string "int"
+ .byte 0
+ .section .debug_abbrev,"",@progbits
+.Ldebug_abbrev0:
+ .uleb128 0x1
+ .uleb128 0x11
+ .byte 0x1
+ .uleb128 0x25
+ .uleb128 0xe
+ .uleb128 0x13
+ .uleb128 0xb
+ .uleb128 0x3
+ .uleb128 0x8
+ .uleb128 0x1b
+ .uleb128 0xe
+ .uleb128 0x11
+ .uleb128 0x1
+ .uleb128 0x12
+ .uleb128 0x7
+ .uleb128 0x10
+ .uleb128 0x17
+ .uleb128 0x2119
+ .uleb128 0x17
+ .byte 0
+ .byte 0
+ .uleb128 0x2
+ .uleb128 0x2e
+ .byte 0
+ .uleb128 0x3f
+ .uleb128 0x19
+ .uleb128 0x3
+ .uleb128 0xe
+ .uleb128 0x3a
+ .uleb128 0xb
+ .uleb128 0x3b
+ .uleb128 0xb
+ .uleb128 0x49
+ .uleb128 0x13
+ .uleb128 0x11
+ .uleb128 0x1
+ .uleb128 0x12
+ .uleb128 0x7
+ .uleb128 0x40
+ .uleb128 0x18
+ .uleb128 0x2117
+ .uleb128 0x19
+ .byte 0
+ .byte 0
+ .uleb128 0x3
+ .uleb128 0x24
+ .byte 0
+ .uleb128 0xb
+ .uleb128 0xb
+ .uleb128 0x3e
+ .uleb128 0xb
+ .uleb128 0x3
+ .uleb128 0x8
+ .byte 0
+ .byte 0
+ .byte 0
+ .section .debug_aranges,"",@progbits
+ .long 0x2c
+ .value 0x2
+ .long .Ldebug_info0
+ .byte 0x8
+ .byte 0
+ .value 0
+ .value 0
+ .quad .Ltext0
+ .quad .Letext0-.Ltext0
+ .quad 0
+ .quad 0
+ .section .debug_macro,"",@progbits
+.Ldebug_macro0:
+ .value 0x4
+ .byte 0x6
+ .long .Ldebug_line0
+ .byte 0x1
+ .byte 0xff
+ .uleb128 0
+ .byte 0xff
+ .byte 0x3
+ .uleb128 0
+ .uleb128 0x1
+ .byte 0x5
+ .uleb128 0x1
+ .long .LASF243
+ .byte 0x4
+ .byte 0
+ .section .debug_line,"",@progbits
+.Ldebug_line0:
+ .section .debug_str,"MS",@progbits,1
+.LASF245:
+ .string "/home/petr/proj/elfutils/master/elfutils"
+.LASF244:
+ .string "GNU C++ 4.9.0 20140422 (Red Hat 4.9.0-1) -mtune=generic -march=x86-64 -g3"
+.LASF243:
+ .string "FOO 0"
+.LASF246:
+ .string "main"
+ .ident "GCC: (GNU) 4.9.0 20140422 (Red Hat 4.9.0-1)"
+ .section .note.GNU-stack,"",@progbits
--
2.1.0
9 years, 4 months
Announcing dwgrep 0.1
by Petr Machata
I am happy to announce the first release of dwgrep, a tool for querying
Dwarf graphs.
Dwgrep is useful for looking up particular patterns in Dwarf files.
They might be nonsensical or sub-optimal constructs produced as a result
of a compiler bug, rare constructs, or some sort of relationship that
you are interested in. E.g. it is fairly straghtforward to write a
few-liner to generate class inheritance information, to find underlying
type of typedefs, to find functions that pass structure parameters by
value, etc.
For more information, documentation and a tutorial, please visit:
http://pmachata.github.io/dwgrep/index.html
Current release tarball is available here:
https://github.com/pmachata/dwgrep/archive/0.1/dwgrep-0.1.tar.gz
Dwgrep contains a C API, but it should be considered experimental.
Correspondingly there's no documentation. This is only 0.1 after all.
There is no mailing list. Please contact me directly at
pmachata(a){redhat,gmail}.com, or file issues at github issue tracker:
https://github.com/pmachata/dwgrep/issues
Thank you,
Petr
9 years, 4 months
[PATCH] readelf: Fix overflow check in handle_sysv_hash64.
by Mark Wielaard
Since all values are 64bit, not 32bit as in other hashes, we need to
explicitly check for overflow.
Signed-off-by: Mark Wielaard <mjw(a)redhat.com>
---
src/ChangeLog | 4 ++++
src/readelf.c | 6 ++++--
2 files changed, 8 insertions(+), 2 deletions(-)
diff --git a/src/ChangeLog b/src/ChangeLog
index d3828d9..0819c1e 100644
--- a/src/ChangeLog
+++ b/src/ChangeLog
@@ -1,3 +1,7 @@
+2014-11-30 Mark Wielaard <mjw(a)redhat.com>
+
+ * readelf.c (handle_sysv_hash64): Fix overflow check.
+
2014-11-28 Mark Wielaard <mjw(a)redhat.com>
* readelf.c (handle_relocs_rel): Don't reuse destshdr to store
diff --git a/src/readelf.c b/src/readelf.c
index 69ae5d0..89b1754 100644
--- a/src/readelf.c
+++ b/src/readelf.c
@@ -3055,8 +3055,10 @@ handle_sysv_hash64 (Ebl *ebl, Elf_Scn *scn, GElf_Shdr *shdr, size_t shstrndx)
Elf64_Xword nbucket = ((Elf64_Xword *) data->d_buf)[0];
Elf64_Xword nchain = ((Elf64_Xword *) data->d_buf)[1];
- uint64_t used_buf = (2ULL + nchain + nbucket) * sizeof (Elf64_Xword);
- if (used_buf > data->d_size)
+ uint64_t maxwords = data->d_size / sizeof (Elf64_Xword);
+ if (maxwords < 2
+ || maxwords - 2 < nbucket
+ || maxwords - 2 - nbucket < nchain)
goto invalid_data;
Elf64_Xword *bucket = &((Elf64_Xword *) data->d_buf)[2];
--
1.9.3
9 years, 5 months
[PATCH] libdwfl: Check relocations don't overlap ELF ehdr, shdrs or phdrs.
by Mark Wielaard
American Fuzzy Lop (afl-fuzz) has an habit of generating ELF files
with relocations that when applied (or removed/cleared) change one
of the in-memory ELF headers. There does not seem to be a valid reason
for having section data that contain relocations or to which relocations
are applied to overlap with one of the headers.
If either the section that needs the relocation applied, or the
section that the relocations come from overlap one of the ehdrs,
shdrs or phdrs data then refuse to do the relocations. We update
both section data. It isn't illegal for ELF section data to overlap
the header data, but updating the (relocation) data might corrupt
the in-memory libelf headers causing strange corruptions or errors.
Also check offset + size of a relocation doesn't overflow.
Signed-off-by: Mark Wielaard <mjw(a)redhat.com>
---
libdwfl/ChangeLog | 6 ++++++
libdwfl/relocate.c | 47 ++++++++++++++++++++++++++++++++++++++++++++++-
2 files changed, 52 insertions(+), 1 deletion(-)
diff --git a/libdwfl/ChangeLog b/libdwfl/ChangeLog
index 5876fcc..03faecf 100644
--- a/libdwfl/ChangeLog
+++ b/libdwfl/ChangeLog
@@ -1,3 +1,9 @@
+2014-11-29 Mark Wielaard <mjw(a)redhat.com>
+
+ * relocate.c (relocate_section): Check relocation section and target
+ section data don't overlap any of the ELF headers.
+ (relocate): Check for offset + size overflow.
+
2014-11-22 Mark Wielaard <mjw(a)redhat.com>
* link_map.c (consider_executable): Use elf_getphdrnum.
diff --git a/libdwfl/relocate.c b/libdwfl/relocate.c
index 52b7b5e..4fc0956 100644
--- a/libdwfl/relocate.c
+++ b/libdwfl/relocate.c
@@ -297,6 +297,51 @@ relocate_section (Dwfl_Module *mod, Elf *relocated, const GElf_Ehdr *ehdr,
if (tdata == NULL)
return DWFL_E_LIBELF;
+ /* If either the section that needs the relocation applied, or the
+ section that the relocations come from overlap one of the ehdrs,
+ shdrs or phdrs data then we refuse to do the relocations. It
+ isn't illegal for ELF section data to overlap the header data,
+ but updating the (relocation) data might corrupt the in-memory
+ libelf headers causing strange corruptions or errors. */
+ if (unlikely (shdr->sh_offset < ehdr->e_ehsize
+ || tshdr->sh_offset < ehdr->e_ehsize))
+ return DWFL_E_BADELF;
+
+ GElf_Off shdr_start = ehdr->e_shoff;
+ size_t shnums;
+ if (elf_getshdrnum (relocated, &shnums) < 0)
+ return DWFL_E_LIBELF;
+ /* Overflows will have been checked by elf_getshdrnum/get|rawdata. */
+ GElf_Off shdr_end = shdr_start + shnums * ehdr->e_shentsize;
+ if (unlikely ((shdr->sh_offset >= shdr_start
+ && shdr->sh_offset < shdr_end)
+ || (shdr->sh_offset + shdr->sh_size >= shdr_start
+ && shdr->sh_offset + shdr->sh_size < shdr_end)
+ || (tshdr->sh_offset >= shdr_start
+ && tshdr->sh_offset < shdr_end)
+ || (tshdr->sh_offset + tshdr->sh_size >= shdr_start
+ && tshdr->sh_offset + tshdr->sh_size < shdr_end)))
+ return DWFL_E_BADELF;
+
+ GElf_Off phdr_start = ehdr->e_phoff;
+ size_t phnums;
+ if (elf_getphdrnum (relocated, &phnums) < 0)
+ return DWFL_E_LIBELF;
+ if (phdr_start != 0 && phnums != 0)
+ {
+ /* Overflows will have been checked by elf_getphdrnum/get|rawdata. */
+ GElf_Off phdr_end = phdr_start + phnums * ehdr->e_phentsize;
+ if (unlikely ((shdr->sh_offset >= phdr_start
+ && shdr->sh_offset < phdr_end)
+ || (shdr->sh_offset + shdr->sh_size >= phdr_start
+ && shdr->sh_offset + shdr->sh_size < phdr_end)
+ || (tshdr->sh_offset >= phdr_start
+ && tshdr->sh_offset < phdr_end)
+ || (tshdr->sh_offset + tshdr->sh_size >= phdr_start
+ && tshdr->sh_offset + tshdr->sh_size < phdr_end)))
+ return DWFL_E_BADELF;
+ }
+
/* Apply one relocation. Returns true for any invalid data. */
Dwfl_Error relocate (GElf_Addr offset, const GElf_Sxword *addend,
int rtype, int symndx)
@@ -365,7 +410,7 @@ relocate_section (Dwfl_Module *mod, Elf *relocated, const GElf_Ehdr *ehdr,
return DWFL_E_BADRELTYPE;
}
- if (offset + size > tdata->d_size)
+ if (offset > tdata->d_size || tdata->d_size - offset < size)
return DWFL_E_BADRELOFF;
#define DO_TYPE(NAME, Name) GElf_##Name Name;
--
1.9.3
9 years, 5 months
[PATCH] readelf: Always print INVALID SECTION if destshdr is NULL for relocation
by Mark Wielaard
We already checked this in all other cases except for the special case
of relocs in statically_linked executables. Found with afl.
Signed-off-by: Mark Wielaard <mjw(a)redhat.com>
---
src/ChangeLog | 6 +++++
src/readelf.c | 77 +++++++++++++++++++++++++++++++++++++++++------------------
2 files changed, 60 insertions(+), 23 deletions(-)
diff --git a/src/ChangeLog b/src/ChangeLog
index a6d18b5..072146a 100644
--- a/src/ChangeLog
+++ b/src/ChangeLog
@@ -1,3 +1,9 @@
+2014-11-28 Mark Wielaard <mjw(a)redhat.com>
+
+ * readelf.c (handle_relocs_rel): Print INVALID SECTION if destshdr
+ is NULL also for statically_linked relocations.
+ (handle_relocs_rela): Likewise.
+
2014-11-26 Mark Wielaard <mjw(a)redhat.com>
* readelf.c (print_debug_aranges_section): Cast Dwarf_Word length
diff --git a/src/readelf.c b/src/readelf.c
index cd15e4c..6060851 100644
--- a/src/readelf.c
+++ b/src/readelf.c
@@ -1857,17 +1857,32 @@ handle_relocs_rel (Ebl *ebl, GElf_Ehdr *ehdr, Elf_Scn *scn, GElf_Shdr *shdr)
}
if (is_statically_linked > 0 && shdr->sh_link == 0)
- printf ("\
- %#0*" PRIx64 " %-20s %*s %s\n",
- class == ELFCLASS32 ? 10 : 18, rel->r_offset,
- ebl_reloc_type_check (ebl, GELF_R_TYPE (rel->r_info))
- /* Avoid the leading R_ which isn't carrying any
- information. */
- ? ebl_reloc_type_name (ebl, GELF_R_TYPE (rel->r_info),
- buf, sizeof (buf)) + 2
- : gettext ("<INVALID RELOC>"),
- class == ELFCLASS32 ? 10 : 18, "",
- elf_strptr (ebl->elf, shstrndx, destshdr->sh_name));
+ {
+ if (unlikely (destshdr == NULL))
+ printf (" %#0*" PRIx64 " %-20s %*s <%s %ld>\n",
+ class == ELFCLASS32 ? 10 : 18, rel->r_offset,
+ ebl_reloc_type_check (ebl, GELF_R_TYPE (rel->r_info))
+ /* Avoid the leading R_ which isn't carrying any
+ information. */
+ ? ebl_reloc_type_name (ebl, GELF_R_TYPE (rel->r_info),
+ buf, sizeof (buf)) + 2
+ : gettext ("<INVALID RELOC>"),
+ class == ELFCLASS32 ? 10 : 18, "",
+ gettext ("INVALID SECTION"),
+ (long int) (sym->st_shndx == SHN_XINDEX
+ ? xndx : sym->st_shndx));
+ else
+ printf (" %#0*" PRIx64 " %-20s %*s %s\n",
+ class == ELFCLASS32 ? 10 : 18, rel->r_offset,
+ ebl_reloc_type_check (ebl, GELF_R_TYPE (rel->r_info))
+ /* Avoid the leading R_ which isn't carrying any
+ information. */
+ ? ebl_reloc_type_name (ebl, GELF_R_TYPE (rel->r_info),
+ buf, sizeof (buf)) + 2
+ : gettext ("<INVALID RELOC>"),
+ class == ELFCLASS32 ? 10 : 18, "",
+ elf_strptr (ebl->elf, shstrndx, destshdr->sh_name));
+ }
else
printf (" %#0*" PRIx64 " %-20s <%s %ld>\n",
class == ELFCLASS32 ? 10 : 18, rel->r_offset,
@@ -2045,18 +2060,34 @@ handle_relocs_rela (Ebl *ebl, GElf_Ehdr *ehdr, Elf_Scn *scn, GElf_Shdr *shdr)
}
if (is_statically_linked > 0 && shdr->sh_link == 0)
- printf ("\
- %#0*" PRIx64 " %-15s %*s %#6" PRIx64 " %s\n",
- class == ELFCLASS32 ? 10 : 18, rel->r_offset,
- ebl_reloc_type_check (ebl, GELF_R_TYPE (rel->r_info))
- /* Avoid the leading R_ which isn't carrying any
- information. */
- ? ebl_reloc_type_name (ebl, GELF_R_TYPE (rel->r_info),
- buf, sizeof (buf)) + 2
- : gettext ("<INVALID RELOC>"),
- class == ELFCLASS32 ? 10 : 18, "",
- rel->r_addend,
- elf_strptr (ebl->elf, shstrndx, destshdr->sh_name));
+ {
+ if (unlikely (destshdr == NULL))
+ printf (" %#0*" PRIx64 " %-15s %*s %#6" PRIx64 " <%s %ld>\n",
+ class == ELFCLASS32 ? 10 : 18, rel->r_offset,
+ ebl_reloc_type_check (ebl, GELF_R_TYPE (rel->r_info))
+ /* Avoid the leading R_ which isn't carrying any
+ information. */
+ ? ebl_reloc_type_name (ebl, GELF_R_TYPE (rel->r_info),
+ buf, sizeof (buf)) + 2
+ : gettext ("<INVALID RELOC>"),
+ class == ELFCLASS32 ? 10 : 18, "",
+ rel->r_addend,
+ gettext ("INVALID SECTION"),
+ (long int) (sym->st_shndx == SHN_XINDEX
+ ? xndx : sym->st_shndx));
+ else
+ printf (" %#0*" PRIx64 " %-15s %*s %#6" PRIx64 " %s\n",
+ class == ELFCLASS32 ? 10 : 18, rel->r_offset,
+ ebl_reloc_type_check (ebl, GELF_R_TYPE (rel->r_info))
+ /* Avoid the leading R_ which isn't carrying any
+ information. */
+ ? ebl_reloc_type_name (ebl, GELF_R_TYPE (rel->r_info),
+ buf, sizeof (buf)) + 2
+ : gettext ("<INVALID RELOC>"),
+ class == ELFCLASS32 ? 10 : 18, "",
+ rel->r_addend,
+ elf_strptr (ebl->elf, shstrndx, destshdr->sh_name));
+ }
else
printf (" %#0*" PRIx64 " %-15s <%s %ld>\n",
class == ELFCLASS32 ? 10 : 18, rel->r_offset,
--
1.9.3
9 years, 5 months
[PATCH] Add configure --disable-textrelcheck option to enable CC=afl-fuzz on 32bit.
by Mark Wielaard
Using american fuzzy lop has found a lot of issues. It would be nice to
make using it a bit easier. Our build files make sure that no shared
library uses text relocations, but afl-gcc will insert some on i686.
http://www.akkadia.org/drepper/textrelocs.html
Now CC=afl-gcc ./configure --disable-textrelcheck will allow them so
that afl can instrument the libraries.
Don't try to use or install them except with afl-fuzz. When selinux is
enabled it might prevent loading the libraries with DT_TEXTREL set.
Signed-off-by: Mark Wielaard <mjw(a)redhat.com>
---
ChangeLog | 4 ++++
config/ChangeLog | 5 +++++
config/eu.am | 8 +++++++-
configure.ac | 5 +++++
libasm/ChangeLog | 4 ++++
libasm/Makefile.am | 2 +-
libdw/ChangeLog | 4 ++++
libdw/Makefile.am | 2 +-
libelf/ChangeLog | 4 ++++
libelf/Makefile.am | 2 +-
10 files changed, 36 insertions(+), 4 deletions(-)
diff --git a/ChangeLog b/ChangeLog
index 0947608..8eeaa08 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,7 @@
+2014-11-27 Mark Wielaard <mjw(a)redhat.com>
+
+ * configure.ac: Add --disable-textrelcheck.
+
2014-10-06 Mark Wielaard <mjw(a)redhat.com>
* NEWS: New section 0.161. Add dwarf_peel_type.
diff --git a/config/ChangeLog b/config/ChangeLog
index 9ebf14f..a05f552 100644
--- a/config/ChangeLog
+++ b/config/ChangeLog
@@ -1,3 +1,8 @@
+2014-11-27 Mark Wielaard <mjw(a)redhat.com>
+
+ * eu.am: Define textrel_msg, textrel_found and textrel_check based
+ on FATAL_TEXTREL.
+
2014-08-25 Mark Wielaard <mjw(a)redhat.com>
* elfutils.spec.in: Update for 0.160.
diff --git a/config/eu.am b/config/eu.am
index c3b00e0..faf8add 100644
--- a/config/eu.am
+++ b/config/eu.am
@@ -52,4 +52,10 @@ endif
CLEANFILES = *.gcno *.gcda
-textrel_check = if $(READELF) -d $@ | fgrep -q TEXTREL; then exit 1; fi
+textrel_msg = echo "WARNING: TEXTREL found in '$@'"
+if FATAL_TEXTREL
+textrel_found = $(textrel_msg); exit 1
+else
+textrel_found = $(textrel_msg)
+endif
+textrel_check = if $(READELF) -d $@ | fgrep -q TEXTREL; then $(textrel_found); fi
diff --git a/configure.ac b/configure.ac
index 76a172d..9bc83c5 100644
--- a/configure.ac
+++ b/configure.ac
@@ -212,6 +212,11 @@ AC_CHECK_LIB([stdc++], [__cxa_demangle], [dnl
AC_DEFINE([USE_DEMANGLE], [1], [Defined if demangling is enabled])])
AM_CONDITIONAL(DEMANGLE, test "$ac_cv_lib_stdcpp___cxa_demangle" = yes)
+AC_ARG_ENABLE([textrelcheck],
+AS_HELP_STRING([--disable-textrelcheck],
+ [Disable textrelcheck being a fatal error]))
+AM_CONDITIONAL(FATAL_TEXTREL, [test "x$enable_textrelcheck" != "xno"])
+
dnl The directories with content.
dnl Documentation.
diff --git a/libasm/ChangeLog b/libasm/ChangeLog
index 2613610..034a64d 100644
--- a/libasm/ChangeLog
+++ b/libasm/ChangeLog
@@ -1,3 +1,7 @@
+2014-01127 Mark Wielaard <mjw(a)redhat.com>
+
+ * Makefile.am (libasm.so): Use textrel_check.
+
2014-04-13 Mark Wielaard <mjw(a)redhat.com>
* Makefile.am: Remove !MUDFLAP conditions.
diff --git a/libasm/Makefile.am b/libasm/Makefile.am
index 3d6a2e5..88c2530 100644
--- a/libasm/Makefile.am
+++ b/libasm/Makefile.am
@@ -66,7 +66,7 @@ libasm.so$(EXEEXT): libasm_pic.a libasm.map
-Wl,--version-script,$(srcdir)/libasm.map,--no-undefined \
-Wl,--soname,$@.$(VERSION) \
../libebl/libebl.a ../libelf/libelf.so $(libasm_so_LDLIBS)
- if $(READELF) -d $@ | fgrep -q TEXTREL; then exit 1; fi
+ $(textrel_check)
ln -fs $@ $@.$(VERSION)
install: install-am libasm.so
diff --git a/libdw/ChangeLog b/libdw/ChangeLog
index c199707..bab02e5 100644
--- a/libdw/ChangeLog
+++ b/libdw/ChangeLog
@@ -1,5 +1,9 @@
2014-11-27 Mark Wielaard <mjw(a)redhat.com>
+ * Makefile.am (libdw.so): Use textrel_check.
+
+2014-11-27 Mark Wielaard <mjw(a)redhat.com>
+
* dwarf_getcfi_elf.c (getcfi_gnu_eh_frame): Initialize
search_table_entries and search_table_encoding.
diff --git a/libdw/Makefile.am b/libdw/Makefile.am
index 852d2c8..7a2a25d 100644
--- a/libdw/Makefile.am
+++ b/libdw/Makefile.am
@@ -113,7 +113,7 @@ libdw.so$(EXEEXT): $(srcdir)/libdw.map libdw_pic.a ../libdwelf/libdwelf_pic.a \
-Wl,--version-script,$<,--no-undefined \
-Wl,--whole-archive $(filter-out $<,$^) -Wl,--no-whole-archive\
-ldl $(zip_LIBS)
- if $(READELF) -d $@ | fgrep -q TEXTREL; then exit 1; fi
+ $(textrel_check)
ln -fs $@ $@.$(VERSION)
install: install-am libdw.so
diff --git a/libelf/ChangeLog b/libelf/ChangeLog
index 68fb0fc..e03ee09 100644
--- a/libelf/ChangeLog
+++ b/libelf/ChangeLog
@@ -1,3 +1,7 @@
+2014-11-27 Mark Wielaard <mjw(a)redhat.com>
+
+ * Makefile.am (libelf.so): Use textrel_check.
+
2014-11-23 Mark Wielaard <mjw(a)redhat.com>
* elf_getdata_rawchunk.c (elf_getdata_rawchunk): Change signed
diff --git a/libelf/Makefile.am b/libelf/Makefile.am
index 493e4ec..6888529 100644
--- a/libelf/Makefile.am
+++ b/libelf/Makefile.am
@@ -103,7 +103,7 @@ libelf.so$(EXEEXT): libelf_pic.a libelf.map
$(LINK) -shared -o $@ -Wl,--whole-archive,$<,--no-whole-archive \
-Wl,--version-script,$(srcdir)/libelf.map,--no-undefined \
-Wl,--soname,$@.$(VERSION),-z,defs,-z,relro $(libelf_so_LDLIBS)
- if $(READELF) -d $@ | fgrep -q TEXTREL; then exit 1; fi
+ $(textrel_check)
ln -fs $@ $@.$(VERSION)
install: install-am libelf.so
--
1.9.3
9 years, 5 months