diff options
Diffstat (limited to 'debian/patches/pr21139.diff')
-rw-r--r-- | debian/patches/pr21139.diff | 227 |
1 files changed, 227 insertions, 0 deletions
diff --git a/debian/patches/pr21139.diff b/debian/patches/pr21139.diff new file mode 100644 index 0000000..0183594 --- /dev/null +++ b/debian/patches/pr21139.diff @@ -0,0 +1,227 @@ +# DP: Fix PR binutils/21139, read-after-free error in readelf. + +From f84ce13b6708801ca1d6289b7c4003e2f5a6d7f9 Mon Sep 17 00:00:00 2001 +From: Nick Clifton <nickc@redhat.com> +Date: Mon, 13 Feb 2017 14:03:22 +0000 +Subject: [PATCH] Fix read-after-free error in readelf when processing + multiple, relocated sections in an MSP430 binary. + + PR binutils/21139 + * readelf.c (target_specific_reloc_handling): Add num_syms + parameter. Check for symbol table overflow before accessing + symbol value. If reloc pointer is NULL, discard all saved state. + (apply_relocations): Pass num_syms to target_specific_reloc_handling. + Call target_specific_reloc_handling with a NULL reloc pointer + after processing all of the relocs. +--- + binutils/ChangeLog | 10 +++++ + binutils/readelf.c | 109 +++++++++++++++++++++++++++++++++++++++++------------ + 2 files changed, 94 insertions(+), 25 deletions(-) + +2017-02-13 Nick Clifton <nickc@redhat.com> + + PR binutils/21139 + * readelf.c (target_specific_reloc_handling): Add num_syms + parameter. Check for symbol table overflow before accessing + symbol value. If reloc pointer is NULL, discard all saved state. + (apply_relocations): Pass num_syms to target_specific_reloc_handling. + Call target_specific_reloc_handling with a NULL reloc pointer + after processing all of the relocs. + +diff --git a/binutils/readelf.c b/binutils/readelf.c +index e474f27..de961c4 100644 +--- a/binutils/readelf.c ++++ b/binutils/readelf.c +@@ -11586,15 +11586,27 @@ process_syminfo (FILE * file ATTRIBUTE_UNUSED) + + /* Check to see if the given reloc needs to be handled in a target specific + manner. If so then process the reloc and return TRUE otherwise return +- FALSE. */ ++ FALSE. ++ ++ If called with reloc == NULL, then this is a signal that reloc processing ++ for the current section has finished, and any saved state should be ++ discarded. */ + + static bfd_boolean + target_specific_reloc_handling (Elf_Internal_Rela * reloc, + unsigned char * start, + unsigned char * end, +- Elf_Internal_Sym * symtab) ++ Elf_Internal_Sym * symtab, ++ unsigned long num_syms) + { +- unsigned int reloc_type = get_reloc_type (reloc->r_info); ++ unsigned int reloc_type = 0; ++ unsigned long sym_index = 0; ++ ++ if (reloc) ++ { ++ reloc_type = get_reloc_type (reloc->r_info); ++ sym_index = get_reloc_symindex (reloc->r_info); ++ } + + switch (elf_header.e_machine) + { +@@ -11603,6 +11615,12 @@ target_specific_reloc_handling (Elf_Internal_Rela * reloc, + { + static Elf_Internal_Sym * saved_sym = NULL; + ++ if (reloc == NULL) ++ { ++ saved_sym = NULL; ++ return TRUE; ++ } ++ + switch (reloc_type) + { + case 10: /* R_MSP430_SYM_DIFF */ +@@ -11610,7 +11628,12 @@ target_specific_reloc_handling (Elf_Internal_Rela * reloc, + break; + /* Fall through. */ + case 21: /* R_MSP430X_SYM_DIFF */ +- saved_sym = symtab + get_reloc_symindex (reloc->r_info); ++ /* PR 21139. */ ++ if (sym_index >= num_syms) ++ error (_("MSP430 SYM_DIFF reloc contains invalid symbol index %lu\n"), ++ sym_index); ++ else ++ saved_sym = symtab + sym_index; + return TRUE; + + case 1: /* R_MSP430_32 or R_MSP430_ABS32 */ +@@ -11635,16 +11658,21 @@ target_specific_reloc_handling (Elf_Internal_Rela * reloc, + int reloc_size = reloc_type == 1 ? 4 : 2; + bfd_vma value; + +- value = reloc->r_addend +- + (symtab[get_reloc_symindex (reloc->r_info)].st_value +- - saved_sym->st_value); +- +- if (start + reloc->r_offset + reloc_size >= end) +- /* PR 21137 */ +- error (_("MSP430 sym diff reloc writes past end of section (%p vs %p)\n"), +- start + reloc->r_offset + reloc_size, end); ++ if (sym_index >= num_syms) ++ error (_("MSP430 reloc contains invalid symbol index %lu\n"), ++ sym_index); + else +- byte_put (start + reloc->r_offset, value, reloc_size); ++ { ++ value = reloc->r_addend + (symtab[sym_index].st_value ++ - saved_sym->st_value); ++ ++ if (start + reloc->r_offset + reloc_size >= end) ++ /* PR 21137 */ ++ error (_("MSP430 sym diff reloc writes past end of section (%p vs %p)\n"), ++ start + reloc->r_offset + reloc_size, end); ++ else ++ byte_put (start + reloc->r_offset, value, reloc_size); ++ } + + saved_sym = NULL; + return TRUE; +@@ -11664,13 +11692,24 @@ target_specific_reloc_handling (Elf_Internal_Rela * reloc, + { + static Elf_Internal_Sym * saved_sym = NULL; + ++ if (reloc == NULL) ++ { ++ saved_sym = NULL; ++ return TRUE; ++ } ++ + switch (reloc_type) + { + case 34: /* R_MN10300_ALIGN */ + return TRUE; + case 33: /* R_MN10300_SYM_DIFF */ +- saved_sym = symtab + get_reloc_symindex (reloc->r_info); ++ if (sym_index >= num_syms) ++ error (_("MN10300_SYM_DIFF reloc contains invalid symbol index %lu\n"), ++ sym_index); ++ else ++ saved_sym = symtab + sym_index; + return TRUE; ++ + case 1: /* R_MN10300_32 */ + case 2: /* R_MN10300_16 */ + if (saved_sym != NULL) +@@ -11678,15 +11717,20 @@ target_specific_reloc_handling (Elf_Internal_Rela * reloc, + int reloc_size = reloc_type == 1 ? 4 : 2; + bfd_vma value; + +- value = reloc->r_addend +- + (symtab[get_reloc_symindex (reloc->r_info)].st_value +- - saved_sym->st_value); +- +- if (start + reloc->r_offset + reloc_size >= end) +- error (_("MN10300 sym diff reloc writes past end of section (%p vs %p)\n"), +- start + reloc->r_offset + reloc_size, end); ++ if (sym_index >= num_syms) ++ error (_("MN10300 reloc contains invalid symbol index %lu\n"), ++ sym_index); + else +- byte_put (start + reloc->r_offset, value, reloc_size); ++ { ++ value = reloc->r_addend + (symtab[sym_index].st_value ++ - saved_sym->st_value); ++ ++ if (start + reloc->r_offset + reloc_size >= end) ++ error (_("MN10300 sym diff reloc writes past end of section (%p vs %p)\n"), ++ start + reloc->r_offset + reloc_size, end); ++ else ++ byte_put (start + reloc->r_offset, value, reloc_size); ++ } + + saved_sym = NULL; + return TRUE; +@@ -11706,12 +11750,24 @@ target_specific_reloc_handling (Elf_Internal_Rela * reloc, + static bfd_vma saved_sym2 = 0; + static bfd_vma value; + ++ if (reloc == NULL) ++ { ++ saved_sym1 = saved_sym2 = 0; ++ return TRUE; ++ } ++ + switch (reloc_type) + { + case 0x80: /* R_RL78_SYM. */ + saved_sym1 = saved_sym2; +- saved_sym2 = symtab[get_reloc_symindex (reloc->r_info)].st_value; +- saved_sym2 += reloc->r_addend; ++ if (sym_index >= num_syms) ++ error (_("RL78_SYM reloc contains invalid symbol index %lu\n"), ++ sym_index); ++ else ++ { ++ saved_sym2 = symtab[sym_index].st_value; ++ saved_sym2 += reloc->r_addend; ++ } + return TRUE; + + case 0x83: /* R_RL78_OPsub. */ +@@ -12360,7 +12416,7 @@ apply_relocations (void * file, + + reloc_type = get_reloc_type (rp->r_info); + +- if (target_specific_reloc_handling (rp, start, end, symtab)) ++ if (target_specific_reloc_handling (rp, start, end, symtab, num_syms)) + continue; + else if (is_none_reloc (reloc_type)) + continue; +@@ -12456,6 +12512,9 @@ apply_relocations (void * file, + } + + free (symtab); ++ /* Let the target specific reloc processing code know that ++ we have finished with these relocs. */ ++ target_specific_reloc_handling (NULL, NULL, NULL, NULL, 0); + + if (relocs_return) + { +-- +2.9.3 + |