Save/restore file offset while reading notes in core file
authorKeith Seitz <keiths@redhat.com>
Thu, 25 Mar 2021 17:31:48 +0000 (10:31 -0700)
committerKeith Seitz <keiths@redhat.com>
Fri, 26 Mar 2021 17:47:48 +0000 (10:47 -0700)
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]
shell1$ /usr/libexec/qemu-kvm

[shell2]
shell2$ pkill -SEGV -x qemu-kvm

[shell1]
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.

bfd/ChangeLog
2021-03-26  Keith Seitz  <keiths@redhat.com>

* elfcore.h (_bfd_elf_core_find_build_id): Seek file
offset of program headers after calling elf_read_notes.

bfd/ChangeLog
bfd/elfcore.h

index 3245f8c5ad3b72136c433c74c321c1e7f902304f..6f3fccc0a6a23a01694bf42b054fac94f1440f19 100644 (file)
@@ -1,3 +1,8 @@
+2021-03-26  Keith Seitz  <keiths@redhat.com>
+
+       * elfcore.h (_bfd_elf_core_find_build_id): Seek file
+       offset of program headers after calling elf_read_notes.
+
 2021-03-23  Jan Beulich  <jbeulich@suse.com>
 
        * dwarf2.c (read_indexed_string): Rename index to idx.
index 3015e582ef05b24c58aef4479483c762559c7429..4e6383415f7df81b2afc4ec1489074bb7caee570 100644 (file)
@@ -410,6 +410,13 @@ NAME(_bfd_elf, core_find_build_id)
        {
          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, (file_ptr) (offset + i_ehdr.e_phoff
+                                         + (i + 1) * sizeof (x_phdr)),
+                       SEEK_SET) != 0)
+           goto fail;
+
          if (abfd->build_id != NULL)
            return TRUE;
        }