--- binutils/readelf.c.orig 2010-08-05 22:09:25.000000000 -0400 +++ binutils/readelf.c 2010-08-05 22:44:23.000000000 -0400 @@ -3774,7 +3774,26 @@ get_32bit_elf_symbols (FILE * file, Elf_ } } + if (section->sh_entsize == 0) + { + error (_("Invalid sh_entsize\n")); + if (shndx) + free (shndx); + free (esyms); + return NULL; + } + number = section->sh_size / section->sh_entsize; + + if (number * sizeof (Elf32_External_Sym) > section->sh_size + 1) + { + error (_("Invalid sh_entsize\n")); + if (shndx) + free (shndx); + free (esyms); + return NULL; + } + isyms = (Elf_Internal_Sym *) cmalloc (number, sizeof (Elf_Internal_Sym)); if (isyms == NULL) @@ -3841,7 +3860,26 @@ get_64bit_elf_symbols (FILE * file, Elf_ } } + if (section->sh_entsize == 0) + { + error (_("Invalid sh_entsize\n")); + if (shndx) + free (shndx); + free (esyms); + return NULL; + } + number = section->sh_size / section->sh_entsize; + + if (number * sizeof (Elf64_External_Sym) > section->sh_size + 1) + { + error (_("Invalid sh_entsize\n")); + if (shndx) + free (shndx); + free (esyms); + return NULL; + } + isyms = (Elf_Internal_Sym *) cmalloc (number, sizeof (Elf_Internal_Sym)); if (isyms == NULL) @@ -4636,6 +4674,12 @@ process_section_groups (FILE * file) symtab = GET_ELF_SYMBOLS (file, symtab_sec); } + if (!symtab) + { + error (_("Corrupt header in group section `%s'\n"), name); + continue; + } + sym = symtab + section->sh_info; if (ELF_ST_TYPE (sym->st_info) == STT_SECTION) @@ -6608,6 +6652,9 @@ process_version_sections (FILE * file) int j; int isum; + if ((unsigned) edefs + idx < (unsigned) edefs) + break; + vstart = ((char *) edefs) + idx; if (vstart + sizeof (*edef) > endbuf) break; @@ -6628,6 +6675,11 @@ process_version_sections (FILE * file) printf (_(" Index: %d Cnt: %d "), ent.vd_ndx, ent.vd_cnt); + /* Check for overflow */ + if ((unsigned)(vstart + ent.vd_aux) < (unsigned)vstart || + (unsigned)(vstart + ent.vd_aux) > (unsigned)endbuf) + break; + vstart += ent.vd_aux; eaux = (Elf_External_Verdaux *) vstart; @@ -6644,6 +6696,12 @@ process_version_sections (FILE * file) for (j = 1; j < ent.vd_cnt; j++) { + + /* Check for overflow */ + if ((unsigned)(vstart + aux.vda_next) < (unsigned)vstart || + (unsigned)(vstart + aux.vda_next) > (unsigned)endbuf) + break; + isum += aux.vda_next; vstart += aux.vda_next; @@ -6709,6 +6767,9 @@ process_version_sections (FILE * file) int isum; char * vstart; + if ((unsigned)eneed + idx < (unsigned)eneed) + break; + vstart = ((char *) eneed) + idx; if (vstart + sizeof (*entry) > endbuf) break; @@ -6730,6 +6791,11 @@ process_version_sections (FILE * file) printf (_(" Cnt: %d\n"), ent.vn_cnt); + /* Check for overflow */ + if ((unsigned)(vstart + ent.vn_aux) < (unsigned)vstart || + (unsigned)(vstart + ent.vn_aux) > (unsigned)endbuf) + break; + vstart += ent.vn_aux; for (j = 0, isum = idx + ent.vn_aux; j < ent.vn_cnt; ++j) @@ -6757,6 +6823,10 @@ process_version_sections (FILE * file) printf (_(" Flags: %s Version: %d\n"), get_ver_flags (aux.vna_flags), aux.vna_other); + /* Check for overflow */ + if ((unsigned)(vstart + aux.vna_next) < (unsigned)vstart || + (unsigned)(vstart + aux.vna_next) > (unsigned)endbuf) + break; isum += aux.vna_next; vstart += aux.vna_next; } @@ -6797,6 +6867,9 @@ process_version_sections (FILE * file) symbols = GET_ELF_SYMBOLS (file, link_section); + if (!symbols) + break; + string_sec = section_headers + link_section->sh_link; strtab = (char *) get_data (NULL, file, string_sec->sh_offset, 1, @@ -6857,6 +6930,16 @@ process_version_sections (FILE * file) nn = printf ("%4x%c", data[cnt + j] & 0x7fff, data[cnt + j] & 0x8000 ? 'h' : ' '); + /* If this index value is greater than the size of the symbols + array, break to avoid an out-of-bounds read */ + if ((unsigned long)(cnt + j) >= + ((unsigned long)link_section->sh_size / + (unsigned long)link_section->sh_entsize)) + { + warn (_("invalid index into symbol array\n")); + break; + } + check_def = 1; check_need = 1; if (symbols[cnt + j].st_shndx >= elf_header.e_shnum @@ -7493,9 +7576,13 @@ process_symbol_table (FILE * file) && section->sh_type != SHT_DYNSYM) continue; - printf (_("\nSymbol table '%s' contains %lu entries:\n"), - SECTION_NAME (section), - (unsigned long) (section->sh_size / section->sh_entsize)); + if ( section->sh_entsize != 0 ) + { + printf (_("\nSymbol table '%s' contains %lu entries:\n"), + SECTION_NAME (section), + (unsigned long) (section->sh_size / section->sh_entsize)); + } + if (is_32bit_elf) printf (_(" Num: Value Size Type Bind Vis Ndx Name\n")); else @@ -10483,7 +10570,8 @@ process_corefile_note_segment (FILE * fi next = (Elf_External_Note *) (inote.descdata + align_power (inote.descsz, 2)); - if (((char *) next) > (((char *) pnotes) + length)) + if (((char *) next) > (((char *) pnotes) + length) || + (char *) next < (char *) pnotes) { warn (_("corrupt note found at offset %lx into core notes\n"), (unsigned long) ((char *) external - (char *) pnotes)); @@ -10494,6 +10582,17 @@ process_corefile_note_segment (FILE * fi external = next; + /* Prevent out-of-bounds indexing */ + if (inote.namedata + inote.namesz >= (char *)pnotes + length || + inote.namedata + inote.namesz < inote.namedata) + { + warn (_("corrupt note found at offset %lx into core notes\n"), + (unsigned long) ((char *) external - (char *) pnotes)); + warn (_(" type: %lx, namesize: %08lx, descsize: %08lx\n"), + inote.type, inote.namesz, inote.descsz); + break; + } + /* Verify that name is null terminated. It appears that at least one version of Linux (RedHat 6.0) generates corefiles that don't comply with the ELF spec by failing to include the null byte in