From 2e6be59c8de57c32260771ac5307968d18793a0a Mon Sep 17 00:00:00 2001 From: Nick Clifton Date: Thu, 25 Jul 2019 13:05:27 +0100 Subject: [PATCH] Stop an illegal memory access by readelf when parsing a corrupt MIPS binary file. PR 24837 * readelf.c (process_mips_specific): Check for buffer overflow before reading reginfo information. --- binutils/ChangeLog | 6 ++++++ binutils/readelf.c | 39 +++++++++++++++++++++++++++++++++++---- 2 files changed, 41 insertions(+), 4 deletions(-) diff --git a/binutils/ChangeLog b/binutils/ChangeLog index 4d6d6e27fc7..635f2218717 100644 --- a/binutils/ChangeLog +++ b/binutils/ChangeLog @@ -1,3 +1,9 @@ +2019-07-25 Nick Clifton + + PR 24837 + * readelf.c (process_mips_specific): Check for buffer overflow + before reading reginfo information. + 2019-07-24 Nick Clifton PR 13256 diff --git a/binutils/readelf.c b/binutils/readelf.c index 1ba4bcb5793..6175b330179 100644 --- a/binutils/readelf.c +++ b/binutils/readelf.c @@ -16473,8 +16473,6 @@ process_mips_specific (Filedata * filedata) if (options_offset != 0) { Elf_External_Options * eopt; - Elf_Internal_Options * iopt; - Elf_Internal_Options * option; size_t offset; int cnt; sect = filedata->section_headers; @@ -16498,6 +16496,10 @@ process_mips_specific (Filedata * filedata) sect->sh_size, _("options")); if (eopt) { + 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)); if (iopt == NULL) @@ -16508,7 +16510,8 @@ 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)) { Elf_External_Options * eoption; @@ -16551,15 +16554,25 @@ process_mips_specific (Filedata * filedata) /* This shouldn't happen. */ printf (" NULL %d %lx", option->section, option->info); break; + case ODK_REGINFO: printf (" REGINFO "); if (filedata->file_header.e_machine == EM_MIPS) { - /* 32bit form. */ Elf32_External_RegInfo * ereg; Elf32_RegInfo reginfo; + /* 32bit form. */ + if (option + 2 > iopt_end) + { + printf (_("\n")); + error (_("Truncated MIPS REGINFO option\n")); + cnt = 0; + break; + } + ereg = (Elf32_External_RegInfo *) (option + 1); + reginfo.ri_gprmask = BYTE_GET (ereg->ri_gprmask); reginfo.ri_cprmask[0] = BYTE_GET (ereg->ri_cprmask[0]); reginfo.ri_cprmask[1] = BYTE_GET (ereg->ri_cprmask[1]); @@ -16580,6 +16593,14 @@ process_mips_specific (Filedata * filedata) Elf64_External_RegInfo * ereg; Elf64_Internal_RegInfo reginfo; + if (option + 2 > iopt_end) + { + printf (_("\n")); + error (_("Truncated MIPS REGINFO option\n")); + cnt = 0; + break; + } + ereg = (Elf64_External_RegInfo *) (option + 1); reginfo.ri_gprmask = BYTE_GET (ereg->ri_gprmask); reginfo.ri_cprmask[0] = BYTE_GET (ereg->ri_cprmask[0]); @@ -16599,6 +16620,7 @@ process_mips_specific (Filedata * filedata) } ++option; continue; + case ODK_EXCEPTIONS: fputs (" EXCEPTIONS fpe_min(", stdout); process_mips_fpe_exception (option->info & OEX_FPU_MIN); @@ -16615,6 +16637,7 @@ process_mips_specific (Filedata * filedata) if (option->info & OEX_DISMISS) fputs (" DISMISS", stdout); break; + case ODK_PAD: fputs (" PAD ", stdout); if (option->info & OPAD_PREFIX) @@ -16624,6 +16647,7 @@ process_mips_specific (Filedata * filedata) if (option->info & OPAD_SYMBOL) fputs (" SYMBOL", stdout); break; + case ODK_HWPATCH: fputs (" HWPATCH ", stdout); if (option->info & OHW_R4KEOP) @@ -16635,14 +16659,17 @@ process_mips_specific (Filedata * filedata) if (option->info & OHW_R5KCVTL) fputs (" R5KCVTL", stdout); break; + case ODK_FILL: fputs (" FILL ", stdout); /* XXX Print content of info word? */ break; + case ODK_TAGS: fputs (" TAGS ", stdout); /* XXX Print content of info word? */ break; + case ODK_HWAND: fputs (" HWAND ", stdout); if (option->info & OHWA0_R4KEOP_CHECKED) @@ -16650,6 +16677,7 @@ process_mips_specific (Filedata * filedata) if (option->info & OHWA0_R4KEOP_CLEAN) fputs (" R4KEOP_CLEAN", stdout); break; + case ODK_HWOR: fputs (" HWOR ", stdout); if (option->info & OHWA0_R4KEOP_CHECKED) @@ -16657,16 +16685,19 @@ process_mips_specific (Filedata * filedata) if (option->info & OHWA0_R4KEOP_CLEAN) fputs (" R4KEOP_CLEAN", stdout); break; + case ODK_GP_GROUP: printf (" GP_GROUP %#06lx self-contained %#06lx", option->info & OGP_GROUP, (option->info & OGP_SELF) >> 16); break; + case ODK_IDENT: printf (" IDENT %#06lx self-contained %#06lx", option->info & OGP_GROUP, (option->info & OGP_SELF) >> 16); break; + default: /* This shouldn't happen. */ printf (" %3d ??? %d %lx", -- 2.30.2