From 0587fb9f40f6fdb1f0007226147d66c51d33b5c5 Mon Sep 17 00:00:00 2001 From: Alan Modra Date: Thu, 27 Nov 2025 09:00:26 +1030 Subject: [PATCH] PR 33453 allow extra for .eh_frame in final link buffer The PR33453 testcase overflows a buffer allocated for the .eh_frame section. This happens with a silly large alignment for .eh_frame, creating a large gap between two .eh_frame sections. When the last FDE of the first section is stretched to cover the gap, we get a buffer overflow. This patch makes the final link buffer large enough to cover such gaps. It doesn't fix the testcase yet, because there the first .eh_frame section in question is the x86 plt_eh_frame section which uses a different buffer. However, similar testcases could be constructed using object file .eh_frame sections. PR 33453 * elflink.c (bfd_elf_final_link): Round up max_contents_size for .eh_frame alignment. --- bfd/elflink.c | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/bfd/elflink.c b/bfd/elflink.c index cf593b344f4..fb975d91803 100644 --- a/bfd/elflink.c +++ b/bfd/elflink.c @@ -12757,6 +12757,16 @@ _bfd_elf_final_link (bfd *abfd, struct bfd_link_info *info) for (o = abfd->sections; o != NULL; o = o->next) { struct bfd_elf_section_data *esdo = elf_section_data (o); + bfd_size_type size_align = 1; + + if (o->sec_info_type == SEC_INFO_TYPE_EH_FRAME) + { + /* eh_frame editing can extend last FDE to cover padding + between one section and the next. */ + size_align = (((bfd_size_type) 1 << o->alignment_power) + * bfd_octets_per_byte (abfd, o)); + } + o->reloc_count = 0; for (p = o->map_head.link_order; p != NULL; p = p->next) @@ -12792,10 +12802,11 @@ _bfd_elf_final_link (bfd *abfd, struct bfd_link_info *info) || sec->rawsize != sec->size) #endif { - if (sec->rawsize > max_contents_size) - max_contents_size = sec->rawsize; - if (sec->size > max_contents_size) - max_contents_size = sec->size; + bfd_size_type size = (sec->rawsize > sec->size + ? sec->rawsize : sec->size); + size = (size + size_align - 1) & -size_align; + if (max_contents_size < size) + max_contents_size = size; } if (bfd_get_flavour (sec->owner) == bfd_target_elf_flavour -- 2.47.3