[patch] Verify file vs. core build-id, when both available

Jan Kratochvil jan.kratochvil at redhat.com
Wed Nov 20 19:32:34 UTC 2013

Hi Mark,


the approved patch
	[patch] Fix non-build-id core files on build-id system
	Message-ID: <20131112203642.GA23754 at host2.jankratochvil.net>

is right in general but it causes a regression
	FAIL: run-unstrip-n.sh
due to:
+0xf75e9000+0x1a000 29a103420abe341e92072fb14274e250e4072148 at 0xf75e9164 - - libpthread.so.0
-0xf75e8fe0+0x191fc 718a99e8dbf70cd061097f70e5fe21237f86ab4a at 0xf75e9144 /lib/libpthread.so.0 - libpthread.so.0
+0xf7603000+0x1b0000 0b9bf374699e141e5dfc14757ff42b8c2373b4de at 0xf7603184 - - libc.so.6
-0xf75f3fe0+0x1bea7c 50ed3f33e3761eefeeceb120121643f843260b27 at 0xf75f4164 /lib/libc.so.6 - libc.so.6
+0xf77b3000+0x9000 c6c5b5e35ab9589d4762ac85b4bd56b1b2720e37 at 0xf77b3164 - - librt.so.1
-0xf77b3004+0x8224 3b3966acca796ba57b538a014bcc77ea0cc5033e at 0xf77b3168 /lib/librt.so.1 - librt.so.1
+0xf77d7000+0x21000 6d2cb32650054f1c176d01d48713a4a5e5e84c1a at 0xf77d7124 - - ld-linux.so.2
-0xf77d6ff0+0x208f8 03099056658748f4e58e2cd390fb63babfd1d23b at 0xf77d7114 /lib/ld-linux.so.2 - ld-linux.so.2

The problem is that:
 * elfutils will find a completely different version of file with the same name
 * the file has build-id
 * as the file is different the computed memory address of the build-id is bogus
 * bogus address is sure not available from the core file
 * elfutils thinks just that the core file was dumped without first ELF page
therefore elfutils approves the file matching as valid.

One could for example restrict the mappings only for PAGE_SIZE-aligned
displacements but that would not work well with prelinked vs. unprelinked
files, see GDB comment:
              /* There is no way to verify the library file matches.  prelink
                 can during prelinking of an unprelinked file (or unprelinking
                 of a prelinked file) shift the DYNAMIC segment by arbitrary
                 offset without any page size alignment.  There is no way to
                 find out the ELF header and/or Program Headers for a limited
                 verification if it they match.  One could do a verification
                 of the DYNAMIC segment.  Still the found address is the best
                 one GDB could find.  */

But as elfutils scans the memory space and finds there files by their build-id
it can verify build-id of the found disk file vs. that in-memory file.

This will make all the tests of the initial patch PASSing again.

-------------- next part --------------
commit 18545b45f6e2ea807467f189d58e2bdce8fb4a3a
Author: Jan Kratochvil <jan.kratochvil at redhat.com>
Date:   Wed Nov 20 20:27:50 2013 +0100

    Verify file vs. core build-id, when both available
    2013-11-20  Jan Kratochvil  <jan.kratochvil at redhat.com>
    	* dwfl_segment_report_module.c (dwfl_segment_report_module): New
    	variable close_elf.  Call __libdwfl_find_elf_build_id and compare the
    	content, if possible.
    Signed-off-by: Jan Kratochvil <jan.kratochvil at redhat.com>

diff --git a/libdwfl/dwfl_segment_report_module.c b/libdwfl/dwfl_segment_report_module.c
index 97f4a1a..55f6d38 100644
--- a/libdwfl/dwfl_segment_report_module.c
+++ b/libdwfl/dwfl_segment_report_module.c
@@ -478,20 +478,40 @@ dwfl_segment_report_module (Dwfl *dwfl, int ndx, const char *name,
 	if ((module_end > module->start && module_start < module->end)
 	    || dyn_vaddr == module->l_ld)
+	    bool close_elf = false;
 	    if (! module->disk_file_has_build_id && build_id_len > 0)
 		/* Module found in segments with build-id is more reliable
 		   than a module found via DT_DEBUG on disk without any
 		   build-id.   */
 		if (module->elf != NULL)
+		  close_elf = true;
+	      }
+	    if (module->elf != NULL
+		&& module->disk_file_has_build_id && build_id_len > 0)
+	      {
+		const void *elf_build_id;
+		GElf_Addr elf_build_id_elfaddr;
+		int elf_build_id_len;
+		if (__libdwfl_find_elf_build_id (NULL, module->elf,
+						 &elf_build_id,
+						 &elf_build_id_elfaddr,
+						 &elf_build_id_len) > 0)
-		    elf_end (module->elf);
-		    close (module->fd);
-		    module->elf = NULL;
-		    module->fd = -1;
+		    if (build_id_len != (size_t) elf_build_id_len
+			|| memcmp (build_id, elf_build_id, build_id_len) != 0)
+		      close_elf = true;
-	    else if (module->elf != NULL)
+	    if (close_elf)
+	      {
+		elf_end (module->elf);
+		close (module->fd);
+		module->elf = NULL;
+		module->fd = -1;
+	      }
+	    if (module->elf != NULL)
 		/* Ignore this found module if it would conflict in address
 		   space with any already existing module of DWFL.  */

More information about the elfutils-devel mailing list