diff options
author | Alan Modra <amodra@gmail.com> | 2020-06-11 13:27:50 +0930 |
---|---|---|
committer | Alan Modra <amodra@gmail.com> | 2020-06-11 13:54:46 +0930 |
commit | d0c4e7802dae311d71059d0e2114150a5e09acf1 (patch) | |
tree | 9824b956af903fa6348c339ab5163d0d22db6af9 /binutils/readelf.c | |
parent | ec16513e310c2bfe4ff6d7e01b371858c6756c9e (diff) | |
download | gdb-d0c4e7802dae311d71059d0e2114150a5e09acf1.zip gdb-d0c4e7802dae311d71059d0e2114150a5e09acf1.tar.gz gdb-d0c4e7802dae311d71059d0e2114150a5e09acf1.tar.bz2 |
asan: readelf: process_mips_specific buffer overflow
DT_MIPS_OPTIONS is not a regular array as assumed by readelf. This
patch corrects that assumption, and to do so easily, makes various
internal (host byte order) structs the same size as external (target
byte order) structs.
include/
* elf/mips.h (Elf32_RegInfo): Use fixed width integer types.
(Elf64_Internal_RegInfo, Elf_Internal_Options): Likewise.
binutils/
* readelf.c (process_mips_specific): Assert size of internal
types match size of external types, and simplify allocation of
internal buffer. Catch possible integer overflow when sanity
checking option size. Don't assume options are a regular array.
Sanity check reginfo option against option size. Use PRI macros
when printing.
Diffstat (limited to 'binutils/readelf.c')
-rw-r--r-- | binutils/readelf.c | 51 |
1 files changed, 26 insertions, 25 deletions
diff --git a/binutils/readelf.c b/binutils/readelf.c index 0bdabcc..0705a49 100644 --- a/binutils/readelf.c +++ b/binutils/readelf.c @@ -16896,10 +16896,11 @@ process_mips_specific (Filedata * filedata) { Elf_Internal_Options * iopt; Elf_Internal_Options * option; - Elf_Internal_Options * iopt_end; - iopt = (Elf_Internal_Options *) - cmalloc ((sect->sh_size / sizeof (eopt)), sizeof (* iopt)); + assert (sizeof (Elf_Internal_Options) == sizeof (Elf_External_Options)); + assert (sizeof (Elf32_RegInfo) == sizeof (Elf32_External_RegInfo)); + assert (sizeof (Elf64_Internal_RegInfo) == sizeof (Elf64_External_RegInfo)); + iopt = (Elf_Internal_Options *) cmalloc (sect->sh_size, 1); if (iopt == NULL) { error (_("Out of memory allocating space for MIPS options\n")); @@ -16909,7 +16910,6 @@ process_mips_specific (Filedata * filedata) offset = cnt = 0; option = iopt; - iopt_end = iopt + (sect->sh_size / sizeof (eopt)); while (offset <= sect->sh_size - sizeof (* eopt)) { @@ -16924,7 +16924,7 @@ process_mips_specific (Filedata * filedata) /* PR 17531: file: ffa0fa3b. */ if (option->size < sizeof (* eopt) - || offset + option->size > sect->sh_size) + || option->size > sect->sh_size - offset) { error (_("Invalid size (%u) for MIPS option\n"), option->size); @@ -16943,18 +16943,18 @@ process_mips_specific (Filedata * filedata) cnt), printable_section_name (filedata, sect), cnt); - option = iopt; offset = 0; - while (cnt-- > 0) { size_t len; + option = (Elf_Internal_Options *) ((char *) iopt + offset); switch (option->kind) { case ODK_NULL: /* This shouldn't happen. */ - printf (" NULL %d %lx", option->section, option->info); + printf (" NULL %" PRId16 " %" PRIx32, + option->section, option->info); break; case ODK_REGINFO: @@ -16965,7 +16965,8 @@ process_mips_specific (Filedata * filedata) Elf32_RegInfo reginfo; /* 32bit form. */ - if (option + 2 > iopt_end) + if (option->size < (sizeof (Elf_External_Options) + + sizeof (Elf32_External_RegInfo))) { printf (_("<corrupt>\n")); error (_("Truncated MIPS REGINFO option\n")); @@ -16982,10 +16983,11 @@ process_mips_specific (Filedata * filedata) reginfo.ri_cprmask[3] = BYTE_GET (ereg->ri_cprmask[3]); reginfo.ri_gp_value = BYTE_GET (ereg->ri_gp_value); - printf ("GPR %08lx GP 0x%lx\n", - reginfo.ri_gprmask, - (unsigned long) reginfo.ri_gp_value); - printf (" CPR0 %08lx CPR1 %08lx CPR2 %08lx CPR3 %08lx\n", + printf ("GPR %08" PRIx32 " GP 0x%" PRIx32 "\n", + reginfo.ri_gprmask, reginfo.ri_gp_value); + printf (" " + " CPR0 %08" PRIx32 " CPR1 %08" PRIx32 + " CPR2 %08" PRIx32 " CPR3 %08" PRIx32 "\n", reginfo.ri_cprmask[0], reginfo.ri_cprmask[1], reginfo.ri_cprmask[2], reginfo.ri_cprmask[3]); } @@ -16995,7 +16997,8 @@ process_mips_specific (Filedata * filedata) Elf64_External_RegInfo * ereg; Elf64_Internal_RegInfo reginfo; - if (option + 2 > iopt_end) + if (option->size < (sizeof (Elf_External_Options) + + sizeof (Elf64_External_RegInfo))) { printf (_("<corrupt>\n")); error (_("Truncated MIPS REGINFO option\n")); @@ -17011,16 +17014,15 @@ process_mips_specific (Filedata * filedata) reginfo.ri_cprmask[3] = BYTE_GET (ereg->ri_cprmask[3]); reginfo.ri_gp_value = BYTE_GET (ereg->ri_gp_value); - printf ("GPR %08lx GP 0x", - reginfo.ri_gprmask); - printf_vma (reginfo.ri_gp_value); - printf ("\n"); - - printf (" CPR0 %08lx CPR1 %08lx CPR2 %08lx CPR3 %08lx\n", + printf ("GPR %08" PRIx32 " GP 0x%" PRIx64 "\n", + reginfo.ri_gprmask, reginfo.ri_gp_value); + printf (" " + " CPR0 %08" PRIx32 " CPR1 %08" PRIx32 + " CPR2 %08" PRIx32 " CPR3 %08" PRIx32 "\n", reginfo.ri_cprmask[0], reginfo.ri_cprmask[1], reginfo.ri_cprmask[2], reginfo.ri_cprmask[3]); } - ++option; + offset += option->size; continue; case ODK_EXCEPTIONS: @@ -17089,20 +17091,20 @@ process_mips_specific (Filedata * filedata) break; case ODK_GP_GROUP: - printf (" GP_GROUP %#06lx self-contained %#06lx", + printf (" GP_GROUP %#06x self-contained %#06x", option->info & OGP_GROUP, (option->info & OGP_SELF) >> 16); break; case ODK_IDENT: - printf (" IDENT %#06lx self-contained %#06lx", + printf (" IDENT %#06x self-contained %#06x", option->info & OGP_GROUP, (option->info & OGP_SELF) >> 16); break; default: /* This shouldn't happen. */ - printf (" %3d ??? %d %lx", + printf (" %3d ??? %" PRId16 " %" PRIx32, option->kind, option->section, option->info); break; } @@ -17121,7 +17123,6 @@ process_mips_specific (Filedata * filedata) fputs ("\n", stdout); offset += option->size; - ++option; } free (iopt); free (eopt); |