From 74fd118fb91f49377b63931d092b6d42dd8b3b3c Mon Sep 17 00:00:00 2001 From: Nick Clifton Date: Tue, 25 May 2021 11:22:15 +0100 Subject: [PATCH] Add range checks to local array accesses in elf32-arm.c. bfd * elf32-arn.c (struct elf_arm_obj_tdata): Add num_entries field. (elf32_arm_num_entries): New macro. (elf32_arm_allocate_local_sym_info): Initialise the new field. Allocate arrays individually so that buffer overruns can be detected by memory checkers. (elf32_arm_create_local_iplt): Check num_entries. (elf32_arm_get_plt_info): Likewise. (elf32_arm_final_link_relocate): Likewise. (elf32_arm_check_relocs): Likewise. (elf32_arm_size_dynamic_sections): Likewise. (elf32_arm_output_arch_local_syms): Likewise. --- bfd/ChangeLog | 14 ++++++ bfd/elf32-arm.c | 112 +++++++++++++++++++++++++++++++++++++++--------- 2 files changed, 105 insertions(+), 21 deletions(-) diff --git a/bfd/ChangeLog b/bfd/ChangeLog index 248044fe94d..fec2dcbb681 100644 --- a/bfd/ChangeLog +++ b/bfd/ChangeLog @@ -1,3 +1,17 @@ +2021-05-25 Nick Clifton + + * elf32-arn.c (struct elf_arm_obj_tdata): Add num_entries field. + (elf32_arm_num_entries): New macro. + (elf32_arm_allocate_local_sym_info): Initialise the new field. + Allocate arrays individually so that buffer overruns can be + detected by memory checkers. + (elf32_arm_create_local_iplt): Check num_entries. + (elf32_arm_get_plt_info): Likewise. + (elf32_arm_final_link_relocate): Likewise. + (elf32_arm_check_relocs): Likewise. + (elf32_arm_size_dynamic_sections): Likewise. + (elf32_arm_output_arch_local_syms): Likewise. + 2021-05-25 Nick Clifton * elf32-arm.c: Fix formatting. diff --git a/bfd/elf32-arm.c b/bfd/elf32-arm.c index cab9264b7fa..a9119c49780 100644 --- a/bfd/elf32-arm.c +++ b/bfd/elf32-arm.c @@ -3152,6 +3152,10 @@ struct elf_arm_obj_tdata /* Zero to warn when linking objects with incompatible wchar_t sizes. */ int no_wchar_size_warning; + /* The number of entries in each of the arrays in this strcuture. + Used to avoid buffer overruns. */ + bfd_size_type num_entries; + /* tls_type for each local got entry. */ char *local_got_tls_type; @@ -3168,6 +3172,9 @@ struct elf_arm_obj_tdata #define elf_arm_tdata(bfd) \ ((struct elf_arm_obj_tdata *) (bfd)->tdata.any) +#define elf32_arm_num_entries(bfd) \ + (elf_arm_tdata (bfd)->num_entries) + #define elf32_arm_local_got_tls_type(bfd) \ (elf_arm_tdata (bfd)->local_got_tls_type) @@ -3581,35 +3588,48 @@ elf32_arm_allocate_local_sym_info (bfd *abfd) if (elf_local_got_refcounts (abfd) == NULL) { bfd_size_type num_syms; - bfd_size_type size; - char *data; + + elf32_arm_num_entries (abfd) = 0; + + /* Whilst it might be tempting to allocate a single block of memory and + then divide it up amoungst the arrays in the elf_arm_obj_tdata + structure, this interferes with the work of memory checkers looking + for buffer overruns. So allocate each array individually. */ num_syms = elf_tdata (abfd)->symtab_hdr.sh_info; - size = num_syms * (sizeof (bfd_signed_vma) - + sizeof (bfd_vma) - + sizeof (struct arm_local_iplt_info *) - + sizeof (struct fdpic_local) - + sizeof (char)); - data = bfd_zalloc (abfd, size); - if (data == NULL) + + elf_local_got_refcounts (abfd) = bfd_zalloc + (abfd, num_syms * sizeof (* elf_local_got_refcounts (abfd))); + + if (elf_local_got_refcounts (abfd) == NULL) return false; - /* It is important that these all be allocated in descending - order of required alignment, so that arrays allocated later - will be sufficiently aligned. */ - elf_local_got_refcounts (abfd) = (bfd_signed_vma *) data; - data += num_syms * sizeof (bfd_signed_vma); + elf32_arm_local_tlsdesc_gotent (abfd) = bfd_zalloc + (abfd, num_syms * sizeof (* elf32_arm_local_tlsdesc_gotent (abfd))); - elf32_arm_local_tlsdesc_gotent (abfd) = (bfd_vma *) data; - data += num_syms * sizeof (bfd_vma); + if (elf32_arm_local_tlsdesc_gotent (abfd) == NULL) + return false; - elf32_arm_local_iplt (abfd) = (struct arm_local_iplt_info **) data; - data += num_syms * sizeof (struct arm_local_iplt_info *); + elf32_arm_local_iplt (abfd) = bfd_zalloc + (abfd, num_syms * sizeof (* elf32_arm_local_iplt (abfd))); - elf32_arm_local_fdpic_cnts (abfd) = (struct fdpic_local *) data; - data += num_syms * sizeof (struct fdpic_local); + if (elf32_arm_local_iplt (abfd) == NULL) + return false; + + elf32_arm_local_fdpic_cnts (abfd) = bfd_zalloc + (abfd, num_syms * sizeof (* elf32_arm_local_fdpic_cnts (abfd))); + + if (elf32_arm_local_fdpic_cnts (abfd) == NULL) + return false; + + elf32_arm_local_got_tls_type (abfd) = bfd_zalloc + (abfd, num_syms * sizeof (* elf32_arm_local_got_tls_type (abfd))); + + if (elf32_arm_local_got_tls_type (abfd) == NULL) + return false; + + elf32_arm_num_entries (abfd) = num_syms; - elf32_arm_local_got_tls_type (abfd) = data; #if GCC_VERSION >= 3000 BFD_ASSERT (__alignof__ (*elf32_arm_local_tlsdesc_gotent (abfd)) <= __alignof__ (*elf_local_got_refcounts (abfd))); @@ -3637,6 +3657,7 @@ elf32_arm_create_local_iplt (bfd *abfd, unsigned long r_symndx) return NULL; BFD_ASSERT (r_symndx < elf_tdata (abfd)->symtab_hdr.sh_info); + BFD_ASSERT (r_symndx < elf32_arm_num_entries (abfd)); ptr = &elf32_arm_local_iplt (abfd)[r_symndx]; if (*ptr == NULL) *ptr = bfd_zalloc (abfd, sizeof (**ptr)); @@ -3672,6 +3693,9 @@ elf32_arm_get_plt_info (bfd *abfd, struct elf32_arm_link_hash_table *globals, if (elf32_arm_local_iplt (abfd) == NULL) return false; + if (r_symndx >= elf32_arm_num_entries (abfd)) + return false; + local_iplt = elf32_arm_local_iplt (abfd)[r_symndx]; if (local_iplt == NULL) return false; @@ -11649,6 +11673,15 @@ elf32_arm_final_link_relocate (reloc_howto_type * howto, { BFD_ASSERT (local_got_offsets != NULL); + if (r_symndx >= elf32_arm_num_entries (input_bfd)) + { + _bfd_error_handler (_("\ +%pB: expected symbol index in range 0..%lu but found local symbol with index %lu"), + input_bfd, + (unsigned long) elf32_arm_num_entries (input_bfd), + r_symndx); + return false; + } off = local_got_offsets[r_symndx]; offplt = local_tlsdesc_gotents[r_symndx]; tls_type = elf32_arm_local_got_tls_type (input_bfd)[r_symndx]; @@ -12569,6 +12602,13 @@ elf32_arm_final_link_relocate (reloc_howto_type * howto, { struct fdpic_local *local_fdpic_cnts = elf32_arm_local_fdpic_cnts (input_bfd); int dynindx = elf_section_data (sym_sec->output_section)->dynindx; + + if (r_symndx >= elf32_arm_num_entries (input_bfd)) + { + * error_message = _("local symbol index too big"); + return bfd_reloc_dangerous; + } + int offset = local_fdpic_cnts[r_symndx].funcdesc_offset & ~1; bfd_vma addr = dynreloc_value - sym_sec->output_section->vma; bfd_vma seg = -1; @@ -12721,6 +12761,13 @@ elf32_arm_final_link_relocate (reloc_howto_type * howto, struct fdpic_local *local_fdpic_cnts = elf32_arm_local_fdpic_cnts (input_bfd); Elf_Internal_Rela outrel; int dynindx = elf_section_data (sym_sec->output_section)->dynindx; + + if (r_symndx >= elf32_arm_num_entries (input_bfd)) + { + * error_message = _("local symbol index too big"); + return bfd_reloc_dangerous; + } + int offset = local_fdpic_cnts[r_symndx].funcdesc_offset & ~1; bfd_vma addr = dynreloc_value - sym_sec->output_section->vma; bfd_vma seg = -1; @@ -15277,6 +15324,8 @@ elf32_arm_check_relocs (bfd *abfd, struct bfd_link_info *info, { if (!elf32_arm_allocate_local_sym_info (abfd)) return false; + if (r_symndx >= elf32_arm_num_entries (abfd)) + return false; elf32_arm_local_fdpic_cnts (abfd) [r_symndx].gotofffuncdesc_cnt += 1; elf32_arm_local_fdpic_cnts (abfd) [r_symndx].funcdesc_offset = -1; } @@ -15309,6 +15358,8 @@ elf32_arm_check_relocs (bfd *abfd, struct bfd_link_info *info, { if (!elf32_arm_allocate_local_sym_info (abfd)) return false; + if (r_symndx >= elf32_arm_num_entries (abfd)) + return false; elf32_arm_local_fdpic_cnts (abfd) [r_symndx].funcdesc_cnt += 1; elf32_arm_local_fdpic_cnts (abfd) [r_symndx].funcdesc_offset = -1; } @@ -15363,6 +15414,13 @@ elf32_arm_check_relocs (bfd *abfd, struct bfd_link_info *info, /* This is a global offset table entry for a local symbol. */ if (!elf32_arm_allocate_local_sym_info (abfd)) return false; + if (r_symndx >= elf32_arm_num_entries (abfd)) + { + _bfd_error_handler (_("%pB: bad symbol index: %d"), abfd, + r_symndx); + return false; + } + elf_local_got_refcounts (abfd)[r_symndx] += 1; old_tls_type = elf32_arm_local_got_tls_type (abfd) [r_symndx]; } @@ -16703,6 +16761,9 @@ elf32_arm_size_dynamic_sections (bfd * output_bfd ATTRIBUTE_UNUSED, ++local_got, ++local_iplt_ptr, ++local_tls_type, ++local_tlsdesc_gotent, ++symndx, ++local_fdpic_cnts) { + if (symndx >= elf32_arm_num_entries (ibfd)) + return false; + *local_tlsdesc_gotent = (bfd_vma) -1; local_iplt = *local_iplt_ptr; @@ -18164,6 +18225,15 @@ elf32_arm_output_arch_local_syms (bfd *output_bfd, if (local_iplt != NULL) { num_syms = elf_symtab_hdr (input_bfd).sh_info; + if (num_syms > elf32_arm_num_entries (input_bfd)) + { + _bfd_error_handler (_("\ +%pB: Number of symbols in input file has increased from %lu to %u\n"), + input_bfd, + (unsigned long) elf32_arm_num_entries (input_bfd), + num_syms); + return false; + } for (i = 0; i < num_syms; i++) if (local_iplt[i] != NULL && !elf32_arm_output_plt_map_1 (&osi, true, -- 2.30.2