]> git.ipfire.org Git - thirdparty/binutils-gdb.git/commitdiff
score: segfault on null hi16_rel_addr
authorAlan Modra <amodra@gmail.com>
Fri, 23 Jan 2026 23:19:29 +0000 (09:49 +1030)
committerAlan Modra <amodra@gmail.com>
Sat, 24 Jan 2026 00:13:40 +0000 (10:43 +1030)
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.

bfd/elf32-score.c
bfd/elf32-score7.c

index 49ff8105bfbe8afde682fd9f485023f1301f3525..706732768e59cf32f2844ce6676061d649dacc21 100644 (file)
@@ -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);
index 7219b364269ae97d5266bf267d038a8ed42971db..91610240462c0358e7a2019b76051a9bdb7a5551 100644 (file)
@@ -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);