From: Alan Modra Date: Sun, 9 Feb 2025 02:22:23 +0000 (+1030) Subject: PR32662, segv in _bfd_generic_link_output_symbols X-Git-Tag: binutils-2_45~1647 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=38ee3a7664f00778fcc895a7f279c289a12cdbfd;p=thirdparty%2Fbinutils-gdb.git 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 --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) {