Package: binutils Version: 2.16.1-2 Severity: important Tags: patch readelf -s currently segfaults on some mips libraries, notably libnewt.so.0.51-so used in debian-installer: hattusa:~/colo/binutils$ readelf -s libnewt.so.0.51-so Symbol table '.dynsym' contains 186 entries: Num: Value Size Type Bind Vis Ndx Name 0: 00000000 0 NOTYPE LOCAL DEFAULT UND 1: 000000d4 0 SECTION LOCAL DEFAULT 1 2: 00002410 0 SECTION LOCAL DEFAULT 8 3: 0000cd40 0 SECTION LOCAL DEFAULT 9 4: 0000d120 0 SECTION LOCAL DEFAULT 10 5: 0000d4d0 0 SECTION LOCAL DEFAULT 11 6: 0004d4e4 0 SECTION LOCAL DEFAULT 12 7: 0004d50c 0 SECTION LOCAL DEFAULT 13 8: 0004d810 0 SECTION LOCAL DEFAULT 14 9: 0004db50 0 SECTION LOCAL DEFAULT 17 10: 00002d88 132 FUNC GLOBAL DEFAULT 8 newtRadiobutton 11: 000063e0 240 FUNC GLOBAL DEFAULT 8 newtLabel 12: 0000a9fc 76 FUNC GLOBAL DEFAULT 8 newtGetScreenSize Segmentation fault The appended patch (from upstream, by Jakub Jelinek, adjusted for the revision in debian) fixes it. Thiemo --- binutils/readelf.c.orig 2005-04-20 20:43:36.000000000 +0200 +++ binutils/readelf.c 2005-07-15 00:23:05.000000000 +0200 @@ -206,7 +206,7 @@ unsigned int num_dump_sects = 0; #define DISASS_DUMP (1 << 1) #define DEBUG_DUMP (1 << 2) -/* How to rpint a vma value. */ +/* How to print a vma value. */ typedef enum print_mode { HEX, @@ -286,11 +286,42 @@ warn (const char *message, ...) } static void * -get_data (void *var, FILE *file, long offset, size_t size, const char *reason) +cmalloc (size_t nmemb, size_t size) +{ + /* Check for overflow. */ + if (nmemb >= ~(size_t) 0 / size) + return NULL; + else + return malloc (nmemb * size); +} + +static void * +xcmalloc (size_t nmemb, size_t size) +{ + /* Check for overflow. */ + if (nmemb >= ~(size_t) 0 / size) + return NULL; + else + return xmalloc (nmemb * size); +} + +static void * +xcrealloc (void *ptr, size_t nmemb, size_t size) +{ + /* Check for overflow. */ + if (nmemb >= ~(size_t) 0 / size) + return NULL; + else + return xrealloc (ptr, nmemb * size); +} + +static void * +get_data (void *var, FILE *file, long offset, size_t size, size_t nmemb, + const char *reason) { void *mvar; - if (size == 0) + if (size == 0 || nmemb == 0) return NULL; if (fseek (file, archive_file_offset + offset, SEEK_SET)) @@ -303,19 +334,24 @@ get_data (void *var, FILE *file, long of mvar = var; if (mvar == NULL) { - mvar = malloc (size); + /* Check for overflow. */ + if (nmemb < (~(size_t) 0 - 1) / size) + /* + 1 so that we can '\0' terminate invalid string table sections. */ + mvar = malloc (size * nmemb + 1); if (mvar == NULL) { error (_("Out of memory allocating 0x%x bytes for %s\n"), - size, reason); + size * nmemb, reason); return NULL; } + + ((char *) mvar)[size * nmemb] = '\0'; } - if (fread (mvar, size, 1, file) != 1) + if (fread (mvar, size, nmemb, file) != nmemb) { - error (_("Unable to read in 0x%x bytes of %s\n"), size, reason); + error (_("Unable to read in 0x%x bytes of %s\n"), size * nmemb, reason); if (mvar != var) free (mvar); return NULL; @@ -769,16 +805,17 @@ slurp_rela_relocs (FILE *file, { Elf32_External_Rela *erelas; - erelas = get_data (NULL, file, rel_offset, rel_size, _("relocs")); + erelas = get_data (NULL, file, rel_offset, 1, rel_size, _("relocs")); if (!erelas) return 0; nrelas = rel_size / sizeof (Elf32_External_Rela); - relas = malloc (nrelas * sizeof (Elf_Internal_Rela)); + relas = cmalloc (nrelas, sizeof (Elf_Internal_Rela)); if (relas == NULL) { + free (erelas); error (_("out of memory parsing relocs")); return 0; } @@ -796,16 +833,17 @@ slurp_rela_relocs (FILE *file, { Elf64_External_Rela *erelas; - erelas = get_data (NULL, file, rel_offset, rel_size, _("relocs")); + erelas = get_data (NULL, file, rel_offset, 1, rel_size, _("relocs")); if (!erelas) return 0; nrelas = rel_size / sizeof (Elf64_External_Rela); - relas = malloc (nrelas * sizeof (Elf_Internal_Rela)); + relas = cmalloc (nrelas, sizeof (Elf_Internal_Rela)); if (relas == NULL) { + free (erelas); error (_("out of memory parsing relocs")); return 0; } @@ -839,16 +877,17 @@ slurp_rel_relocs (FILE *file, { Elf32_External_Rel *erels; - erels = get_data (NULL, file, rel_offset, rel_size, _("relocs")); + erels = get_data (NULL, file, rel_offset, 1, rel_size, _("relocs")); if (!erels) return 0; nrels = rel_size / sizeof (Elf32_External_Rel); - rels = malloc (nrels * sizeof (Elf_Internal_Rela)); + rels = cmalloc (nrels, sizeof (Elf_Internal_Rela)); if (rels == NULL) { + free (erels); error (_("out of memory parsing relocs")); return 0; } @@ -866,16 +905,17 @@ slurp_rel_relocs (FILE *file, { Elf64_External_Rel *erels; - erels = get_data (NULL, file, rel_offset, rel_size, _("relocs")); + erels = get_data (NULL, file, rel_offset, 1, rel_size, _("relocs")); if (!erels) return 0; nrels = rel_size / sizeof (Elf64_External_Rel); - rels = malloc (nrels * sizeof (Elf_Internal_Rela)); + rels = cmalloc (nrels, sizeof (Elf_Internal_Rela)); if (rels == NULL) { + free (erels); error (_("out of memory parsing relocs")); return 0; } @@ -1293,7 +1333,7 @@ dump_relocations (FILE *file, } else if (strtab == NULL) printf (_(""), psym->st_name); - else if (psym->st_name > strtablen) + else if (psym->st_name >= strtablen) printf (_(""), psym->st_name); else print_symbol (22, strtab + psym->st_name); @@ -3087,7 +3127,7 @@ get_32bit_program_headers (FILE *file, E unsigned int i; phdrs = get_data (NULL, file, elf_header.e_phoff, - elf_header.e_phentsize * elf_header.e_phnum, + elf_header.e_phentsize, elf_header.e_phnum, _("program headers")); if (!phdrs) return 0; @@ -3120,7 +3160,7 @@ get_64bit_program_headers (FILE *file, E unsigned int i; phdrs = get_data (NULL, file, elf_header.e_phoff, - elf_header.e_phentsize * elf_header.e_phnum, + elf_header.e_phentsize, elf_header.e_phnum, _("program headers")); if (!phdrs) return 0; @@ -3155,7 +3195,7 @@ get_program_headers (FILE *file) if (program_headers != NULL) return 1; - phdrs = malloc (elf_header.e_phnum * sizeof (Elf_Internal_Phdr)); + phdrs = cmalloc (elf_header.e_phnum, sizeof (Elf_Internal_Phdr)); if (phdrs == NULL) { @@ -3368,13 +3408,11 @@ process_program_headers (FILE *file) putc ('\n', stdout); } - if (do_segments && section_headers != NULL) + if (do_segments && section_headers != NULL && string_table != NULL) { printf (_("\n Section to Segment mapping:\n")); printf (_(" Segment Sections...\n")); - assert (string_table != NULL); - for (i = 0; i < elf_header.e_phnum; i++) { unsigned int j; @@ -3452,11 +3490,11 @@ get_32bit_section_headers (FILE *file, u unsigned int i; shdrs = get_data (NULL, file, elf_header.e_shoff, - elf_header.e_shentsize * num, _("section headers")); + elf_header.e_shentsize, num, _("section headers")); if (!shdrs) return 0; - section_headers = malloc (num * sizeof (Elf_Internal_Shdr)); + section_headers = cmalloc (num, sizeof (Elf_Internal_Shdr)); if (section_headers == NULL) { @@ -3493,11 +3531,11 @@ get_64bit_section_headers (FILE *file, u unsigned int i; shdrs = get_data (NULL, file, elf_header.e_shoff, - elf_header.e_shentsize * num, _("section headers")); + elf_header.e_shentsize, num, _("section headers")); if (!shdrs) return 0; - section_headers = malloc (num * sizeof (Elf_Internal_Shdr)); + section_headers = cmalloc (num, sizeof (Elf_Internal_Shdr)); if (section_headers == NULL) { @@ -3536,7 +3574,7 @@ get_32bit_elf_symbols (FILE *file, Elf_I Elf_Internal_Sym *psym; unsigned int j; - esyms = get_data (NULL, file, section->sh_offset, section->sh_size, + esyms = get_data (NULL, file, section->sh_offset, 1, section->sh_size, _("symbols")); if (!esyms) return NULL; @@ -3547,7 +3585,7 @@ get_32bit_elf_symbols (FILE *file, Elf_I == (unsigned long) SECTION_HEADER_NUM (section - section_headers))) { shndx = get_data (NULL, file, symtab_shndx_hdr->sh_offset, - symtab_shndx_hdr->sh_size, _("symtab shndx")); + 1, symtab_shndx_hdr->sh_size, _("symtab shndx")); if (!shndx) { free (esyms); @@ -3556,7 +3594,7 @@ get_32bit_elf_symbols (FILE *file, Elf_I } number = section->sh_size / section->sh_entsize; - isyms = malloc (number * sizeof (Elf_Internal_Sym)); + isyms = cmalloc (number, sizeof (Elf_Internal_Sym)); if (isyms == NULL) { @@ -3599,7 +3637,7 @@ get_64bit_elf_symbols (FILE *file, Elf_I Elf_Internal_Sym *psym; unsigned int j; - esyms = get_data (NULL, file, section->sh_offset, section->sh_size, + esyms = get_data (NULL, file, section->sh_offset, 1, section->sh_size, _("symbols")); if (!esyms) return NULL; @@ -3610,7 +3648,7 @@ get_64bit_elf_symbols (FILE *file, Elf_I == (unsigned long) SECTION_HEADER_NUM (section - section_headers))) { shndx = get_data (NULL, file, symtab_shndx_hdr->sh_offset, - symtab_shndx_hdr->sh_size, _("symtab shndx")); + 1, symtab_shndx_hdr->sh_size, _("symtab shndx")); if (!shndx) { free (esyms); @@ -3619,7 +3657,7 @@ get_64bit_elf_symbols (FILE *file, Elf_I } number = section->sh_size / section->sh_entsize; - isyms = malloc (number * sizeof (Elf_Internal_Sym)); + isyms = cmalloc (number, sizeof (Elf_Internal_Sym)); if (isyms == NULL) { @@ -3729,17 +3767,17 @@ process_section_headers (FILE *file) return 0; /* Read in the string table, so that we have names to display. */ - section = SECTION_HEADER (elf_header.e_shstrndx); - - if (section->sh_size != 0) + if (SECTION_HEADER_INDEX (elf_header.e_shstrndx) < elf_header.e_shnum) { - string_table = get_data (NULL, file, section->sh_offset, - section->sh_size, _("string table")); + section = SECTION_HEADER (elf_header.e_shstrndx); - if (string_table == NULL) - return 0; + if (section->sh_size != 0) + { + string_table = get_data (NULL, file, section->sh_offset, + 1, section->sh_size, _("string table")); - string_table_length = section->sh_size; + string_table_length = string_table != NULL ? section->sh_size : 0; + } } /* Scan the sections for the dynamic symbol table @@ -3796,7 +3834,7 @@ process_section_headers (FILE *file) } dynamic_strings = get_data (NULL, file, section->sh_offset, - section->sh_size, _("dynamic strings")); + 1, section->sh_size, _("dynamic strings")); dynamic_strings_length = section->sh_size; } else if (section->sh_type == SHT_SYMTAB_SHNDX) @@ -3983,6 +4021,7 @@ process_section_groups (FILE *file) Elf_Internal_Shdr *symtab_sec, *strtab_sec; Elf_Internal_Sym *symtab; char *strtab; + size_t strtab_size; /* Don't process section groups unless needed. */ if (!do_unwind && !do_section_groups) @@ -4039,6 +4078,7 @@ process_section_groups (FILE *file) strtab_sec = NULL; symtab = NULL; strtab = NULL; + strtab_size = 0; for (i = 0, section = section_headers, group = section_groups; i < elf_header.e_shnum; i++, section++) @@ -4053,8 +4093,9 @@ process_section_groups (FILE *file) Elf_Internal_Sym *sym; /* Get the symbol table. */ - sec = SECTION_HEADER (section->sh_link); - if (sec->sh_type != SHT_SYMTAB) + if (SECTION_HEADER_INDEX (section->sh_link) >= elf_header.e_shnum + || ((sec = SECTION_HEADER (section->sh_link))->sh_type + != SHT_SYMTAB)) { error (_("Bad sh_link in group section `%s'\n"), name); continue; @@ -4080,26 +4121,41 @@ process_section_groups (FILE *file) } group_name = SECTION_NAME (section_headers + sec_index); + strtab_sec = NULL; + if (strtab) + free (strtab); strtab = NULL; + strtab_size = 0; } else { /* Get the string table. */ - sec = SECTION_HEADER (symtab_sec->sh_link); - if (strtab_sec != sec) + if (SECTION_HEADER_INDEX (symtab_sec->sh_link) + >= elf_header.e_shnum) + { + strtab_sec = NULL; + if (strtab) + free (strtab); + strtab = NULL; + strtab_size = 0; + } + else if (strtab_sec + != (sec = SECTION_HEADER (symtab_sec->sh_link))) { strtab_sec = sec; if (strtab) free (strtab); strtab = get_data (NULL, file, strtab_sec->sh_offset, - strtab_sec->sh_size, + 1, strtab_sec->sh_size, _("string table")); + strtab_size = strtab != NULL ? strtab_sec->sh_size : 0; } - group_name = strtab + sym->st_name; + group_name = sym->st_name < strtab_size + ? strtab + sym->st_name : ""; } start = get_data (NULL, file, section->sh_offset, - section->sh_size, _("section data")); + 1, section->sh_size, _("section data")); indices = start; size = (section->sh_size / section->sh_entsize) - 1; @@ -4126,7 +4182,7 @@ process_section_groups (FILE *file) if (section_headers_groups [SECTION_HEADER_INDEX (entry)] != NULL) { - if (entry) + if (SECTION_HEADER_INDEX (entry)) { error (_("section [%5u] already in group section [%5u]\n"), entry, @@ -4154,8 +4210,7 @@ process_section_groups (FILE *file) if (do_section_groups) { sec = SECTION_HEADER (entry); - printf (" [%5u] %s\n", - entry, SECTION_NAME (sec)); + printf (" [%5u] %s\n", entry, SECTION_NAME (sec)); } g = xmalloc (sizeof (struct group_list)); @@ -4286,12 +4341,14 @@ process_relocs (FILE *file) is_rela = section->sh_type == SHT_RELA; - if (section->sh_link) + if (section->sh_link + && SECTION_HEADER_INDEX (section->sh_link) + < elf_header.e_shnum) { Elf_Internal_Shdr *symsec; Elf_Internal_Sym *symtab; unsigned long nsyms; - unsigned long strtablen; + unsigned long strtablen = 0; char *strtab = NULL; symsec = SECTION_HEADER (section->sh_link); @@ -4301,11 +4358,16 @@ process_relocs (FILE *file) if (symtab == NULL) continue; - strsec = SECTION_HEADER (symsec->sh_link); + if (SECTION_HEADER_INDEX (symsec->sh_link) + < elf_header.e_shnum) + { + strsec = SECTION_HEADER (symsec->sh_link); - strtab = get_data (NULL, file, strsec->sh_offset, - strsec->sh_size, _("string table")); - strtablen = strtab == NULL ? 0 : strsec->sh_size; + strtab = get_data (NULL, file, strsec->sh_offset, + 1, strsec->sh_size, + _("string table")); + strtablen = strtab == NULL ? 0 : strsec->sh_size; + } dump_relocations (file, rel_offset, rel_size, symtab, nsyms, strtab, strtablen, is_rela); @@ -4496,11 +4558,11 @@ slurp_ia64_unwind_table (FILE *file, /* Second, build the unwind table from the contents of the unwind section: */ size = sec->sh_size; - table = get_data (NULL, file, sec->sh_offset, size, _("unwind table")); + table = get_data (NULL, file, sec->sh_offset, 1, size, _("unwind table")); if (!table) return 0; - aux->table = xmalloc (size / (3 * eh_addr_size) * sizeof (aux->table[0])); + aux->table = xcmalloc (size / (3 * eh_addr_size), sizeof (aux->table[0])); tep = aux->table; for (tp = table; tp < table + size; tp += 3 * eh_addr_size, ++tep) { @@ -4532,6 +4594,7 @@ slurp_ia64_unwind_table (FILE *file, ++relsec) { if (relsec->sh_type != SHT_RELA + || SECTION_HEADER_INDEX (relsec->sh_info) >= elf_header.e_shnum || SECTION_HEADER (relsec->sh_info) != sec) continue; @@ -4597,15 +4660,16 @@ ia64_process_unwind (FILE *file) for (i = 0, sec = section_headers; i < elf_header.e_shnum; ++i, ++sec) { - if (sec->sh_type == SHT_SYMTAB) + if (sec->sh_type == SHT_SYMTAB + && SECTION_HEADER_INDEX (sec->sh_link) < elf_header.e_shnum) { aux.nsyms = sec->sh_size / sec->sh_entsize; aux.symtab = GET_ELF_SYMBOLS (file, sec); strsec = SECTION_HEADER (sec->sh_link); - aux.strtab_size = strsec->sh_size; aux.strtab = get_data (NULL, file, strsec->sh_offset, - aux.strtab_size, _("string table")); + 1, strsec->sh_size, _("string table")); + aux.strtab_size = aux.strtab != NULL ? strsec->sh_size : 0; } else if (sec->sh_type == SHT_IA_64_UNWIND) unwcount++; @@ -4686,7 +4750,7 @@ ia64_process_unwind (FILE *file) { aux.info_size = sec->sh_size; aux.info_addr = sec->sh_addr; - aux.info = get_data (NULL, file, sec->sh_offset, aux.info_size, + aux.info = get_data (NULL, file, sec->sh_offset, 1, aux.info_size, _("unwind info")); printf (_("\nUnwind section ")); @@ -4876,13 +4940,13 @@ slurp_hppa_unwind_table (FILE *file, /* Second, build the unwind table from the contents of the unwind section. */ size = sec->sh_size; - table = get_data (NULL, file, sec->sh_offset, size, _("unwind table")); + table = get_data (NULL, file, sec->sh_offset, 1, size, _("unwind table")); if (!table) return 0; unw_ent_size = 2 * eh_addr_size + 8; - tep = aux->table = xmalloc (size / unw_ent_size * sizeof (aux->table[0])); + tep = aux->table = xcmalloc (size / unw_ent_size, sizeof (aux->table[0])); for (tp = table; tp < table + size; tp += (2 * eh_addr_size + 8), ++tep) { @@ -4950,6 +5014,7 @@ slurp_hppa_unwind_table (FILE *file, ++relsec) { if (relsec->sh_type != SHT_RELA + || SECTION_HEADER_INDEX (relsec->sh_info) >= elf_header.e_shnum || SECTION_HEADER (relsec->sh_info) != sec) continue; @@ -5013,19 +5078,21 @@ hppa_process_unwind (FILE *file) memset (& aux, 0, sizeof (aux)); - assert (string_table != NULL); + if (string_table == NULL) + return 1; for (i = 0, sec = section_headers; i < elf_header.e_shnum; ++i, ++sec) { - if (sec->sh_type == SHT_SYMTAB) + if (sec->sh_type == SHT_SYMTAB + && SECTION_HEADER_INDEX (sec->sh_link) < elf_header.e_shnum) { aux.nsyms = sec->sh_size / sec->sh_entsize; aux.symtab = GET_ELF_SYMBOLS (file, sec); strsec = SECTION_HEADER (sec->sh_link); - aux.strtab_size = strsec->sh_size; aux.strtab = get_data (NULL, file, strsec->sh_offset, - aux.strtab_size, _("string table")); + 1, strsec->sh_size, _("string table")); + aux.strtab_size = aux.strtab != NULL ? strsec->sh_size : 0; } else if (streq (SECTION_NAME (sec), ".PARISC.unwind")) unwsec = sec; @@ -5241,7 +5308,7 @@ get_32bit_dynamic_section (FILE *file) Elf32_External_Dyn *edyn, *ext; Elf_Internal_Dyn *entry; - edyn = get_data (NULL, file, dynamic_addr, dynamic_size, + edyn = get_data (NULL, file, dynamic_addr, 1, dynamic_size, _("dynamic section")); if (!edyn) return 0; @@ -5258,7 +5325,7 @@ get_32bit_dynamic_section (FILE *file) break; } - dynamic_section = malloc (dynamic_nent * sizeof (*entry)); + dynamic_section = cmalloc (dynamic_nent, sizeof (*entry)); if (dynamic_section == NULL) { error (_("Out of memory\n")); @@ -5285,7 +5352,7 @@ get_64bit_dynamic_section (FILE *file) Elf64_External_Dyn *edyn, *ext; Elf_Internal_Dyn *entry; - edyn = get_data (NULL, file, dynamic_addr, dynamic_size, + edyn = get_data (NULL, file, dynamic_addr, 1, dynamic_size, _("dynamic section")); if (!edyn) return 0; @@ -5302,7 +5369,7 @@ get_64bit_dynamic_section (FILE *file) break; } - dynamic_section = malloc (dynamic_nent * sizeof (*entry)); + dynamic_section = cmalloc (dynamic_nent, sizeof (*entry)); if (dynamic_section == NULL) { error (_("Out of memory\n")); @@ -5460,7 +5527,7 @@ process_dynamic_section (FILE *file) continue; } - dynamic_strings = get_data (NULL, file, offset, str_tab_len, + dynamic_strings = get_data (NULL, file, offset, 1, str_tab_len, _("dynamic string table")); dynamic_strings_length = str_tab_len; break; @@ -5495,8 +5562,8 @@ process_dynamic_section (FILE *file) Elf_Internal_Syminfo *syminfo; /* There is a syminfo section. Read the data. */ - extsyminfo = get_data (NULL, file, dynamic_syminfo_offset, syminsz, - _("symbol information")); + extsyminfo = get_data (NULL, file, dynamic_syminfo_offset, 1, + syminsz, _("symbol information")); if (!extsyminfo) return 0; @@ -5972,9 +6039,13 @@ process_version_sections (FILE *file) printf_vma (section->sh_addr); printf (_(" Offset: %#08lx Link: %lx (%s)\n"), (unsigned long) section->sh_offset, section->sh_link, - SECTION_NAME (SECTION_HEADER (section->sh_link))); + SECTION_HEADER_INDEX (section->sh_link) + < elf_header.e_shnum + ? SECTION_NAME (SECTION_HEADER (section->sh_link)) + : ""); - edefs = get_data (NULL, file, section->sh_offset, section->sh_size, + edefs = get_data (NULL, file, section->sh_offset, 1, + section->sh_size, _("version definition section")); if (!edefs) break; @@ -6061,9 +6132,13 @@ process_version_sections (FILE *file) printf_vma (section->sh_addr); printf (_(" Offset: %#08lx Link to section: %ld (%s)\n"), (unsigned long) section->sh_offset, section->sh_link, - SECTION_NAME (SECTION_HEADER (section->sh_link))); + SECTION_HEADER_INDEX (section->sh_link) + < elf_header.e_shnum + ? SECTION_NAME (SECTION_HEADER (section->sh_link)) + : ""); - eneed = get_data (NULL, file, section->sh_offset, section->sh_size, + eneed = get_data (NULL, file, section->sh_offset, 1, + section->sh_size, _("version need section")); if (!eneed) break; @@ -6143,16 +6218,23 @@ process_version_sections (FILE *file) Elf_Internal_Shdr *string_sec; long off; + if (SECTION_HEADER_INDEX (section->sh_link) >= elf_header.e_shnum) + break; + link_section = SECTION_HEADER (section->sh_link); total = section->sh_size / section->sh_entsize; + if (SECTION_HEADER_INDEX (link_section->sh_link) + >= elf_header.e_shnum) + break; + found = 1; symbols = GET_ELF_SYMBOLS (file, link_section); string_sec = SECTION_HEADER (link_section->sh_link); - strtab = get_data (NULL, file, string_sec->sh_offset, + strtab = get_data (NULL, file, string_sec->sh_offset, 1, string_sec->sh_size, _("version string table")); if (!strtab) break; @@ -6169,7 +6251,7 @@ process_version_sections (FILE *file) off = offset_from_vma (file, version_info[DT_VERSIONTAGIDX (DT_VERSYM)], total * sizeof (short)); - edata = get_data (NULL, file, off, total * sizeof (short), + edata = get_data (NULL, file, off, total, sizeof (short), _("version symbol data")); if (!edata) { @@ -6177,7 +6259,7 @@ process_version_sections (FILE *file) break; } - data = malloc (total * sizeof (short)); + data = cmalloc (total, sizeof (short)); for (cnt = total; cnt --;) data[cnt] = byte_get (edata + cnt * sizeof (short), @@ -6210,8 +6292,10 @@ process_version_sections (FILE *file) check_def = 1; check_need = 1; - if (SECTION_HEADER (symbols[cnt + j].st_shndx)->sh_type - != SHT_NOBITS) + if (SECTION_HEADER_INDEX (symbols[cnt + j].st_shndx) + >= elf_header.e_shnum + || SECTION_HEADER (symbols[cnt + j].st_shndx)->sh_type + != SHT_NOBITS) { if (symbols[cnt + j].st_shndx == SHN_UNDEF) check_def = 0; @@ -6236,7 +6320,7 @@ process_version_sections (FILE *file) Elf_External_Vernaux evna; unsigned long a_off; - get_data (&evn, file, offset, sizeof (evn), + get_data (&evn, file, offset, sizeof (evn), 1, _("version need")); ivn.vn_aux = BYTE_GET (evn.vn_aux); @@ -6247,7 +6331,7 @@ process_version_sections (FILE *file) do { get_data (&evna, file, a_off, sizeof (evna), - _("version need aux (2)")); + 1, _("version need aux (2)")); ivna.vna_next = BYTE_GET (evna.vna_next); ivna.vna_other = BYTE_GET (evna.vna_other); @@ -6288,7 +6372,7 @@ process_version_sections (FILE *file) do { - get_data (&evd, file, offset, sizeof (evd), + get_data (&evd, file, offset, sizeof (evd), 1, _("version def")); ivd.vd_next = BYTE_GET (evd.vd_next); @@ -6308,7 +6392,8 @@ process_version_sections (FILE *file) get_data (&evda, file, offset - ivd.vd_next + ivd.vd_aux, - sizeof (evda), _("version def aux")); + sizeof (evda), 1, + _("version def aux")); ivda.vda_name = BYTE_GET (evda.vda_name); @@ -6460,7 +6545,7 @@ get_dynamic_data (FILE *file, unsigned i unsigned char *e_data; bfd_vma *i_data; - e_data = malloc (number * ent_size); + e_data = cmalloc (number, ent_size); if (e_data == NULL) { @@ -6474,7 +6559,7 @@ get_dynamic_data (FILE *file, unsigned i return NULL; } - i_data = malloc (number * sizeof (*i_data)); + i_data = cmalloc (number, sizeof (*i_data)); if (i_data == NULL) { @@ -6602,7 +6687,8 @@ process_symbol_table (FILE *file) i++, section++) { unsigned int si; - char *strtab; + char *strtab = NULL; + unsigned long int strtab_size = 0; Elf_Internal_Sym *symtab; Elf_Internal_Sym *psym; @@ -6624,15 +6710,19 @@ process_symbol_table (FILE *file) continue; if (section->sh_link == elf_header.e_shstrndx) - strtab = string_table; - else + { + strtab = string_table; + strtab_size = string_table_length; + } + else if (SECTION_HEADER_INDEX (section->sh_link) < elf_header.e_shnum) { Elf_Internal_Shdr *string_sec; string_sec = SECTION_HEADER (section->sh_link); strtab = get_data (NULL, file, string_sec->sh_offset, - string_sec->sh_size, _("string table")); + 1, string_sec->sh_size, _("string table")); + strtab_size = strtab != NULL ? string_sec->sh_size : 0; } for (si = 0, psym = symtab; @@ -6647,7 +6737,8 @@ process_symbol_table (FILE *file) printf (" %-6s", get_symbol_binding (ELF_ST_BIND (psym->st_info))); printf (" %-3s", get_symbol_visibility (ELF_ST_VISIBILITY (psym->st_other))); printf (" %4s ", get_symbol_index_type (psym->st_shndx)); - print_symbol (25, strtab + psym->st_name); + print_symbol (25, psym->st_name < strtab_size + ? strtab + psym->st_name : ""); if (section->sh_type == SHT_DYNSYM && version_info[DT_VERSIONTAGIDX (DT_VERSYM)] != 0) @@ -6663,12 +6754,14 @@ process_symbol_table (FILE *file) sizeof data + si * sizeof (vers_data)); get_data (&data, file, offset + si * sizeof (vers_data), - sizeof (data), _("version data")); + sizeof (data), 1, _("version data")); vers_data = byte_get (data, 2); - is_nobits = (SECTION_HEADER (psym->st_shndx)->sh_type - == SHT_NOBITS); + is_nobits = (SECTION_HEADER_INDEX (psym->st_shndx) + < elf_header.e_shnum + && SECTION_HEADER (psym->st_shndx)->sh_type + == SHT_NOBITS); check_def = (psym->st_shndx != SHN_UNDEF); @@ -6690,7 +6783,7 @@ process_symbol_table (FILE *file) { unsigned long vna_off; - get_data (&evn, file, offset, sizeof (evn), + get_data (&evn, file, offset, sizeof (evn), 1, _("version need")); ivn.vn_aux = BYTE_GET (evn.vn_aux); @@ -6703,7 +6796,7 @@ process_symbol_table (FILE *file) Elf_External_Vernaux evna; get_data (&evna, file, vna_off, - sizeof (evna), + sizeof (evna), 1, _("version need aux (3)")); ivna.vna_other = BYTE_GET (evna.vna_other); @@ -6725,7 +6818,9 @@ process_symbol_table (FILE *file) if (ivna.vna_other == vers_data) { printf ("@%s (%d)", - strtab + ivna.vna_name, ivna.vna_other); + ivna.vna_name < strtab_size + ? strtab + ivna.vna_name : "", + ivna.vna_other); check_def = 0; } else if (! is_nobits) @@ -6754,7 +6849,7 @@ process_symbol_table (FILE *file) Elf_External_Verdef evd; get_data (&evd, file, offset, sizeof (evd), - _("version def")); + 1, _("version def")); ivd.vd_ndx = BYTE_GET (evd.vd_ndx); ivd.vd_aux = BYTE_GET (evd.vd_aux); @@ -6769,14 +6864,15 @@ process_symbol_table (FILE *file) offset += ivd.vd_aux; get_data (&evda, file, offset, sizeof (evda), - _("version def aux")); + 1, _("version def aux")); ivda.vda_name = BYTE_GET (evda.vda_name); if (psym->st_name != ivda.vda_name) printf ((vers_data & 0x8000) ? "@%s" : "@@%s", - strtab + ivda.vda_name); + ivda.vda_name < strtab_size + ? strtab + ivda.vda_name : ""); } } } @@ -6961,7 +7057,8 @@ dump_section (Elf_Internal_Shdr *section addr = section->sh_addr; - start = get_data (NULL, file, section->sh_offset, bytes, _("section data")); + start = get_data (NULL, file, section->sh_offset, 1, bytes, + _("section data")); if (!start) return 0; @@ -7168,7 +7265,7 @@ load_debug_str (FILE *file) debug_str_size = sec->sh_size; - debug_str_contents = get_data (NULL, file, sec->sh_offset, sec->sh_size, + debug_str_contents = get_data (NULL, file, sec->sh_offset, 1, sec->sh_size, _("debug_str section data")); } @@ -7214,7 +7311,7 @@ load_debug_loc (FILE *file) debug_loc_size = sec->sh_size; - debug_loc_contents = get_data (NULL, file, sec->sh_offset, sec->sh_size, + debug_loc_contents = get_data (NULL, file, sec->sh_offset, 1, sec->sh_size, _("debug_loc section data")); } @@ -7248,7 +7345,7 @@ load_debug_range (FILE *file) debug_range_size = sec->sh_size; - debug_range_contents = get_data (NULL, file, sec->sh_offset, sec->sh_size, + debug_range_contents = get_data (NULL, file, sec->sh_offset, 1, sec->sh_size, _("debug_range section data")); } @@ -7289,8 +7386,10 @@ debug_apply_rela_addends (FILE *file, Elf_Internal_Sym *sym; if (relsec->sh_type != SHT_RELA + || SECTION_HEADER_INDEX (relsec->sh_info) >= elf_header.e_shnum || SECTION_HEADER (relsec->sh_info) != section - || relsec->sh_size == 0) + || relsec->sh_size == 0 + || SECTION_HEADER_INDEX (relsec->sh_link) >= elf_header.e_shnum) continue; if (!slurp_rela_relocs (file, relsec->sh_offset, relsec->sh_size, @@ -8228,11 +8327,11 @@ read_and_display_attr_value (unsigned lo { max += 1024; debug_info_p->loc_offsets - = xrealloc (debug_info_p->loc_offsets, - max * sizeof (*debug_info_p->loc_offsets)); + = xcrealloc (debug_info_p->loc_offsets, + max, sizeof (*debug_info_p->loc_offsets)); debug_info_p->have_frame_base - = xrealloc (debug_info_p->have_frame_base, - max * sizeof (*debug_info_p->have_frame_base)); + = xcrealloc (debug_info_p->have_frame_base, + max, sizeof (*debug_info_p->have_frame_base)); debug_info_p->max_loc_offsets = max; } debug_info_p->loc_offsets [num] = uvalue; @@ -8257,8 +8356,8 @@ read_and_display_attr_value (unsigned lo { max += 1024; debug_info_p->range_lists - = xrealloc (debug_info_p->range_lists, - max * sizeof (*debug_info_p->range_lists)); + = xcrealloc (debug_info_p->range_lists, + max, sizeof (*debug_info_p->range_lists)); debug_info_p->max_range_lists = max; } debug_info_p->range_lists [num] = uvalue; @@ -8633,8 +8732,8 @@ process_debug_info (Elf_Internal_Shdr *s } /* Then allocate an array to hold the information. */ - debug_information = malloc (num_units * - sizeof (* debug_information)); + debug_information = cmalloc (num_units, + sizeof (* debug_information)); if (debug_information == NULL) { error (_("Not enough memory for a debug info array of %u entries"), @@ -8747,7 +8846,7 @@ process_debug_info (Elf_Internal_Shdr *s return 0; } - begin = get_data (NULL, file, sec->sh_offset, sec->sh_size, + begin = get_data (NULL, file, sec->sh_offset, 1, sec->sh_size, _("debug_abbrev section data")); if (!begin) return 0; @@ -8916,7 +9015,7 @@ get_debug_info (FILE * file) if (section == NULL) return 0; - start = get_data (NULL, file, section->sh_offset, section->sh_size, + start = get_data (NULL, file, section->sh_offset, 1, section->sh_size, _("extracting information from .debug_info section")); if (start == NULL) return 0; @@ -9529,8 +9628,22 @@ display_debug_loc (Elf_Internal_Shdr *se } start = next; + if (offset >= bytes) + { + warn (_("Offset 0x%lx is bigger than .debug_loc section size.\n"), + offset); + continue; + } + while (1) { + if (start + 2 * pointer_size > section_end) + { + warn (_("Location list starting at offset 0x%lx is not terminated.\n"), + offset); + break; + } + begin = byte_get (start, pointer_size); start += pointer_size; end = byte_get (start, pointer_size); @@ -9546,14 +9659,28 @@ display_debug_loc (Elf_Internal_Shdr *se if (begin == -1UL && end != -1UL) { base_address = end; - printf (" %8.8lx %8.8lx %8.8lx (base address)\n", + printf (_(" %8.8lx %8.8lx %8.8lx (base address)\n"), offset, begin, end); continue; } + if (start + 2 > section_end) + { + warn (_("Location list starting at offset 0x%lx is not terminated.\n"), + offset); + break; + } + length = byte_get (start, 2); start += 2; + if (start + length > section_end) + { + warn (_("Location list starting at offset 0x%lx is not terminated.\n"), + offset); + break; + } + printf (" %8.8lx %8.8lx %8.8lx (", offset, begin + base_address, end + base_address); need_frame_base = decode_location_expression (start, @@ -9926,8 +10053,8 @@ frame_need_space (Frame_Chunk *fc, int r return; fc->ncols = reg + 1; - fc->col_type = xrealloc (fc->col_type, fc->ncols * sizeof (short int)); - fc->col_offset = xrealloc (fc->col_offset, fc->ncols * sizeof (int)); + fc->col_type = xcrealloc (fc->col_type, fc->ncols, sizeof (short int)); + fc->col_offset = xcrealloc (fc->col_offset, fc->ncols, sizeof (int)); while (prev < fc->ncols) { @@ -10237,8 +10364,8 @@ display_debug_frames (Elf_Internal_Shdr else { fc->ncols = cie->ncols; - fc->col_type = xmalloc (fc->ncols * sizeof (short int)); - fc->col_offset = xmalloc (fc->ncols * sizeof (int)); + fc->col_type = xcmalloc (fc->ncols, sizeof (short int)); + fc->col_offset = xcmalloc (fc->ncols, sizeof (int)); memcpy (fc->col_type, cie->col_type, fc->ncols * sizeof (short int)); memcpy (fc->col_offset, cie->col_offset, fc->ncols * sizeof (int)); fc->augmentation = cie->augmentation; @@ -10550,8 +10677,8 @@ display_debug_frames (Elf_Internal_Shdr printf (" DW_CFA_remember_state\n"); rs = xmalloc (sizeof (Frame_Chunk)); rs->ncols = fc->ncols; - rs->col_type = xmalloc (rs->ncols * sizeof (short int)); - rs->col_offset = xmalloc (rs->ncols * sizeof (int)); + rs->col_type = xcmalloc (rs->ncols, sizeof (short int)); + rs->col_offset = xcmalloc (rs->ncols, sizeof (int)); memcpy (rs->col_type, fc->col_type, rs->ncols); memcpy (rs->col_offset, fc->col_offset, rs->ncols * sizeof (int)); rs->next = remembered_state; @@ -10773,7 +10900,7 @@ display_debug_section (Elf_Internal_Shdr { unsigned char *start; - start = get_data (NULL, file, section->sh_offset, length, + start = get_data (NULL, file, section->sh_offset, 1, length, _("debug section data")); if (start == NULL) { @@ -10899,7 +11026,7 @@ process_mips_specific (FILE *file) size_t cnt; elib = get_data (NULL, file, liblist_offset, - liblistno * sizeof (Elf32_External_Lib), + liblistno, sizeof (Elf32_External_Lib), _("liblist")); if (elib) { @@ -10988,11 +11115,11 @@ process_mips_specific (FILE *file) while (sect->sh_type != SHT_MIPS_OPTIONS) ++sect; - eopt = get_data (NULL, file, options_offset, sect->sh_size, + eopt = get_data (NULL, file, options_offset, 1, sect->sh_size, _("options")); if (eopt) { - iopt = malloc ((sect->sh_size / sizeof (eopt)) * sizeof (*iopt)); + iopt = cmalloc ((sect->sh_size / sizeof (eopt)), sizeof (*iopt)); if (iopt == NULL) { error (_("Out of memory")); @@ -11184,7 +11311,7 @@ process_mips_specific (FILE *file) return 0; } - iconf = malloc (conflictsno * sizeof (*iconf)); + iconf = cmalloc (conflictsno, sizeof (*iconf)); if (iconf == NULL) { error (_("Out of memory")); @@ -11196,7 +11323,7 @@ process_mips_specific (FILE *file) Elf32_External_Conflict *econf32; econf32 = get_data (NULL, file, conflicts_offset, - conflictsno * sizeof (*econf32), _("conflict")); + conflictsno, sizeof (*econf32), _("conflict")); if (!econf32) return 0; @@ -11210,7 +11337,7 @@ process_mips_specific (FILE *file) Elf64_External_Conflict *econf64; econf64 = get_data (NULL, file, conflicts_offset, - conflictsno * sizeof (*econf64), _("conflict")); + conflictsno, sizeof (*econf64), _("conflict")); if (!econf64) return 0; @@ -11250,6 +11377,7 @@ process_gnu_liblist (FILE *file) Elf_Internal_Shdr *section, *string_sec; Elf32_External_Lib *elib; char *strtab; + size_t strtab_size; size_t cnt; unsigned i; @@ -11263,15 +11391,19 @@ process_gnu_liblist (FILE *file) switch (section->sh_type) { case SHT_GNU_LIBLIST: - elib = get_data (NULL, file, section->sh_offset, section->sh_size, + if (SECTION_HEADER_INDEX (section->sh_link) >= elf_header.e_shnum) + break; + + elib = get_data (NULL, file, section->sh_offset, 1, section->sh_size, _("liblist")); if (elib == NULL) break; string_sec = SECTION_HEADER (section->sh_link); - strtab = get_data (NULL, file, string_sec->sh_offset, + strtab = get_data (NULL, file, string_sec->sh_offset, 1, string_sec->sh_size, _("liblist string table")); + strtab_size = string_sec->sh_size; if (strtab == NULL || section->sh_entsize != sizeof (Elf32_External_Lib)) @@ -11308,9 +11440,11 @@ process_gnu_liblist (FILE *file) printf ("%3lu: ", (unsigned long) cnt); if (do_wide) - printf ("%-20s", strtab + liblist.l_name); + printf ("%-20s", liblist.l_name < strtab_size + ? strtab + liblist.l_name : ""); else - printf ("%-20.20s", strtab + liblist.l_name); + printf ("%-20.20s", liblist.l_name < strtab_size + ? strtab + liblist.l_name : ""); printf (" %s %#010lx %-7ld %-7ld\n", timebuf, liblist.l_checksum, liblist.l_version, liblist.l_flags); } @@ -11475,7 +11609,7 @@ process_corefile_note_segment (FILE *fil if (length <= 0) return 0; - pnotes = get_data (NULL, file, offset, length, _("notes")); + pnotes = get_data (NULL, file, offset, 1, length, _("notes")); if (!pnotes) return 0;