From 1ed0032b40063795d6c3ce89eab3101a8fd67569 Mon Sep 17 00:00:00 2001 From: Alan Modra Date: Sun, 24 Oct 2021 20:27:06 +1030 Subject: [PATCH] asan: c4x, c54x coff_canonicalize_reloc buffer overflow 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 | 4 ++-- bfd/bfd-in2.h | 4 ++-- bfd/coff-tic54x.c | 2 +- bfd/coffcode.h | 22 +++++++++++----------- bfd/coffgen.c | 2 +- bfd/coffswap.h | 27 +++++++++++++++++++++++++++ 6 files changed, 44 insertions(+), 17 deletions(-) diff --git a/bfd/bfd-in.h b/bfd/bfd-in.h index 12176433045..286afc607a3 100644 --- a/bfd/bfd-in.h +++ b/bfd/bfd-in.h @@ -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 diff --git a/bfd/bfd-in2.h b/bfd/bfd-in2.h index 91888ef1852..669f250d0e5 100644 --- a/bfd/bfd-in2.h +++ b/bfd/bfd-in2.h @@ -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 diff --git a/bfd/coff-tic54x.c b/bfd/coff-tic54x.c index 63d36ae4375..86156711741 100644 --- a/bfd/coff-tic54x.c +++ b/bfd/coff-tic54x.c @@ -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)\ diff --git a/bfd/coffcode.h b/bfd/coffcode.h index c28d753011a..7967cedf918 100644 --- a/bfd/coffcode.h +++ b/bfd/coffcode.h @@ -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, diff --git a/bfd/coffgen.c b/bfd/coffgen.c index 77bda9e9947..6627a9af4b6 100644 --- a/bfd/coffgen.c +++ b/bfd/coffgen.c @@ -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. */ diff --git a/bfd/coffswap.h b/bfd/coffswap.h index 63a0026a669..e0dbd04f399 100644 --- a/bfd/coffswap.h +++ b/bfd/coffswap.h @@ -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 -- 2.30.2