On Sun, 2015-01-25 at 15:05 -0800, Josh Stone wrote: > On 01/25/2015 11:39 AM, Hanno Böck wrote: > > Please see attached file, which is a malformed (fuzzed) elf file that > > causes elfutil's readelf -e to hang, testet with the latest version > > 0.161. > > > > This was found with zzuf. > > You should be fuzzing with git master, as Mark is still making a lot of > commits for robustness.
Yes please. We made a lot of progress with elfutils 0.161, but we aren't completely there yet. Also if possible please do add new samples to the "Fuzzing elfutils -- various badness" bug report https://bugzilla.redhat.com/show_bug.cgi?id=1170810 so we don't forget about any fuzzing issue found. > That said, I can reproduce this on master. > > I'm not sure it's a hang, exactly, but it's a least a really huge loop. > :) I see it stuck in __libdwfl_addrsym::search_table with the end value > of 1073741862, from the call "search_table (1, first_global)". > > Debugging earlier, I see this comes from load_symtab, where the shdr is: > > (gdb) p *shdr > $4 = { > sh_name = 1, > sh_type = 2, > sh_flags = 0, > sh_addr = 0, > sh_offset = 7200, > sh_size = 1392, > sh_link = 33, > sh_info = 1073741862, > sh_addralign = 8, > sh_entsize = 24 > } > > These are used as: > *syments = shdr->sh_size / shdr->sh_entsize; > *first_global = shdr->sh_info; > > I guess it should be an error for first_global to be out of range, or at > least clamp it to at most syments. And we do that in find_symtab when we find the normal symtab or the aux symtab. But in this case after we found the symtab we detect something is fishy with the string table/shdrs, so we discard the result and fall back to find_dynsym to get a backup symbol table through phdrs. Which succeeds. dynsym only has global syms, so we don't need to set first_global because it is initialized to zero. But... we forgot to clear the original first_global we found when we discarded the result... oops. How does the following fix look?
From 6e576f095e6f3bb810e6388ed8e606eacb318b67 Mon Sep 17 00:00:00 2001 From: Mark Wielaard <[email protected]> Date: Mon, 26 Jan 2015 16:34:57 +0100 Subject: [PATCH] libdwfl: Clear symtab result on error before using find_dynsym fallback. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit find_dynsym could succeed after find_symtab failed but had already set up symdata, syments and first_global. find_dynsym would not set or clear first_global since all syms in dynsym are global. Causing lots of failing lookups when calling __libdwfl_addrsym if first_global was some huge bogus value. Reported-by: Hanno Böck <[email protected]> Signed-off-by: Mark Wielaard <[email protected]> --- libdwfl/ChangeLog | 5 +++++ libdwfl/dwfl_module_getdwarf.c | 3 +++ 2 files changed, 8 insertions(+) diff --git a/libdwfl/ChangeLog b/libdwfl/ChangeLog index 5a97578..d40dbae 100644 --- a/libdwfl/ChangeLog +++ b/libdwfl/ChangeLog @@ -1,3 +1,8 @@ +2015-01-26 Mark Wielaard <[email protected]> + + * dwfl_module_getdwarf.c (find_symtab): Explicitly clear symdata, + syments and first_global on elferr before calling find_dynsym. + 2014-12-27 Mark Wielaard <[email protected]> * dwfl_module_getsrc.c (dwfl_module_getsrc): Never match a line that diff --git a/libdwfl/dwfl_module_getdwarf.c b/libdwfl/dwfl_module_getdwarf.c index 494407d..a31898a 100644 --- a/libdwfl/dwfl_module_getdwarf.c +++ b/libdwfl/dwfl_module_getdwarf.c @@ -1083,6 +1083,9 @@ find_symtab (Dwfl_Module *mod) if (elf_strptr (mod->symfile->elf, strshndx, 0) == NULL) { elferr: + mod->symdata = NULL; + mod->syments = 0; + mod->first_global = 0; mod->symerr = DWFL_E (LIBELF, elf_errno ()); goto aux_cleanup; /* This cleans up some more and tries find_dynsym. */ } -- 1.8.3.1
