asan: c4x, c54x coff_canonicalize_reloc buffer overflow
authorAlan Modra <amodra@gmail.com>
Sun, 24 Oct 2021 09:57:06 +0000 (20:27 +1030)
committerAlan Modra <amodra@gmail.com>
Sun, 24 Oct 2021 11:35:51 +0000 (22:05 +1030)
Sometimes the investigation of a fuzzing bug report leads into areas
you'd rather not go.  In this instance by the time I'd figured out the
real cause was a target variant that had never been properly supported
in binutils, the time needed to fix it was less than the time needed
to rip it out.

* coffcode.h (coff_set_alignment_hook): Call bfd_coff_swap_reloc_in
not coff_swap_reloc_in.
(coff_slurp_reloc_table): Likewise.  Don't use RELOC type.
(ticoff0_swap_table): Use coff_swap_reloc_v0_out and
coff_swap_reloc_v0_in.
* coffswap.h (coff_swap_reloc_v0_in, coff_swap_reloc_v0_out): New.
* coff-tic54x.c (tic54x_lookup_howto): Don't abort.
* coffgen.c (coff_get_normalized_symtab): Use PTR_ADD.
* bfd-in.h (PTR_ADD, NPTR_ADD): Avoid warnings when passing an
expression.
* bfd-in2.h: Regenerate.

bfd/bfd-in.h
bfd/bfd-in2.h
bfd/coff-tic54x.c
bfd/coffcode.h
bfd/coffgen.c
bfd/coffswap.h

index 12176433045662686b26d0c26d4048638ce55f9d..286afc607a3a18cbf54c8c15ef0c8be9d8fccdd8 100644 (file)
@@ -114,9 +114,9 @@ typedef struct bfd bfd;
 #endif
 
 /* Silence "applying zero offset to null pointer" UBSAN warnings.  */
-#define PTR_ADD(P,A) ((A) ? (P) + (A) : (P))
+#define PTR_ADD(P,A) ((A) != 0 ? (P) + (A) : (P))
 /* Also prevent non-zero offsets from being applied to a null pointer.  */
-#define NPTR_ADD(P,A) ((P) ? (P) + (A) : (P))
+#define NPTR_ADD(P,A) ((P) != NULL ? (P) + (A) : (P))
 
 #ifdef BFD64
 
index 91888ef1852a8df07a8cb0aad2f6a24649f215da..669f250d0e52f896a62adb324cf7a826dc14ab29 100644 (file)
@@ -121,9 +121,9 @@ typedef struct bfd bfd;
 #endif
 
 /* Silence "applying zero offset to null pointer" UBSAN warnings.  */
-#define PTR_ADD(P,A) ((A) ? (P) + (A) : (P))
+#define PTR_ADD(P,A) ((A) != 0 ? (P) + (A) : (P))
 /* Also prevent non-zero offsets from being applied to a null pointer.  */
-#define NPTR_ADD(P,A) ((P) ? (P) + (A) : (P))
+#define NPTR_ADD(P,A) ((P) != NULL ? (P) + (A) : (P))
 
 #ifdef BFD64
 
index 63d36ae43753a34f8a306b6d59f3e25b238dcf56..86156711741ab787a92be22926d71c4c03febf33 100644 (file)
@@ -278,7 +278,7 @@ tic54x_lookup_howto (bfd *abfd,
 
   _bfd_error_handler (_("%pB: unsupported relocation type %#x"),
                      abfd, (unsigned int) dst->r_type);
-  abort ();
+  internal->howto = NULL;
 }
 
 #define RELOC_PROCESSING(RELENT,RELOC,SYMS,ABFD,SECT)\
index c28d753011ab6c1d8e6aaf5aea18ab6bdf47c8aa..7967cedf918b086a129c1c918af6520b29ab2034 100644 (file)
@@ -1948,7 +1948,7 @@ coff_set_alignment_hook (bfd * abfd ATTRIBUTE_UNUSED,
       if (bfd_bread (& dst, relsz, abfd) != relsz)
        return;
 
-      coff_swap_reloc_in (abfd, &dst, &n);
+      bfd_coff_swap_reloc_in (abfd, &dst, &n);
       if (bfd_seek (abfd, oldpos, 0) != 0)
        return;
       if (n.r_vaddr < 0x10000)
@@ -2019,7 +2019,7 @@ coff_set_alignment_hook (bfd * abfd, asection * section, void * scnhdr)
       if (bfd_bread (& dst, relsz, abfd) != relsz)
        return;
 
-      coff_swap_reloc_in (abfd, &dst, &n);
+      bfd_coff_swap_reloc_in (abfd, &dst, &n);
       if (bfd_seek (abfd, oldpos, 0) != 0)
        return;
       section->reloc_count = hdr->s_nreloc = n.r_vaddr - 1;
@@ -5070,7 +5070,7 @@ SUBSUBSECTION
 static bool
 coff_slurp_reloc_table (bfd * abfd, sec_ptr asect, asymbol ** symbols)
 {
-  RELOC *native_relocs;
+  bfd_byte *native_relocs;
   arelent *reloc_cache;
   arelent *cache_ptr;
   unsigned int idx;
@@ -5085,9 +5085,9 @@ coff_slurp_reloc_table (bfd * abfd, sec_ptr asect, asymbol ** symbols)
   if (!coff_slurp_symbol_table (abfd))
     return false;
 
-  native_relocs = (RELOC *) buy_and_read (abfd, asect->rel_filepos,
-                                         asect->reloc_count,
-                                         bfd_coff_relsz (abfd));
+  native_relocs = (bfd_byte *) buy_and_read (abfd, asect->rel_filepos,
+                                            asect->reloc_count,
+                                            bfd_coff_relsz (abfd));
   if (native_relocs == NULL)
     return false;
 
@@ -5106,16 +5106,16 @@ coff_slurp_reloc_table (bfd * abfd, sec_ptr asect, asymbol ** symbols)
   for (idx = 0; idx < asect->reloc_count; idx++)
     {
       struct internal_reloc dst;
-      struct external_reloc *src;
+      void *src;
 #ifndef RELOC_PROCESSING
       asymbol *ptr;
 #endif
 
       cache_ptr = reloc_cache + idx;
-      src = native_relocs + idx;
+      src = native_relocs + idx * (size_t) bfd_coff_relsz (abfd);
 
       dst.r_offset = 0;
-      coff_swap_reloc_in (abfd, src, &dst);
+      bfd_coff_swap_reloc_in (abfd, src, &dst);
 
 #ifdef RELOC_PROCESSING
       RELOC_PROCESSING (cache_ptr, &dst, symbols, abfd, asect);
@@ -5444,7 +5444,7 @@ static bfd_coff_backend_data ticoff0_swap_table =
 {
   coff_SWAP_aux_in, coff_SWAP_sym_in, coff_SWAP_lineno_in,
   coff_SWAP_aux_out, coff_SWAP_sym_out,
-  coff_SWAP_lineno_out, coff_SWAP_reloc_out,
+  coff_SWAP_lineno_out, coff_swap_reloc_v0_out,
   coff_SWAP_filehdr_out, coff_SWAP_aouthdr_out,
   coff_SWAP_scnhdr_out,
   FILHSZ_V0, AOUTSZ, SCNHSZ_V01, SYMESZ, AUXESZ, RELSZ_V0, LINESZ, FILNMLEN,
@@ -5467,7 +5467,7 @@ static bfd_coff_backend_data ticoff0_swap_table =
 #endif
   32768,
   coff_SWAP_filehdr_in, coff_SWAP_aouthdr_in, coff_SWAP_scnhdr_in,
-  coff_SWAP_reloc_in, ticoff0_bad_format_hook, coff_set_arch_mach_hook,
+  coff_swap_reloc_v0_in, ticoff0_bad_format_hook, coff_set_arch_mach_hook,
   coff_mkobject_hook, styp_to_sec_flags, coff_set_alignment_hook,
   coff_slurp_symbol_table, symname_in_debug_hook, coff_pointerize_aux_hook,
   coff_print_aux, coff_reloc16_extra_cases, coff_reloc16_estimate,
index 77bda9e99471d8f64f2843d33cf1e51b25df9a29..6627a9af4b6607849432bca258971d8d7980f58d 100644 (file)
@@ -1807,7 +1807,7 @@ coff_get_normalized_symtab (bfd *abfd)
 
   /* Mark the end of the symbols.  */
   symesz = bfd_coff_symesz (abfd);
-  raw_end = (char *) raw_src + obj_raw_syment_count (abfd) * symesz;
+  raw_end = PTR_ADD (raw_src, obj_raw_syment_count (abfd) * symesz);
 
   /* FIXME SOMEDAY.  A string table size of zero is very weird, but
      probably possible.  If one shows up, it will probably kill us.  */
index 63a0026a66998df66cf3cf0d2436e0ef8a555b47..e0dbd04f399611997198bfde66c79d3b2a95f10d 100644 (file)
@@ -246,6 +246,33 @@ coff_swap_reloc_out (bfd * abfd, void * src, void * dst)
   return bfd_coff_relsz (abfd);
 }
 
+#ifdef TICOFF
+static void
+coff_swap_reloc_v0_in (bfd *abfd, void *src, void *dst)
+{
+  struct external_reloc_v0 *reloc_src = (struct external_reloc_v0 *) src;
+  struct internal_reloc *reloc_dst = (struct internal_reloc *) dst;
+
+  reloc_dst->r_vaddr  = GET_RELOC_VADDR (abfd, reloc_src->r_vaddr);
+  reloc_dst->r_symndx = H_GET_16 (abfd, reloc_src->r_symndx);
+  reloc_dst->r_type   = H_GET_16 (abfd, reloc_src->r_type);
+}
+
+static unsigned int
+coff_swap_reloc_v0_out (bfd *abfd, void *src, void *dst)
+{
+  struct internal_reloc *reloc_src = (struct internal_reloc *) src;
+  struct external_reloc_v0 *reloc_dst = (struct external_reloc_v0 *) dst;
+
+  PUT_RELOC_VADDR (abfd, reloc_src->r_vaddr, reloc_dst->r_vaddr);
+  H_PUT_16 (abfd, reloc_src->r_symndx, reloc_dst->r_symndx);
+  H_PUT_16 (abfd, reloc_src->r_type, reloc_dst->r_type);
+  SWAP_OUT_RELOC_EXTRA (abfd, reloc_src, reloc_dst);
+
+  return bfd_coff_relsz (abfd);
+}
+#endif
+
 #endif /* NO_COFF_RELOCS */
 
 static void