aboutsummaryrefslogtreecommitdiff
path: root/bfd/elflink.c
diff options
context:
space:
mode:
authorNick Clifton <nickc@redhat.com>2019-03-14 14:45:32 +0000
committerNick Clifton <nickc@redhat.com>2019-03-14 14:45:32 +0000
commitbe22c732bf873e0c7e8a08564c97cafdfcf153bb (patch)
tree779aef5992f5920439e815d320be7f2038ace442 /bfd/elflink.c
parent3b336828de914a39741339b5341b88aa003d7225 (diff)
downloadgdb-be22c732bf873e0c7e8a08564c97cafdfcf153bb.zip
gdb-be22c732bf873e0c7e8a08564c97cafdfcf153bb.tar.gz
gdb-be22c732bf873e0c7e8a08564c97cafdfcf153bb.tar.bz2
Fix illegal memory access parsing a corrupt ELF file.
PR 24332 * elflink.c (elf_link_add_object_symbols): Add new local variable extversym_end. Initialise it to point to the end of the version symbol table, if present. Check it when initialising and updating the ever pointer.
Diffstat (limited to 'bfd/elflink.c')
-rw-r--r--bfd/elflink.c29
1 files changed, 26 insertions, 3 deletions
diff --git a/bfd/elflink.c b/bfd/elflink.c
index e50c0e4..3ac58da 100644
--- a/bfd/elflink.c
+++ b/bfd/elflink.c
@@ -3872,6 +3872,7 @@ elf_link_add_object_symbols (bfd *abfd, struct bfd_link_info *info)
struct elf_link_hash_entry **sym_hash;
bfd_boolean dynamic;
Elf_External_Versym *extversym = NULL;
+ Elf_External_Versym *extversym_end = NULL;
Elf_External_Versym *ever;
struct elf_link_hash_entry *weaks;
struct elf_link_hash_entry **nondeflt_vers = NULL;
@@ -4297,13 +4298,14 @@ error_free_dyn:
Elf_Internal_Shdr *versymhdr;
versymhdr = &elf_tdata (abfd)->dynversym_hdr;
- extversym = (Elf_External_Versym *) bfd_malloc (versymhdr->sh_size);
+ amt = versymhdr->sh_size;
+ extversym = (Elf_External_Versym *) bfd_malloc (amt);
if (extversym == NULL)
goto error_free_sym;
- amt = versymhdr->sh_size;
if (bfd_seek (abfd, versymhdr->sh_offset, SEEK_SET) != 0
|| bfd_bread (extversym, amt, abfd) != amt)
goto error_free_vers;
+ extversym_end = extversym + (amt / sizeof (* extversym));
}
}
@@ -4378,7 +4380,20 @@ error_free_dyn:
}
weaks = NULL;
- ever = extversym != NULL ? extversym + extsymoff : NULL;
+ if (extversym == NULL)
+ ever = NULL;
+ else if (extversym + extsymoff < extversym_end)
+ ever = extversym + extsymoff;
+ else
+ {
+ /* xgettext:c-format */
+ _bfd_error_handler (_("%pB: invalid version offset %lx (max %lx)"),
+ abfd, (long) extsymoff,
+ (long) (extversym_end - extversym) / sizeof (* extversym));
+ bfd_set_error (bfd_error_bad_value);
+ goto error_free_vers;
+ }
+
for (isym = isymbuf, isymend = isymbuf + extsymcount;
isym < isymend;
isym++, sym_hash++, ever = (ever != NULL ? ever + 1 : NULL))
@@ -4562,6 +4577,14 @@ error_free_dyn:
else
iver.vs_vers = 0;
}
+ else if (ever >= extversym_end)
+ {
+ /* xgettext:c-format */
+ _bfd_error_handler (_("%pB: not enough version information"),
+ abfd);
+ bfd_set_error (bfd_error_bad_value);
+ goto error_free_vers;
+ }
else
_bfd_elf_swap_versym_in (abfd, ever, &iver);