[PATCHv1 1/2] libdwfl: specify optional sysroot to search for shared libraries
When searching the list of modules in a core file, if the core was generated on a different system to the current one, we need to look in a sysroot for the various shared objects. For example, we might be looking at a core file from an ARM system using elfutils running on an x86 host. This change adds a new function, dwfl_set_sysroot(), which then gets used when searching for libraries. Signed-off-by: Luke Diamand --- libdw/libdw.map| 7 ++- libdwfl/libdwfl.h | 5 + libdwfl/libdwflP.h | 1 + libdwfl/link_map.c | 25 +++-- 4 files changed, 35 insertions(+), 3 deletions(-) diff --git a/libdw/libdw.map b/libdw/libdw.map index 55482d58..43a9de2e 100644 --- a/libdw/libdw.map +++ b/libdw/libdw.map @@ -360,4 +360,9 @@ ELFUTILS_0.173 { ELFUTILS_0.175 { global: dwelf_elf_begin; -} ELFUTILS_0.173; \ No newline at end of file +} ELFUTILS_0.173; + +ELFUTILS_0.176 { + global: +dwfl_set_sysroot; +} ELFUTILS_0.175; diff --git a/libdwfl/libdwfl.h b/libdwfl/libdwfl.h index a0c1d357..c11e2f24 100644 --- a/libdwfl/libdwfl.h +++ b/libdwfl/libdwfl.h @@ -807,6 +807,11 @@ int dwfl_getthread_frames (Dwfl *dwfl, pid_t tid, bool dwfl_frame_pc (Dwfl_Frame *state, Dwarf_Addr *pc, bool *isactivation) __nonnull_attribute__ (1, 2); +/* Set the sysroot to use when searching for shared libraries. If not + specified, search in the system root. */ +void dwfl_set_sysroot (Dwfl *dwfl, const char *sysroot) + __nonnull_attribute__ (1); + #ifdef __cplusplus } #endif diff --git a/libdwfl/libdwflP.h b/libdwfl/libdwflP.h index 941a8b66..993a0e7c 100644 --- a/libdwfl/libdwflP.h +++ b/libdwfl/libdwflP.h @@ -138,6 +138,7 @@ struct Dwfl int lookup_tail_ndx; struct Dwfl_User_Core *user_core; + const char *sysroot; /* sysroot, or NULL to search standard system paths */ }; #define OFFLINE_REDZONE0x1 diff --git a/libdwfl/link_map.c b/libdwfl/link_map.c index 29307c74..0fae680d 100644 --- a/libdwfl/link_map.c +++ b/libdwfl/link_map.c @@ -388,8 +388,21 @@ report_r_debug (uint_fast8_t elfclass, uint_fast8_t elfdata, if (name != NULL) { /* This code is mostly inlined dwfl_report_elf. */ - // XXX hook for sysroot - int fd = open (name, O_RDONLY); + char *path_name; + const char *sysroot = dwfl->sysroot; + int rc; + + /* don't look in the sysroot if the path is already inside the sysroot */ + bool name_in_sysroot = strncmp(name, sysroot, strlen(sysroot)) == 0; + + if (!name_in_sysroot && sysroot) + rc = asprintf(&path_name, "%s/%s", sysroot, name); + else + rc = asprintf(&path_name, "%s", name); + if (unlikely(rc == -1)) + return release_buffer(-1); + + int fd = open (path_name, O_RDONLY); if (fd >= 0) { Elf *elf; @@ -471,6 +484,7 @@ report_r_debug (uint_fast8_t elfclass, uint_fast8_t elfdata, close (fd); } } + free(path_name); } if (mod != NULL) @@ -1037,3 +1051,10 @@ dwfl_link_map_report (Dwfl *dwfl, const void *auxv, size_t auxv_size, &integrated_memory_callback, &mcb, r_debug_info); } INTDEF (dwfl_link_map_report) + +void +dwfl_set_sysroot (Dwfl *dwfl, const char *sysroot) +{ + dwfl->sysroot = sysroot; +} +INTDEF (dwfl_set_sysroot) -- 2.20.1
[PATCHv1 2/2] eu-stack: add support for sysroot option
Use the dwfl_set_sysroot() function to set the sysroot to be used when analysing a core: e.g. $ eu-stack --core core --sysroot /path/to/sysroot -e crashing_prog Signed-off-by: Luke Diamand --- src/stack.c | 9 + 1 file changed, 9 insertions(+) diff --git a/src/stack.c b/src/stack.c index c5f347e1..5a58cc1b 100644 --- a/src/stack.c +++ b/src/stack.c @@ -73,6 +73,7 @@ static int core_fd = -1; static Elf *core = NULL; static const char *exec = NULL; static char *debuginfo_path = NULL; +static const char *sysroot = NULL; static const Dwfl_Callbacks proc_callbacks = { @@ -554,6 +555,10 @@ parse_opt (int key, char *arg __attribute__ ((unused)), show_modules = true; break; +case 'S': + sysroot = arg; + break; + case ARGP_KEY_END: if (core == NULL && exec != NULL) argp_error (state, @@ -587,6 +592,8 @@ parse_opt (int key, char *arg __attribute__ ((unused)), dwfl = dwfl_begin (&core_callbacks); if (dwfl == NULL) error (EXIT_BAD, 0, "dwfl_begin: %s", dwfl_errmsg (-1)); + if (sysroot) +dwfl_set_sysroot(dwfl, sysroot); if (dwfl_core_file_report (dwfl, core, exec) < 0) error (EXIT_BAD, 0, "dwfl_core_file_report: %s", dwfl_errmsg (-1)); } @@ -670,6 +677,8 @@ main (int argc, char **argv) N_("Show at most MAXFRAMES per thread (default 256, use 0 for unlimited)"), 0 }, { "list-modules", 'l', NULL, 0, N_("Show module memory map with build-id, elf and debug files detected"), 0 }, + { "sysroot", 'S', "sysroot", 0, + N_("Set the sysroot to search for libraries referenced from the core file"), 0 }, { NULL, 0, NULL, 0, NULL, 0 } }; -- 2.20.1
[PATCHv1 0/2] specify a sysroot to search when examining a core file
Following on from this discussion: https://sourceware.org/ml/elfutils-devel/2018-q4/msg00224.html This patch adds a new API to specify a sysroot, and extends eu-stack to use it with a new command line option. I have been experimenting with this on various ARM-based platforms, currently using a virt-qemu platform built from buildroot. Luke Diamand (2): libdwfl: specify optional sysroot to search for shared libraries eu-stack: add support for sysroot option libdw/libdw.map| 7 ++- libdwfl/libdwfl.h | 5 + libdwfl/libdwflP.h | 1 + libdwfl/link_map.c | 25 +++-- src/stack.c| 9 + 5 files changed, 44 insertions(+), 3 deletions(-) -- 2.20.1
MIPS Elfutils support?
Hi! I was hoping to use elfutils on some MIPS core files. So I was wondering what the status is? There is a patch in Debian (apparently originally from RedHat?) here: https://sources.debian.org/src/elfutils/0.175-2/debian/patches/mips_backend.diff/ That's not in the mainline code though, and also lacks unwind support (?). I also have a small patch needed to pick up the shared library process map - instead of using DT_DEBUG, MIPS targets use DT_MIPS_RLD_MAP in core files. Thanks Luke
[PATCH] libdw: Check terminating NUL byte in dwarf_getsrclines for dir/file table.
For DWARF version < 5 the .debug_line directory and file tables consist of a terminating NUL byte after all strings. The code used to just skip this without checking it actually existed. This could case a spurious read past the end of data. Fix the same issue in readelf. https://sourceware.org/bugzilla/show_bug.cgi?id=24102 Signed-off-by: Mark Wielaard --- libdw/ChangeLog | 5 + libdw/dwarf_getsrclines.c | 11 --- src/ChangeLog | 5 + src/readelf.c | 8 ++-- 4 files changed, 24 insertions(+), 5 deletions(-) diff --git a/libdw/ChangeLog b/libdw/ChangeLog index 44405d75e..ff3880df1 100644 --- a/libdw/ChangeLog +++ b/libdw/ChangeLog @@ -1,3 +1,8 @@ +2019-01-20 Mark Wielaard + + * dwarf_getsrclines.c (read_srclines): Check terminating NUL byte + for dir and file lists. + 2018-10-23 Mark Wielaard * dwarf_child.c (__libdw_find_attr): Initialize readp to NULL. diff --git a/libdw/dwarf_getsrclines.c b/libdw/dwarf_getsrclines.c index 1432b1db7..75ec9c791 100644 --- a/libdw/dwarf_getsrclines.c +++ b/libdw/dwarf_getsrclines.c @@ -315,7 +315,7 @@ read_srclines (Dwarf *dbg, if (version < 5) { const unsigned char *dirp = linep; - while (*dirp != 0) + while (dirp < lineendp && *dirp != 0) { uint8_t *endp = memchr (dirp, '\0', lineendp - dirp); if (endp == NULL) @@ -323,6 +323,8 @@ read_srclines (Dwarf *dbg, ++ndirs; dirp = endp + 1; } + if (dirp >= lineendp || *dirp != '\0') + goto invalid_data; ndirs = ndirs + 1; /* There is always the "unknown" dir. */ } else @@ -392,11 +394,12 @@ read_srclines (Dwarf *dbg, { dirarray[n].dir = (char *) linep; uint8_t *endp = memchr (linep, '\0', lineendp - linep); - assert (endp != NULL); + assert (endp != NULL); // Checked above when calculating ndirlist. dirarray[n].len = endp - linep; linep = endp + 1; } /* Skip the final NUL byte. */ + assert (*linep == '\0'); // Checked above when calculating ndirlist. ++linep; } else @@ -471,7 +474,7 @@ read_srclines (Dwarf *dbg, { if (unlikely (linep >= lineendp)) goto invalid_data; - while (*linep != 0) + while (linep < lineendp && *linep != '\0') { struct filelist *new_file = NEW_FILE (); @@ -527,6 +530,8 @@ read_srclines (Dwarf *dbg, goto invalid_data; get_uleb128 (new_file->info.length, linep, lineendp); } + if (linep >= lineendp || *linep != '\0') + goto invalid_data; /* Skip the final NUL byte. */ ++linep; } diff --git a/src/ChangeLog b/src/ChangeLog index c0455f1cf..4ad12a969 100644 --- a/src/ChangeLog +++ b/src/ChangeLog @@ -1,3 +1,8 @@ +2019-01-20 Mark Wielaard + + * readelf.c (print_debug_line_section): Check terminating NUL byte + for dir and file tables. + 2019-01-16 Mark Wielaard * readelf (handle_core_note): Pass desc to ebl_core_note. diff --git a/src/readelf.c b/src/readelf.c index 71651e091..6bad3bfe9 100644 --- a/src/readelf.c +++ b/src/readelf.c @@ -8444,7 +8444,7 @@ print_debug_line_section (Dwfl_Module *dwflmod, Ebl *ebl, GElf_Ehdr *ehdr, } else { - while (*linep != 0) + while (linep < lineendp && *linep != 0) { unsigned char *endp = memchr (linep, '\0', lineendp - linep); if (unlikely (endp == NULL)) @@ -8454,6 +8454,8 @@ print_debug_line_section (Dwfl_Module *dwflmod, Ebl *ebl, GElf_Ehdr *ehdr, linep = endp + 1; } + if (linep >= lineendp || *linep != 0) + goto invalid_unit; /* Skip the final NUL byte. */ ++linep; } @@ -8523,7 +8525,7 @@ print_debug_line_section (Dwfl_Module *dwflmod, Ebl *ebl, GElf_Ehdr *ehdr, else { puts (gettext (" Entry Dir Time Size Name")); - for (unsigned int cnt = 1; *linep != 0; ++cnt) + for (unsigned int cnt = 1; linep < lineendp && *linep != 0; ++cnt) { /* First comes the file name. */ char *fname = (char *) linep; @@ -8553,6 +8555,8 @@ print_debug_line_section (Dwfl_Module *dwflmod, Ebl *ebl, GElf_Ehdr *ehdr, printf (" %-5u %-5u %-9u %-9u %s\n", cnt, diridx, mtime, fsize, fname); } + if (linep >= lineendp || *linep != '\0') + goto invalid_unit; /* Skip the final NUL byte. */ ++linep; } -- 2.20.1
[Bug libdw/24102] A Heap-buffer-overflow problem was discovered in the function read_srclines in dwarf_getsrclines.c in libdw
https://sourceware.org/bugzilla/show_bug.cgi?id=24102 Mark Wielaard changed: What|Removed |Added Status|UNCONFIRMED |ASSIGNED Last reconfirmed||2019-01-20 CC||mark at klomp dot org Component|backends|libdw Ever confirmed|0 |1 --- Comment #3 from Mark Wielaard --- Nice find. Replicated using valgrind on the reproducers. We would assume the dir and file tables were properly terminated by a NUL byte. But if that wasn't actually there we could read one byte past the end of the data buffer. A similar issue was in readelf.c (although it is harder to trigger since readlelf has more sanity checks before it can get to this point). Proposed fix: https://sourceware.org/ml/elfutils-devel/2019-q1/msg00068.html -- You are receiving this mail because: You are on the CC list for the bug.
[PATCH] libdwfl: Sanity check partial core file dyn data read.
When reading the dyn data from the core file check if we got everything, or just part of the data. https://sourceware.org/bugzilla/show_bug.cgi?id=24103 Signed-off-by: Mark Wielaard --- libdwfl/ChangeLog| 5 + libdwfl/dwfl_segment_report_module.c | 6 ++ 2 files changed, 11 insertions(+) diff --git a/libdwfl/ChangeLog b/libdwfl/ChangeLog index c295fa7d6..de45e7f19 100644 --- a/libdwfl/ChangeLog +++ b/libdwfl/ChangeLog @@ -1,3 +1,8 @@ +2019-01-20 Mark Wielaard + + * dwfl_segment_report_module.c (dwfl_segment_report_module): Check + dyn_filesz vs dyn_data_size after read_portion call. + 2019-01-16 Mark Wielaard * linux-core-attach.c (core_next_thread): Pass desc to ebl_core_note. diff --git a/libdwfl/dwfl_segment_report_module.c b/libdwfl/dwfl_segment_report_module.c index 0d633ffee..f6ad39b3e 100644 --- a/libdwfl/dwfl_segment_report_module.c +++ b/libdwfl/dwfl_segment_report_module.c @@ -783,6 +783,12 @@ dwfl_segment_report_module (Dwfl *dwfl, int ndx, const char *name, if (dyn_filesz != 0 && dyn_filesz % dyn_entsize == 0 && ! read_portion (&dyn_data, &dyn_data_size, dyn_vaddr, dyn_filesz)) { + /* dyn_data_size will be zero if we got everything from the initial + buffer, otherwise it will be the size of the new buffer that + could be read. */ + if (dyn_data_size != 0) + dyn_filesz = dyn_data_size; + void *dyns = malloc (dyn_filesz); Elf32_Dyn (*d32)[dyn_filesz / sizeof (Elf32_Dyn)] = dyns; Elf64_Dyn (*d64)[dyn_filesz / sizeof (Elf64_Dyn)] = dyns; -- 2.20.1
Re: [PATCHv1 1/2] libdwfl: specify optional sysroot to search for shared libraries
On Sun, Jan 20, 2019 at 03:00:45PM +, Luke Diamand wrote: > When searching the list of modules in a core file, if the core was > generated on a different system to the current one, we need to look > in a sysroot for the various shared objects. > > For example, we might be looking at a core file from an ARM system > using elfutils running on an x86 host. > > This change adds a new function, dwfl_set_sysroot(), which then > gets used when searching for libraries. [...] > --- a/libdwfl/link_map.c > +++ b/libdwfl/link_map.c > @@ -388,8 +388,21 @@ report_r_debug (uint_fast8_t elfclass, uint_fast8_t > elfdata, >if (name != NULL) > { > /* This code is mostly inlined dwfl_report_elf. */ > - // XXX hook for sysroot > - int fd = open (name, O_RDONLY); > + char *path_name; > + const char *sysroot = dwfl->sysroot; > + int rc; > + > + /* don't look in the sysroot if the path is already inside the > sysroot */ > + bool name_in_sysroot = strncmp(name, sysroot, strlen(sysroot)) == 0; Is sysroot guaranteed to be non-NULL at this point? If yes, is sysroot guaranteed to end with "/"? -- ldv signature.asc Description: PGP signature
[Bug libdw/24103] Invalid address Deference in elf64_xlatetom in elf32_xlatetom.c in libelf
https://sourceware.org/bugzilla/show_bug.cgi?id=24103 Mark Wielaard changed: What|Removed |Added Status|UNCONFIRMED |ASSIGNED Last reconfirmed||2019-01-20 CC||mark at klomp dot org Component|libelf |libdw Ever confirmed|0 |1 --- Comment #2 from Mark Wielaard --- Thanks. Replicated under valgrind. This is similar to https://sourceware.org/bugzilla/show_bug.cgi?id=23752 We need to check if we got all the dynamic data we expected from the file. Proposed patch: https://sourceware.org/ml/elfutils-devel/2019-q1/msg00070.html -- You are receiving this mail because: You are on the CC list for the bug.