[PATCH] Save/restore file offset while reading notes in core file

Keith Seitz keiths@redhat.com
Thu Mar 18 15:40:26 GMT 2021

A recent bug (RH BZ 1931344) has exposed a bug in the core file
build-ID support that I introduced a while ago. It is pretty
easy to demonstate the problem following a simplified procedure
outlined in that bug:

shell1$ /usr/libexec/qemu-kvm

shell2$ pkill -SEGV -x qemu-kvm

Segmentation fault (core dumped)

Load this core file into GDB without specifying an executable
(an unfortunate Fedora/RHEL-ism), and GDB will inform the user
to install debuginfo for the "missing" executable:

$ gdb -nx -q core.12345
Missing separate debuginfo for the main executable file
Try: dnf --enablerepo='*debug*' install /usr/lib/debug/.build-id/e2/e9c66d3117fb2bbb5b2be122f04f2664e5df54
Core was generated by `/usr/libexec/qemu-kvm'.
Program terminated with signal SIGSEGV, Segmentation fault.

The suggested build-ID is actaully for gmp not qemu-kvm. The problem
lies in _bfd_elf_core_find_build_id, where we loop over program headers
looking for note segments:

  /* Read in program headers and parse notes.  */
  for (i = 0; i < i_ehdr.e_phnum; ++i, ++i_phdr)
      Elf_External_Phdr x_phdr;

      if (bfd_bread (&x_phdr, sizeof (x_phdr), abfd) != sizeof (x_phdr))
        goto fail;
      elf_swap_phdr_in (abfd, &x_phdr, i_phdr);

      if (i_phdr->p_type == PT_NOTE && i_phdr->p_filesz > 0)
          elf_read_notes (abfd, offset + i_phdr->p_offset,
                          i_phdr->p_filesz, i_phdr->p_align);

          if (abfd->build_id != NULL)
            return TRUE;

elf_read_notes uses bfd_seek to forward the stream to the location of
the note segment. When control returns to _bfd_elf_core_fild_build_id,
the stream is no longer in the location looking at program headers, and
all subsequent reads will read from the wrong file offset.

To fix this, this patch marks the stream location and ensures
that it is restored after elf_read_notes is called.

2021-03-18  Keith Seitz  <keiths@redhat.com>

	* elfcore.h (_bfd_elf_core_find_build_id): Save and restore
	file offset when calling elf_read_notes.
 bfd/ChangeLog |  5 +++++
 bfd/elfcore.h | 10 ++++++++++
 2 files changed, 15 insertions(+)

diff --git a/bfd/elfcore.h b/bfd/elfcore.h
index 3015e582ef0..d5d1555ac03 100644
--- a/bfd/elfcore.h
+++ b/bfd/elfcore.h
@@ -408,8 +408,18 @@ NAME(_bfd_elf, core_find_build_id)
       if (i_phdr->p_type == PT_NOTE && i_phdr->p_filesz > 0)
+	  /* elf_read_notes will seek to the file offset of the
+	     note segment.  Save the current location in case
+	     this program header contains multiple note segments.  */
+	  file_ptr origin = bfd_tell (abfd);
 	  elf_read_notes (abfd, offset + i_phdr->p_offset,
 			  i_phdr->p_filesz, i_phdr->p_align);
+	  /* Make sure ABFD returns to processing the program
+	     headers.  */
+	  if (bfd_seek (abfd, origin, SEEK_SET) != 0)
+	    goto fail;
 	  if (abfd->build_id != NULL)
 	    return TRUE;

More information about the Binutils mailing list