Skip to content

Conversation

@stephanosio
Copy link
Member

rewrite_elf_program_header() currently makes a questionable assumption that the LMA of a segment will be aligned at the alignment of the first section in the segment, and attempts to align the address of the segment LMA to the alignment of the first section using align_power() before comparing it to the actual LMA of the first section for the purpose of verifying that the first section starts at the beginning of the segment.

This is not a problem when the LMA is equal to the VMA and both are aligned at the section alignment; but, for the sections that have different VMA and LMA, only the VMA is guaranteed to be aligned at the section alignment, and the LMA may or may not be aligned at the same boundary, leading to rewrite_elf_program_header() returning false even for valid ELF files that do not contain any segments whose first section does not start at the beginning of the segment.

This patch adds an alternate check directly comparing the segment and section LMAs for the segments that do not contain any headers; in case a segment contains a file or program header, the function may still erroneously return false.

A more fundamental fix should re-implement the function such that it uses VMA for verifying that the first section in a segment starts at the beginning of the segment.


Fixes zephyrproject-rtos/zephyr#58080

rewrite_elf_program_header() currently makes a questionable assumption
that the LMA of a segment will be aligned at the alignment of the first
section in the segment, and attempts to align the address of the segment
LMA to the alignment of the first section using align_power() before
comparing it to the actual LMA of the first section for the purpose of
verifying that the first section starts at the beginning of the segment.

This is not a problem when the LMA is equal to the VMA and both are
aligned at the section alignment; but, for the sections that have
different VMA and LMA, only the VMA is guaranteed to be aligned at the
section alignment, and the LMA may or may not be aligned at the same
boundary, leading to rewrite_elf_program_header() returning false even
for valid ELF files that do not contain any segments whose first section
does not start at the beginning of the segment.

This patch adds an alternate check directly comparing the segment and
section LMAs for the segments that do not contain any headers; in case a
segment contains a file or program header, the function may still
erroneously return false.

A more fundamental fix should re-implement the function such that it
uses VMA for verifying that the first section in a segment starts at the
beginning of the segment.

Signed-off-by: Stephanos Ioannidis <root@stephanos.io>
Copy link
Member Author

@stephanosio stephanosio left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@stephanosio stephanosio merged commit 81f63d1 into zephyr-binutils-2_38 Jan 25, 2024
@stephanosio stephanosio deleted the elf_phdr_rewrite_lma_neq_vma branch January 31, 2024 18:43
duynguyenxa pushed a commit to renesas/binutils-gdb that referenced this pull request Oct 29, 2025
On Windows gcore is not implemented, and if you try it, you get an
heap-use-after-free error:

(gdb) gcore C:/gdb/build64/gdb-git-python3/gdb/testsuite/outputs/gdb.base/gcore-buffer-overflow/gcore-buffer-overflow.test
warning: cannot close "=================================================================
==10108==ERROR: AddressSanitizer: heap-use-after-free on address 0x1259ea503110 at pc 0x7ff6806e3936 bp 0x0062e01ed990 sp 0x0062e01ed140
READ of size 111 at 0x1259ea503110 thread T0
    #0 0x7ff6806e3935 in strlen C:/gcc/src/gcc-14.2.0/libsanitizer/sanitizer_common/sanitizer_common_interceptors.inc:391
    zephyrproject-rtos#1 0x7ff6807169c4 in __pformat_puts C:/gcc/src/mingw-w64-v12.0.0/mingw-w64-crt/stdio/mingw_pformat.c:558
    zephyrproject-rtos#2 0x7ff6807186c1 in __mingw_pformat C:/gcc/src/mingw-w64-v12.0.0/mingw-w64-crt/stdio/mingw_pformat.c:2514
    zephyrproject-rtos#3 0x7ff680713614 in __mingw_vsnprintf C:/gcc/src/mingw-w64-v12.0.0/mingw-w64-crt/stdio/mingw_vsnprintf.c:41
    zephyrproject-rtos#4 0x7ff67f34419f in vsnprintf(char*, unsigned long long, char const*, char*) C:/msys64/mingw64/x86_64-w64-mingw32/include/stdio.h:484
    zephyrproject-rtos#5 0x7ff67f34419f in string_vprintf[abi:cxx11](char const*, char*) C:/gdb/src/gdb.git/gdbsupport/common-utils.cc:106
    zephyrproject-rtos#6 0x7ff67b37b739 in cli_ui_out::do_message(ui_file_style const&, char const*, char*) C:/gdb/src/gdb.git/gdb/cli-out.c:227
    zephyrproject-rtos#7 0x7ff67ce3d030 in ui_out::call_do_message(ui_file_style const&, char const*, ...) C:/gdb/src/gdb.git/gdb/ui-out.c:571
    zephyrproject-rtos#8 0x7ff67ce4255a in ui_out::vmessage(ui_file_style const&, char const*, char*) C:/gdb/src/gdb.git/gdb/ui-out.c:740
    zephyrproject-rtos#9 0x7ff67ce2c873 in ui_file::vprintf(char const*, char*) C:/gdb/src/gdb.git/gdb/ui-file.c:73
    zephyrproject-rtos#10 0x7ff67ce7f83d in gdb_vprintf(ui_file*, char const*, char*) C:/gdb/src/gdb.git/gdb/utils.c:1881
    zephyrproject-rtos#11 0x7ff67ce7f83d in vwarning(char const*, char*) C:/gdb/src/gdb.git/gdb/utils.c:181
    zephyrproject-rtos#12 0x7ff67f3530eb in warning(char const*, ...) C:/gdb/src/gdb.git/gdbsupport/errors.cc:33
    zephyrproject-rtos#13 0x7ff67baed27f in gdb_bfd_close_warning C:/gdb/src/gdb.git/gdb/gdb_bfd.c:437
    zephyrproject-rtos#14 0x7ff67baed27f in gdb_bfd_close_or_warn C:/gdb/src/gdb.git/gdb/gdb_bfd.c:646
    zephyrproject-rtos#15 0x7ff67baed27f in gdb_bfd_unref(bfd*) C:/gdb/src/gdb.git/gdb/gdb_bfd.c:739
    zephyrproject-rtos#16 0x7ff68094b6f2 in gdb_bfd_ref_policy::decref(bfd*) C:/gdb/src/gdb.git/gdb/gdb_bfd.h:82
    zephyrproject-rtos#17 0x7ff68094b6f2 in gdb::ref_ptr<bfd, gdb_bfd_ref_policy>::~ref_ptr() C:/gdb/src/gdb.git/gdbsupport/gdb_ref_ptr.h:91
    zephyrproject-rtos#18 0x7ff67badf4d2 in gcore_command C:/gdb/src/gdb.git/gdb/gcore.c:176

0x1259ea503110 is located 16 bytes inside of 4064-byte region [0x1259ea503100,0x1259ea5040e0)
freed by thread T0 here:
    #0 0x7ff6806b1687 in free C:/gcc/src/gcc-14.2.0/libsanitizer/asan/asan_malloc_win.cpp:90
    zephyrproject-rtos#1 0x7ff67f2ae807 in objalloc_free C:/gdb/src/gdb.git/libiberty/objalloc.c:187
    zephyrproject-rtos#2 0x7ff67d7f56e3 in _bfd_free_cached_info C:/gdb/src/gdb.git/bfd/opncls.c:247
    zephyrproject-rtos#3 0x7ff67d7f2782 in _bfd_delete_bfd C:/gdb/src/gdb.git/bfd/opncls.c:180
    zephyrproject-rtos#4 0x7ff67d7f5df9 in bfd_close_all_done C:/gdb/src/gdb.git/bfd/opncls.c:960
    zephyrproject-rtos#5 0x7ff67d7f62ec in bfd_close C:/gdb/src/gdb.git/bfd/opncls.c:925
    zephyrproject-rtos#6 0x7ff67baecd27 in gdb_bfd_close_or_warn C:/gdb/src/gdb.git/gdb/gdb_bfd.c:643
    zephyrproject-rtos#7 0x7ff67baecd27 in gdb_bfd_unref(bfd*) C:/gdb/src/gdb.git/gdb/gdb_bfd.c:739
    zephyrproject-rtos#8 0x7ff68094b6f2 in gdb_bfd_ref_policy::decref(bfd*) C:/gdb/src/gdb.git/gdb/gdb_bfd.h:82
    zephyrproject-rtos#9 0x7ff68094b6f2 in gdb::ref_ptr<bfd, gdb_bfd_ref_policy>::~ref_ptr() C:/gdb/src/gdb.git/gdbsupport/gdb_ref_ptr.h:91
    zephyrproject-rtos#10 0x7ff67badf4d2 in gcore_command C:/gdb/src/gdb.git/gdb/gcore.c:176

It happens because gdb_bfd_close_or_warn uses a bfd-internal name for
the failing-close warning, after the close is finished, and the name
already freed:

static int
gdb_bfd_close_or_warn (struct bfd *abfd)
{
  int ret;
  const char *name = bfd_get_filename (abfd);

  for (asection *sect : gdb_bfd_sections (abfd))
    free_one_bfd_section (sect);

  ret = bfd_close (abfd);

  if (!ret)
    gdb_bfd_close_warning (name,
			   bfd_errmsg (bfd_get_error ()));

  return ret;
}

Fixed by making a copy of the name for the warning.

Approved-By: Andrew Burgess <aburgess@redhat.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Build issues observed when using CONFIG_BUILD_OUTPUT_ADJUST_LMA

2 participants