Fix RHBZ#494858: fix bad address checks in core file support.
diff --git a/libdwfl/ChangeLog b/libdwfl/ChangeLog
index a2487ed..d2c823f 100644
--- a/libdwfl/ChangeLog
+++ b/libdwfl/ChangeLog
@@ -1,3 +1,13 @@
+2009-04-14 Roland McGrath <roland@redhat.com>
+
+ * dwfl_segment_report_module.c: Handle DT_STRTAB value being either
+ absolute (already adjusted in place) or needing load bias adjustment.
+
+ * core-file.c (dwfl_elf_phdr_memory_callback): Fix return value for
+ gelf_getphdr failure. Fix file size limit checks.
+
+ * dwfl_segment_report_module.c: Fix underflow in DYNSTRSZ check.
+
2009-04-08 Roland McGrath <roland@redhat.com>
* dwfl_module_getsym.c: Don't adjust for bias again after
diff --git a/libdwfl/core-file.c b/libdwfl/core-file.c
index bc881eb..77f208c 100644
--- a/libdwfl/core-file.c
+++ b/libdwfl/core-file.c
@@ -1,5 +1,5 @@
/* Core file handling.
- Copyright (C) 2008 Red Hat, Inc.
+ Copyright (C) 2008, 2009 Red Hat, Inc.
This file is part of Red Hat elfutils.
Red Hat elfutils is free software; you can redistribute it and/or modify
@@ -278,7 +278,7 @@
do
if (unlikely (gelf_getphdr (elf, ndx++, &phdr) == NULL))
- return true;
+ return false;
while (phdr.p_type != PT_LOAD
|| ((phdr.p_vaddr + phdr.p_memsz + align - 1) & -align) <= vaddr);
@@ -320,8 +320,14 @@
if (elf->map_address != NULL)
(void) more (elf->maximum_size - start);
- if (unlikely (end - start > elf->maximum_size))
- end = start + elf->maximum_size;
+ /* Make sure we don't look past the end of the actual file,
+ even if the headers tell us to. */
+ if (unlikely (end > elf->maximum_size))
+ end = elf->maximum_size;
+
+ /* If the file is too small, there is nothing at all to get. */
+ if (unlikely (start >= end))
+ return false;
if (elf->map_address != NULL)
{
diff --git a/libdwfl/dwfl_segment_report_module.c b/libdwfl/dwfl_segment_report_module.c
index a6639be..10787bd 100644
--- a/libdwfl/dwfl_segment_report_module.c
+++ b/libdwfl/dwfl_segment_report_module.c
@@ -519,13 +519,28 @@
size_t soname_size = 0;
if (dynstrsz != 0 && dynstr_vaddr != 0)
{
- /* We know the bounds of the .dynstr section. */
- dynstr_vaddr += bias;
+ /* We know the bounds of the .dynstr section.
+
+ The DYNSTR_VADDR pointer comes from the .dynamic section
+ (DT_STRTAB, detected above). Ordinarily the dynamic linker
+ will have adjusted this pointer in place so it's now an
+ absolute address. But sometimes .dynamic is read-only (in
+ vDSOs and odd architectures), and sometimes the adjustment
+ just hasn't happened yet in the memory image we looked at.
+ So treat DYNSTR_VADDR as an absolute address if it falls
+ within the module bounds, or try applying the phdr bias
+ when that adjusts it to fall within the module bounds. */
+
+ if ((dynstr_vaddr < module_start || dynstr_vaddr >= module_end)
+ && dynstr_vaddr + bias >= module_start
+ && dynstr_vaddr + bias < module_end)
+ dynstr_vaddr += bias;
+
if (unlikely (dynstr_vaddr + dynstrsz > module_end))
dynstrsz = 0;
/* Try to get the DT_SONAME string. */
- if (soname_stroff != 0 && soname_stroff < dynstrsz - 1
+ if (soname_stroff != 0 && soname_stroff + 1 < dynstrsz
&& ! read_portion (&soname, &soname_size,
dynstr_vaddr + soname_stroff, 0))
name = soname;
diff --git a/libdwfl/link_map.c b/libdwfl/link_map.c
index 30fb445..2d4d75f 100644
--- a/libdwfl/link_map.c
+++ b/libdwfl/link_map.c
@@ -585,7 +585,6 @@
(*memory_callback) (mod->dwfl, -1, &buffer, &buffer_available, 0, 0,
memory_callback_arg);
-
if (*elfclass == ELFCLASSNONE)
*elfclass = ehdr.e_ident[EI_CLASS];
else if (*elfclass != ehdr.e_ident[EI_CLASS])