aboutsummaryrefslogtreecommitdiff
path: root/binutils/readelf.c
diff options
context:
space:
mode:
authorNick Clifton <nickc@redhat.com>2017-02-13 13:08:32 +0000
committerNick Clifton <nickc@redhat.com>2017-02-13 13:08:32 +0000
commit03f7786e2f440b9892b1c34a58fb26222ce1b493 (patch)
tree971cf273051f9b7249a1e3ac3287109160a52eae /binutils/readelf.c
parent13a590ca65f744c8fa55d6e0748cb12f443493f0 (diff)
downloadgdb-03f7786e2f440b9892b1c34a58fb26222ce1b493.zip
gdb-03f7786e2f440b9892b1c34a58fb26222ce1b493.tar.gz
gdb-03f7786e2f440b9892b1c34a58fb26222ce1b493.tar.bz2
Fix readelf writing to illegal addresses whilst processing corrupt input files containing symbol-difference relocations.
PR binutils/21137 * readelf.c (target_specific_reloc_handling): Add end parameter. Check for buffer overflow before writing relocated values. (apply_relocations): Pass end to target_specific_reloc_handling.
Diffstat (limited to 'binutils/readelf.c')
-rw-r--r--binutils/readelf.c30
1 files changed, 25 insertions, 5 deletions
diff --git a/binutils/readelf.c b/binutils/readelf.c
index b488714..e474f27 100644
--- a/binutils/readelf.c
+++ b/binutils/readelf.c
@@ -11591,6 +11591,7 @@ process_syminfo (FILE * file ATTRIBUTE_UNUSED)
static bfd_boolean
target_specific_reloc_handling (Elf_Internal_Rela * reloc,
unsigned char * start,
+ unsigned char * end,
Elf_Internal_Sym * symtab)
{
unsigned int reloc_type = get_reloc_type (reloc->r_info);
@@ -11631,13 +11632,19 @@ target_specific_reloc_handling (Elf_Internal_Rela * reloc,
handle_sym_diff:
if (saved_sym != NULL)
{
+ 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);
- byte_put (start + reloc->r_offset, value, reloc_type == 1 ? 4 : 2);
+ 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;
@@ -11668,13 +11675,18 @@ target_specific_reloc_handling (Elf_Internal_Rela * reloc,
case 2: /* R_MN10300_16 */
if (saved_sym != NULL)
{
+ 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);
- byte_put (start + reloc->r_offset, value, reloc_type == 1 ? 4 : 2);
+ 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;
@@ -11709,12 +11721,20 @@ target_specific_reloc_handling (Elf_Internal_Rela * reloc,
break;
case 0x41: /* R_RL78_ABS32. */
- byte_put (start + reloc->r_offset, value, 4);
+ if (start + reloc->r_offset + 4 >= end)
+ error (_("RL78 sym diff reloc writes past end of section (%p vs %p)\n"),
+ start + reloc->r_offset + 2, end);
+ else
+ byte_put (start + reloc->r_offset, value, 4);
value = 0;
return TRUE;
case 0x43: /* R_RL78_ABS16. */
- byte_put (start + reloc->r_offset, value, 2);
+ if (start + reloc->r_offset + 2 >= end)
+ error (_("RL78 sym diff reloc writes past end of section (%p vs %p)\n"),
+ start + reloc->r_offset + 2, end);
+ else
+ byte_put (start + reloc->r_offset, value, 2);
value = 0;
return TRUE;
@@ -12340,7 +12360,7 @@ apply_relocations (void * file,
reloc_type = get_reloc_type (rp->r_info);
- if (target_specific_reloc_handling (rp, start, symtab))
+ if (target_specific_reloc_handling (rp, start, end, symtab))
continue;
else if (is_none_reloc (reloc_type))
continue;