From: Alan Modra Date: Fri, 23 Jan 2026 23:19:29 +0000 (+1030) Subject: score: segfault on null hi16_rel_addr X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=073661d8d1a432298084cefe961bee10b40bb4ac;p=thirdparty%2Fbinutils-gdb.git score: segfault on null hi16_rel_addr On a fuzzed input object we hit a segfault when a LO16 reloc doesn't have the required preceding HI16 reloc. move score static hi16_rel_addr to elf_section_data, and check that it is non-NULL before dereferencing. --- diff --git a/bfd/elf32-score.c b/bfd/elf32-score.c index 49ff8105bfb..706732768e5 100644 --- a/bfd/elf32-score.c +++ b/bfd/elf32-score.c @@ -136,8 +136,8 @@ struct _score_elf_section_data { struct score_got_info *got_info; bfd_byte *tdata; - } - u; + } u; + bfd_byte *hi16_rel_addr; }; #define score_elf_section_data(sec) \ @@ -190,8 +190,6 @@ struct _score_elf_section_data #define SCORE_ELF_LOG_FILE_ALIGN(abfd)\ (get_elf_backend_data (abfd)->s->log_file_align) -static bfd_byte *hi16_rel_addr; - /* This will be used when we sort the dynamic relocation records. */ static bfd *reldyn_sorting_bfd; @@ -309,12 +307,13 @@ static bfd_reloc_status_type score_elf_hi16_reloc (bfd *abfd ATTRIBUTE_UNUSED, arelent *reloc_entry, asymbol *symbol ATTRIBUTE_UNUSED, - void * data, - asection *input_section ATTRIBUTE_UNUSED, + void *data, + asection *input_section, bfd *output_bfd ATTRIBUTE_UNUSED, char **error_message ATTRIBUTE_UNUSED) { - hi16_rel_addr = (bfd_byte *) data + reloc_entry->address; + score_elf_section_data (input_section)->hi16_rel_addr + = (bfd_byte *) data + reloc_entry->address; return bfd_reloc_ok; } @@ -330,8 +329,10 @@ score_elf_lo16_reloc (bfd *abfd, bfd_vma addend = 0, offset = 0; unsigned long val; unsigned long hi16_offset, hi16_value, uvalue; + bfd_byte *hi16_rel_addr; - hi16_value = score_bfd_get_32 (abfd, hi16_rel_addr); + hi16_rel_addr = score_elf_section_data (input_section)->hi16_rel_addr; + hi16_value = hi16_rel_addr ? score_bfd_get_32 (abfd, hi16_rel_addr) : 0; hi16_offset = ((((hi16_value >> 16) & 0x3) << 15) | (hi16_value & 0x7fff)) >> 1; addend = score_bfd_get_32 (abfd, (bfd_byte *) data + reloc_entry->address); offset = ((((addend >> 16) & 0x3) << 15) | (addend & 0x7fff)) >> 1; @@ -339,9 +340,13 @@ score_elf_lo16_reloc (bfd *abfd, if (reloc_entry->address > input_section->size) return bfd_reloc_outofrange; uvalue = ((hi16_offset << 16) | (offset & 0xffff)) + val; - hi16_offset = (uvalue >> 16) << 1; - hi16_value = (hi16_value & ~0x37fff) | (hi16_offset & 0x7fff) | ((hi16_offset << 1) & 0x30000); - score_bfd_put_32 (abfd, hi16_value, hi16_rel_addr); + if (hi16_rel_addr) + { + hi16_offset = (uvalue >> 16) << 1; + hi16_value = ((hi16_value & ~0x37fff) + | (hi16_offset & 0x7fff) | ((hi16_offset << 1) & 0x30000)); + score_bfd_put_32 (abfd, hi16_value, hi16_rel_addr); + } offset = (uvalue & 0xffff) << 1; addend = (addend & ~0x37fff) | (offset & 0x7fff) | ((offset << 1) & 0x30000); score_bfd_put_32 (abfd, addend, (bfd_byte *) data + reloc_entry->address); @@ -613,8 +618,10 @@ score_elf_got_lo16_reloc (bfd *abfd, bfd_vma addend = 0, offset = 0; signed long val; signed long hi16_offset, hi16_value, uvalue; + bfd_byte *hi16_rel_addr; - hi16_value = score_bfd_get_32 (abfd, hi16_rel_addr); + hi16_rel_addr = score_elf_section_data (input_section)->hi16_rel_addr; + hi16_value = hi16_rel_addr ? score_bfd_get_32 (abfd, hi16_rel_addr) : 0; hi16_offset = ((((hi16_value >> 16) & 0x3) << 15) | (hi16_value & 0x7fff)) >> 1; addend = score_bfd_get_32 (abfd, (bfd_byte *) data + reloc_entry->address); offset = ((((addend >> 16) & 0x3) << 15) | (addend & 0x7fff)) >> 1; @@ -622,12 +629,16 @@ score_elf_got_lo16_reloc (bfd *abfd, if (reloc_entry->address > input_section->size) return bfd_reloc_outofrange; uvalue = ((hi16_offset << 16) | (offset & 0xffff)) + val; - if ((uvalue > -0x8000) && (uvalue < 0x7fff)) - hi16_offset = 0; - else - hi16_offset = (uvalue >> 16) & 0x7fff; - hi16_value = (hi16_value & ~0x37fff) | (hi16_offset & 0x7fff) | ((hi16_offset << 1) & 0x30000); - score_bfd_put_32 (abfd, hi16_value, hi16_rel_addr); + if (hi16_rel_addr) + { + if ((uvalue > -0x8000) && (uvalue < 0x7fff)) + hi16_offset = 0; + else + hi16_offset = (uvalue >> 16) & 0x7fff; + hi16_value = ((hi16_value & ~0x37fff) + | (hi16_offset & 0x7fff) | ((hi16_offset << 1) & 0x30000)); + score_bfd_put_32 (abfd, hi16_value, hi16_rel_addr); + } offset = (uvalue & 0xffff) << 1; addend = (addend & ~0x37fff) | (offset & 0x7fff) | ((offset << 1) & 0x30000); score_bfd_put_32 (abfd, addend, (bfd_byte *) data + reloc_entry->address); diff --git a/bfd/elf32-score7.c b/bfd/elf32-score7.c index 7219b364269..91610240462 100644 --- a/bfd/elf32-score7.c +++ b/bfd/elf32-score7.c @@ -132,8 +132,8 @@ struct _score_elf_section_data { struct score_got_info *got_info; bfd_byte *tdata; - } - u; + } u; + bfd_byte *hi16_rel_addr; }; #define score_elf_section_data(sec) \ @@ -187,8 +187,6 @@ struct _score_elf_section_data #define SCORE_ELF_LOG_FILE_ALIGN(abfd)\ (get_elf_backend_data (abfd)->s->log_file_align) -static bfd_byte *hi16_rel_addr; - /* This will be used when we sort the dynamic relocation records. */ static bfd *reldyn_sorting_bfd; @@ -213,7 +211,8 @@ score_elf_hi16_reloc (bfd *abfd ATTRIBUTE_UNUSED, bfd *output_bfd ATTRIBUTE_UNUSED, char **error_message ATTRIBUTE_UNUSED) { - hi16_rel_addr = (bfd_byte *) data + reloc_entry->address; + score_elf_section_data (input_section)->hi16_rel_addr + = (bfd_byte *) data + reloc_entry->address; return bfd_reloc_ok; } @@ -229,8 +228,10 @@ score_elf_lo16_reloc (bfd *abfd, bfd_vma addend = 0, offset = 0; unsigned long val; unsigned long hi16_offset, hi16_value, uvalue; + bfd_byte *hi16_rel_addr; - hi16_value = bfd_get_32 (abfd, hi16_rel_addr); + hi16_rel_addr = score_elf_section_data (input_section)->hi16_rel_addr; + hi16_value = hi16_rel_addr ? bfd_get_32 (abfd, hi16_rel_addr) : 0; hi16_offset = ((((hi16_value >> 16) & 0x3) << 15) | (hi16_value & 0x7fff)) >> 1; addend = bfd_get_32 (abfd, (bfd_byte *) data + reloc_entry->address); offset = ((((addend >> 16) & 0x3) << 15) | (addend & 0x7fff)) >> 1; @@ -238,9 +239,13 @@ score_elf_lo16_reloc (bfd *abfd, if (reloc_entry->address > input_section->size) return bfd_reloc_outofrange; uvalue = ((hi16_offset << 16) | (offset & 0xffff)) + val; - hi16_offset = (uvalue >> 16) << 1; - hi16_value = (hi16_value & ~0x37fff) | (hi16_offset & 0x7fff) | ((hi16_offset << 1) & 0x30000); - bfd_put_32 (abfd, hi16_value, hi16_rel_addr); + if (hi16_rel_addr) + { + hi16_offset = (uvalue >> 16) << 1; + hi16_value = ((hi16_value & ~0x37fff) + | (hi16_offset & 0x7fff) | ((hi16_offset << 1) & 0x30000)); + bfd_put_32 (abfd, hi16_value, hi16_rel_addr); + } offset = (uvalue & 0xffff) << 1; addend = (addend & ~0x37fff) | (offset & 0x7fff) | ((offset << 1) & 0x30000); bfd_put_32 (abfd, addend, (bfd_byte *) data + reloc_entry->address); @@ -516,8 +521,10 @@ score_elf_got_lo16_reloc (bfd *abfd, bfd_vma addend = 0, offset = 0; signed long val; signed long hi16_offset, hi16_value, uvalue; + bfd_byte *hi16_rel_addr; - hi16_value = bfd_get_32 (abfd, hi16_rel_addr); + hi16_rel_addr = score_elf_section_data (input_section)->hi16_rel_addr; + hi16_value = hi16_rel_addr ? bfd_get_32 (abfd, hi16_rel_addr) : 0; hi16_offset = ((((hi16_value >> 16) & 0x3) << 15) | (hi16_value & 0x7fff)) >> 1; addend = bfd_get_32 (abfd, (bfd_byte *) data + reloc_entry->address); offset = ((((addend >> 16) & 0x3) << 15) | (addend & 0x7fff)) >> 1; @@ -525,12 +532,16 @@ score_elf_got_lo16_reloc (bfd *abfd, if (reloc_entry->address > input_section->size) return bfd_reloc_outofrange; uvalue = ((hi16_offset << 16) | (offset & 0xffff)) + val; - if ((uvalue > -0x8000) && (uvalue < 0x7fff)) - hi16_offset = 0; - else - hi16_offset = (uvalue >> 16) & 0x7fff; - hi16_value = (hi16_value & ~0x37fff) | (hi16_offset & 0x7fff) | ((hi16_offset << 1) & 0x30000); - bfd_put_32 (abfd, hi16_value, hi16_rel_addr); + if (hi16_rel_addr) + { + if ((uvalue > -0x8000) && (uvalue < 0x7fff)) + hi16_offset = 0; + else + hi16_offset = (uvalue >> 16) & 0x7fff; + hi16_value = ((hi16_value & ~0x37fff) + | (hi16_offset & 0x7fff) | ((hi16_offset << 1) & 0x30000)); + bfd_put_32 (abfd, hi16_value, hi16_rel_addr); + } offset = (uvalue & 0xffff) << 1; addend = (addend & ~0x37fff) | (offset & 0x7fff) | ((offset << 1) & 0x30000); bfd_put_32 (abfd, addend, (bfd_byte *) data + reloc_entry->address);