forked from Imagelibrary/binutils-gdb
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.
This commit is contained in:
48
bfd/linker.c
48
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)
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user