This is the mail archive of the
elfutils-devel@sourceware.org
mailing list for the elfutils project.
[PATCH] libdw: Check terminating NUL byte in dwarf_getsrclines for dir/file table.
- From: Mark Wielaard <mark at klomp dot org>
- To: elfutils-devel at sourceware dot org
- Cc: Mark Wielaard <mark at klomp dot org>
- Date: Sun, 20 Jan 2019 22:16:03 +0100
- Subject: [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 <mark@klomp.org>
---
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 <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 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 <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 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