diff options
author | Mark Wielaard <mark@klomp.org> | 2019-01-20 22:10:18 +0100 |
---|---|---|
committer | Mark Wielaard <mark@klomp.org> | 2019-01-22 18:12:38 +0100 |
commit | 2562759d6fe5b364fe224852e64e8bda39eb2e35 (patch) | |
tree | 40b5cf97caffae1248cd39305434e1dbf914527d | |
parent | da5c5336a1eaf519de246f7d9f0f5585e1d4ac59 (diff) | |
download | elfutils-2562759d6fe5b364fe224852e64e8bda39eb2e35.tar.gz |
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 <mark@klomp.org>
-rw-r--r-- | libdw/ChangeLog | 5 | ||||
-rw-r--r-- | libdw/dwarf_getsrclines.c | 11 | ||||
-rw-r--r-- | src/ChangeLog | 5 | ||||
-rw-r--r-- | src/readelf.c | 8 |
4 files changed, 24 insertions, 5 deletions
diff --git a/libdw/ChangeLog b/libdw/ChangeLog index 44405d75..ff3880df 100644 --- a/libdw/ChangeLog +++ b/libdw/ChangeLog @@ -1,3 +1,8 @@ +2019-01-20 Mark Wielaard <mark@klomp.org> + + * dwarf_getsrclines.c (read_srclines): Check terminating NUL byte + for dir and file lists. + 2018-10-23 Mark Wielaard <mark@klomp.org> * dwarf_child.c (__libdw_find_attr): Initialize readp to NULL. diff --git a/libdw/dwarf_getsrclines.c b/libdw/dwarf_getsrclines.c index 1432b1db..75ec9c79 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 c0455f1c..4ad12a96 100644 --- a/src/ChangeLog +++ b/src/ChangeLog @@ -1,3 +1,8 @@ +2019-01-20 Mark Wielaard <mark@klomp.org> + + * readelf.c (print_debug_line_section): Check terminating NUL byte + for dir and file tables. + 2019-01-16 Mark Wielaard <mark@klomp.org> * readelf (handle_core_note): Pass desc to ebl_core_note. diff --git a/src/readelf.c b/src/readelf.c index 71651e09..6bad3bfe 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; } |