summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRoland McGrath <roland@redhat.com>2010-05-06 00:52:51 -0700
committerRoland McGrath <roland@redhat.com>2010-05-06 00:52:51 -0700
commited431ddb74331f24add8c6d932ebed129c4385d8 (patch)
treefb400789e4956074d5f3fa29f20c83f4538995bd
parentb4bb301f76828bcbd84e467b736fedf44fe50317 (diff)
downloadelfutils-ed431ddb74331f24add8c6d932ebed129c4385d8.tar.gz
libdwfl: Refuse to fall back to an ELF file opened by name when that mismatches the module build ID.
-rw-r--r--libdwfl/ChangeLog14
-rw-r--r--libdwfl/dwfl_build_id_find_elf.c8
-rw-r--r--libdwfl/dwfl_error.c3
-rw-r--r--libdwfl/dwfl_module_getdwarf.c45
-rw-r--r--libdwfl/libdwflP.h4
5 files changed, 70 insertions, 4 deletions
diff --git a/libdwfl/ChangeLog b/libdwfl/ChangeLog
index 32ff63b2..b1ba7a5d 100644
--- a/libdwfl/ChangeLog
+++ b/libdwfl/ChangeLog
@@ -1,3 +1,17 @@
+2010-05-06 Roland McGrath <roland@redhat.com>
+
+ * libdwflP.h (DWFL_ERRORS): Add WRONG_ID_ELF.
+ * dwfl_build_id_find_elf.c: Set MOD->main.valid when there is a build
+ ID but we didn't find a file.
+ * dwfl_module_getdwarf.c (__libdwfl_getelf): When that's set, check
+ and refuse any fallback file-by-name if it lacks the matching ID.
+
+ * dwfl_error.c (dwfl_errno): Add INTDEF.
+ * libdwflP.h: Add INTDECL.
+
+ * dwfl_module_getdwarf.c (open_elf): Do elf_end and clear FILE->elf in
+ failure cases.
+
2010-05-04 Roland McGrath <roland@redhat.com>
* dwfl_segment_report_module.c: Use "[pie]" rather than "[dso]" for an
diff --git a/libdwfl/dwfl_build_id_find_elf.c b/libdwfl/dwfl_build_id_find_elf.c
index fcc6f1e5..e27c8e12 100644
--- a/libdwfl/dwfl_build_id_find_elf.c
+++ b/libdwfl/dwfl_build_id_find_elf.c
@@ -1,5 +1,5 @@
/* Find an ELF file for a module from its build ID.
- Copyright (C) 2007, 2008, 2009 Red Hat, Inc.
+ Copyright (C) 2007-2010 Red Hat, Inc.
This file is part of Red Hat elfutils.
Red Hat elfutils is free software; you can redistribute it and/or modify
@@ -160,6 +160,12 @@ dwfl_build_id_find_elf (Dwfl_Module *mod,
free (*file_name);
*file_name = NULL;
}
+ else if (errno == 0 && mod->build_id_len > 0)
+ /* Setting this with no file yet loaded is a marker that
+ the build ID is authoritative even if we also know a
+ putative *FILE_NAME. */
+ mod->main.valid = true;
+
return fd;
}
INTDEF (dwfl_build_id_find_elf)
diff --git a/libdwfl/dwfl_error.c b/libdwfl/dwfl_error.c
index df2765af..9144a378 100644
--- a/libdwfl/dwfl_error.c
+++ b/libdwfl/dwfl_error.c
@@ -1,5 +1,5 @@
/* Error handling in libdwfl.
- Copyright (C) 2005, 2006, 2009 Red Hat, Inc.
+ Copyright (C) 2005-2010 Red Hat, Inc.
This file is part of Red Hat elfutils.
Red Hat elfutils is free software; you can redistribute it and/or modify
@@ -72,6 +72,7 @@ dwfl_errno (void)
global_error = DWFL_E_NOERROR;
return result;
}
+INTDEF (dwfl_errno)
static const struct msgtable
diff --git a/libdwfl/dwfl_module_getdwarf.c b/libdwfl/dwfl_module_getdwarf.c
index b084673e..6065257d 100644
--- a/libdwfl/dwfl_module_getdwarf.c
+++ b/libdwfl/dwfl_module_getdwarf.c
@@ -75,6 +75,8 @@ open_elf (Dwfl_Module *mod, struct dwfl_file *file)
}
else if (unlikely (elf_kind (file->elf) != ELF_K_ELF))
{
+ elf_end (file->elf);
+ file->elf = NULL;
close (file->fd);
file->fd = -1;
return DWFL_E_BADELF;
@@ -84,6 +86,8 @@ open_elf (Dwfl_Module *mod, struct dwfl_file *file)
if (ehdr == NULL)
{
elf_error:
+ elf_end (file->elf);
+ file->elf = NULL;
close (file->fd);
file->fd = -1;
return DWFL_E (LIBELF, elf_errno ());
@@ -137,9 +141,12 @@ __libdwfl_getelf (Dwfl_Module *mod)
mod->main.fd = (*mod->dwfl->callbacks->find_elf) (MODCB_ARGS (mod),
&mod->main.name,
&mod->main.elf);
+ const bool fallback = mod->main.elf == NULL && mod->main.fd < 0;
mod->elferr = open_elf (mod, &mod->main);
+ if (mod->elferr != DWFL_E_NOERROR)
+ return;
- if (mod->elferr == DWFL_E_NOERROR && !mod->main.valid)
+ if (!mod->main.valid)
{
/* Clear any explicitly reported build ID, just in case it was wrong.
We'll fetch it from the file when asked. */
@@ -147,6 +154,42 @@ __libdwfl_getelf (Dwfl_Module *mod)
mod->build_id_bits = NULL;
mod->build_id_len = 0;
}
+ else if (fallback)
+ {
+ /* We have an authoritative build ID for this module, so
+ don't use a file by name that doesn't match that ID. */
+
+ assert (mod->build_id_len > 0);
+
+ switch (__builtin_expect (__libdwfl_find_build_id (mod, false,
+ mod->main.elf), 2))
+ {
+ case 2:
+ /* Build ID matches as it should. */
+ return;
+
+ case -1: /* ELF error. */
+ mod->elferr = INTUSE(dwfl_errno) ();
+ break;
+
+ case 0: /* File has no build ID note. */
+ case 1: /* FIle has a build ID that does not match. */
+ mod->elferr = DWFL_E_WRONG_ID_ELF;
+ break;
+
+ default:
+ abort ();
+ }
+
+ /* We get here when it was the right ELF file. Clear it out. */
+ elf_end (mod->main.elf);
+ mod->main.elf = NULL;
+ if (mod->main.fd >= 0)
+ {
+ close (mod->main.fd);
+ mod->main.fd = -1;
+ }
+ }
}
/* Search an ELF file for a ".gnu_debuglink" section. */
diff --git a/libdwfl/libdwflP.h b/libdwfl/libdwflP.h
index 58edacb9..e4c7e7c8 100644
--- a/libdwfl/libdwflP.h
+++ b/libdwfl/libdwflP.h
@@ -93,7 +93,8 @@
DWFL_ERROR (TRUNCATED, N_("image truncated")) \
DWFL_ERROR (ALREADY_ELF, N_("ELF file opened")) \
DWFL_ERROR (BADELF, N_("not a valid ELF file")) \
- DWFL_ERROR (WEIRD_TYPE, N_("cannot handle DWARF type description"))
+ DWFL_ERROR (WEIRD_TYPE, N_("cannot handle DWARF type description")) \
+ DWFL_ERROR (WRONG_ID_ELF, N_("ELF file does not match build ID"))
#define DWFL_ERROR(name, text) DWFL_E_##name,
typedef enum { DWFL_ERRORS DWFL_E_NUM } Dwfl_Error;
@@ -404,6 +405,7 @@ extern int dwfl_link_map_report (Dwfl *dwfl, const void *auxv, size_t auxv_size,
/* Avoid PLT entries. */
INTDECL (dwfl_begin)
INTDECL (dwfl_errmsg)
+INTDECL (dwfl_errno)
INTDECL (dwfl_addrmodule)
INTDECL (dwfl_addrsegment)
INTDECL (dwfl_addrdwarf)