[binutils-gdb] PR32662, segv in _bfd_generic_link_output_symbols

Alan Modra amodra@sourceware.org
Sun Feb 9 10:37:01 GMT 2025


https://sourceware.org/git/gitweb.cgi?p=binutils-gdb.git;h=38ee3a7664f00778fcc895a7f279c289a12cdbfd

commit 38ee3a7664f00778fcc895a7f279c289a12cdbfd
Author: Alan Modra <amodra@gmail.com>
Date:   Sun Feb 9 12:52:23 2025 +1030

    PR32662, segv in _bfd_generic_link_output_symbols
    
    asymbol flags zero can result from certain combinations of ELF st_info
    binding and type.  asymbol section is set to bfd_abs_section for
    genuine absolute symbols and also ones with a bogus st_shndx.  A
    fuzzed ELF object with such a symbol can tickle a bug in generic
    linker code added by commit d3a65d4dea to avoid an abort, resulting
    in a segfault.  This patch fixes the segfault by removing the
    sym->section->owner->flags test.  I think it should be OK to exclude
    all symbols without any BSF flags set, not just IR symbols.
    
            PR 32662
            * linker.c (_bfd_generic_link_output_symbols): Exclude all
            symbols with zero flags.  Replace abort with assertion.
            Tidy logic.

Diff:
---
 bfd/linker.c | 48 ++++++++++++++++++------------------------------
 1 file changed, 18 insertions(+), 30 deletions(-)

diff --git a/bfd/linker.c b/bfd/linker.c
index 8b3579dc658..1c466e501d5 100644
--- a/bfd/linker.c
+++ b/bfd/linker.c
@@ -2066,7 +2066,6 @@ _bfd_generic_link_output_symbols (bfd *output_bfd,
     {
       asymbol *sym;
       struct generic_link_hash_entry *h;
-      bool output;
 
       h = NULL;
       sym = *sym_ptr;
@@ -2160,12 +2159,20 @@ _bfd_generic_link_output_symbols (bfd *output_bfd,
 	    }
 	}
 
+      bool output = false;
       if ((sym->flags & BSF_KEEP) == 0
 	  && (info->strip == strip_all
 	      || (info->strip == strip_some
 		  && bfd_hash_lookup (info->keep_hash, bfd_asymbol_name (sym),
 				      false, false) == NULL)))
-	output = false;
+	;
+      /* If this symbol is in a section which is not being included
+	 in the output file, then we don't want to output the
+	 symbol.  */
+      else if (!bfd_is_abs_section (sym->section)
+	       && bfd_section_removed_from_list (output_bfd,
+						 sym->section->output_section))
+	;
       else if ((sym->flags & (BSF_GLOBAL | BSF_WEAK | BSF_GNU_UNIQUE)) != 0)
 	{
 	  /* If this symbol is marked as occurring now, rather
@@ -2175,34 +2182,27 @@ _bfd_generic_link_output_symbols (bfd *output_bfd,
 	  if (bfd_asymbol_bfd (sym) == input_bfd
 	      && (sym->flags & BSF_NOT_AT_END) != 0)
 	    output = true;
-	  else
-	    output = false;
 	}
       else if ((sym->flags & BSF_KEEP) != 0)
 	output = true;
       else if (bfd_is_ind_section (sym->section))
-	output = false;
+	;
       else if ((sym->flags & BSF_DEBUGGING) != 0)
 	{
 	  if (info->strip == strip_none)
 	    output = true;
-	  else
-	    output = false;
 	}
       else if (bfd_is_und_section (sym->section)
 	       || bfd_is_com_section (sym->section))
-	output = false;
+	;
       else if ((sym->flags & BSF_LOCAL) != 0)
 	{
-	  if ((sym->flags & BSF_WARNING) != 0)
-	    output = false;
-	  else
+	  if ((sym->flags & BSF_WARNING) == 0)
 	    {
 	      switch (info->discard)
 		{
 		default:
 		case discard_all:
-		  output = false;
 		  break;
 		case discard_sec_merge:
 		  output = true;
@@ -2211,9 +2211,7 @@ _bfd_generic_link_output_symbols (bfd *output_bfd,
 		    break;
 		  /* FALLTHROUGH */
 		case discard_l:
-		  if (bfd_is_local_label (input_bfd, sym))
-		    output = false;
-		  else
+		  if (!bfd_is_local_label (input_bfd, sym))
 		    output = true;
 		  break;
 		case discard_none:
@@ -2226,25 +2224,15 @@ _bfd_generic_link_output_symbols (bfd *output_bfd,
 	{
 	  if (info->strip != strip_all)
 	    output = true;
-	  else
-	    output = false;
 	}
-      else if (sym->flags == 0
-	       && (sym->section->owner->flags & BFD_PLUGIN) != 0)
+      else if (sym->flags == 0)
 	/* LTO doesn't set symbol information.  We get here with the
 	   generic linker for a symbol that was "common" but no longer
-	   needs to be global.  */
-	output = false;
+	   needs to be global.  We also get here on fuzzed ELF objects
+	   with bogus symbol type and binding.  */
+	;
       else
-	abort ();
-
-      /* If this symbol is in a section which is not being included
-	 in the output file, then we don't want to output the
-	 symbol.  */
-      if (!bfd_is_abs_section (sym->section)
-	  && bfd_section_removed_from_list (output_bfd,
-					    sym->section->output_section))
-	output = false;
+	BFD_FAIL ();
 
       if (output)
 	{


More information about the Binutils-cvs mailing list