libdwfl: Refuse to fall back to an ELF file opened by name when that mismatches the module build ID.
diff --git a/libdwfl/ChangeLog b/libdwfl/ChangeLog
index 32ff63b..b1ba7a5 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 fcc6f1e..e27c8e1 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 @@
       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 df2765a..9144a37 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 @@
   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 b084673..6065257 100644
--- a/libdwfl/dwfl_module_getdwarf.c
+++ b/libdwfl/dwfl_module_getdwarf.c
@@ -75,6 +75,8 @@
     }
   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 @@
   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 @@
   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 @@
       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 58edacb..e4c7e7c 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 @@
 /* Avoid PLT entries.  */
 INTDECL (dwfl_begin)
 INTDECL (dwfl_errmsg)
+INTDECL (dwfl_errno)
 INTDECL (dwfl_addrmodule)
 INTDECL (dwfl_addrsegment)
 INTDECL (dwfl_addrdwarf)