]> git.ipfire.org Git - thirdparty/binutils-gdb.git/commitdiff
PR 33453 allow extra for .eh_frame in final link buffer
authorAlan Modra <amodra@gmail.com>
Wed, 26 Nov 2025 22:30:26 +0000 (09:00 +1030)
committerAlan Modra <amodra@gmail.com>
Wed, 26 Nov 2025 22:41:17 +0000 (09:11 +1030)
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

index cf593b344f4984ac61ea7b817e3006106d08ee70..fb975d918038f84daea3ed9b487e92204b9850a9 100644 (file)
@@ -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