From ba5cdace0d1f5ae5bbaffbcce98de8d0cee133fc Mon Sep 17 00:00:00 2001 From: Nick Clifton Date: Thu, 13 Oct 2011 09:33:02 +0000 Subject: [PATCH] PR binutils/13219 * readelf.c (GET_ELF_SYMBOLS): Add sym_count parameter. (get_32bit_elf_symbols): Add num_syms_return argument. Return the number of symbols loaded into the symbol table. (get_64bit_elf_symbols): Likewise. (process_section_headers): Use GET_ELF_SYMBOLS to initialise symbol count. (proces_relocs): Likewise. (ia64_process_unwind): Likewise. (hppa_process_unwind): Likewise. (arm_process_unwind): Likewise. (process_dynamic_section): Likewise. (process_version_sections): Likewise. (process_symbol_table): Likewise. (process_section_groups): Likewise. Add check before indexing into the symbol table. (apply_relocations): Likewise. --- binutils/ChangeLog | 20 ++++++++ binutils/readelf.c | 131 +++++++++++++++++++++++++++++------------------------ 2 files changed, 92 insertions(+), 59 deletions(-) diff --git a/binutils/ChangeLog b/binutils/ChangeLog index 4d629ec..933a114 100644 --- a/binutils/ChangeLog +++ b/binutils/ChangeLog @@ -1,3 +1,23 @@ +2011-10-13 Nick Clifton + + PR binutils/13219 + * readelf.c (GET_ELF_SYMBOLS): Add sym_count parameter. + (get_32bit_elf_symbols): Add num_syms_return argument. + Return the number of symbols loaded into the symbol table. + (get_64bit_elf_symbols): Likewise. + (process_section_headers): Use GET_ELF_SYMBOLS to initialise + symbol count. + (proces_relocs): Likewise. + (ia64_process_unwind): Likewise. + (hppa_process_unwind): Likewise. + (arm_process_unwind): Likewise. + (process_dynamic_section): Likewise. + (process_version_sections): Likewise. + (process_symbol_table): Likewise. + (process_section_groups): Likewise. + Add check before indexing into the symbol table. + (apply_relocations): Likewise. + 2011-10-11 Chris PR binutils/13051 diff --git a/binutils/readelf.c b/binutils/readelf.c index d68cf27..df27b88 100644 --- a/binutils/readelf.c +++ b/binutils/readelf.c @@ -271,9 +271,9 @@ print_mode; #define DT_VERSIONTAGIDX(tag) (DT_VERNEEDNUM - (tag)) /* Reverse order! */ -#define GET_ELF_SYMBOLS(file, section) \ - (is_32bit_elf ? get_32bit_elf_symbols (file, section) \ - : get_64bit_elf_symbols (file, section)) +#define GET_ELF_SYMBOLS(file, section, sym_count) \ + (is_32bit_elf ? get_32bit_elf_symbols (file, section, sym_count) \ + : get_64bit_elf_symbols (file, section, sym_count)) #define VALID_DYNAMIC_NAME(offset) ((dynamic_strings != NULL) && (offset < dynamic_strings_length)) /* GET_DYNAMIC_NAME asssumes that VALID_DYNAMIC_NAME has @@ -4050,11 +4050,13 @@ get_64bit_section_headers (FILE * file, unsigned int num) } static Elf_Internal_Sym * -get_32bit_elf_symbols (FILE * file, Elf_Internal_Shdr * section) +get_32bit_elf_symbols (FILE * file, + Elf_Internal_Shdr * section, + unsigned long * num_syms_return) { - unsigned long number; + unsigned long number = 0; Elf32_External_Sym * esyms = NULL; - Elf_External_Sym_Shndx * shndx; + Elf_External_Sym_Shndx * shndx = NULL; Elf_Internal_Sym * isyms = NULL; Elf_Internal_Sym * psym; unsigned int j; @@ -4063,7 +4065,7 @@ get_32bit_elf_symbols (FILE * file, Elf_Internal_Shdr * section) if (section->sh_entsize == 0) { error (_("sh_entsize is zero\n")); - return NULL; + goto exit_point; } number = section->sh_size / section->sh_entsize; @@ -4071,13 +4073,13 @@ get_32bit_elf_symbols (FILE * file, Elf_Internal_Shdr * section) if (number * sizeof (Elf32_External_Sym) > section->sh_size + 1) { error (_("Invalid sh_entsize\n")); - return NULL; + goto exit_point; } esyms = (Elf32_External_Sym *) get_data (NULL, file, section->sh_offset, 1, section->sh_size, _("symbols")); if (esyms == NULL) - return NULL; + goto exit_point; shndx = NULL; if (symtab_shndx_hdr != NULL @@ -4116,21 +4118,26 @@ get_32bit_elf_symbols (FILE * file, Elf_Internal_Shdr * section) } exit_point: - if (shndx) + if (shndx != NULL) free (shndx); - if (esyms) + if (esyms != NULL) free (esyms); + if (num_syms_return != NULL) + * num_syms_return = isyms == NULL ? 0 : number; + return isyms; } static Elf_Internal_Sym * -get_64bit_elf_symbols (FILE * file, Elf_Internal_Shdr * section) +get_64bit_elf_symbols (FILE * file, + Elf_Internal_Shdr * section, + unsigned long * num_syms_return) { - unsigned long number; - Elf64_External_Sym * esyms; - Elf_External_Sym_Shndx * shndx; - Elf_Internal_Sym * isyms; + unsigned long number = 0; + Elf64_External_Sym * esyms = NULL; + Elf_External_Sym_Shndx * shndx = NULL; + Elf_Internal_Sym * isyms = NULL; Elf_Internal_Sym * psym; unsigned int j; @@ -4138,7 +4145,7 @@ get_64bit_elf_symbols (FILE * file, Elf_Internal_Shdr * section) if (section->sh_entsize == 0) { error (_("sh_entsize is zero\n")); - return NULL; + goto exit_point; } number = section->sh_size / section->sh_entsize; @@ -4146,15 +4153,14 @@ get_64bit_elf_symbols (FILE * file, Elf_Internal_Shdr * section) if (number * sizeof (Elf64_External_Sym) > section->sh_size + 1) { error (_("Invalid sh_entsize\n")); - return NULL; + goto exit_point; } esyms = (Elf64_External_Sym *) get_data (NULL, file, section->sh_offset, 1, section->sh_size, _("symbols")); if (!esyms) - return NULL; + goto exit_point; - shndx = NULL; if (symtab_shndx_hdr != NULL && (symtab_shndx_hdr->sh_link == (unsigned long) (section - section_headers))) @@ -4163,11 +4169,8 @@ get_64bit_elf_symbols (FILE * file, Elf_Internal_Shdr * section) symtab_shndx_hdr->sh_offset, 1, symtab_shndx_hdr->sh_size, _("symtab shndx")); - if (!shndx) - { - free (esyms); - return NULL; - } + if (shndx == NULL) + goto exit_point; } isyms = (Elf_Internal_Sym *) cmalloc (number, sizeof (Elf_Internal_Sym)); @@ -4175,32 +4178,34 @@ get_64bit_elf_symbols (FILE * file, Elf_Internal_Shdr * section) if (isyms == NULL) { error (_("Out of memory\n")); - if (shndx) - free (shndx); - free (esyms); - return NULL; + goto exit_point; } - for (j = 0, psym = isyms; - j < number; - j++, psym++) + for (j = 0, psym = isyms; j < number; j++, psym++) { psym->st_name = BYTE_GET (esyms[j].st_name); psym->st_info = BYTE_GET (esyms[j].st_info); psym->st_other = BYTE_GET (esyms[j].st_other); psym->st_shndx = BYTE_GET (esyms[j].st_shndx); + if (psym->st_shndx == (SHN_XINDEX & 0xffff) && shndx != NULL) psym->st_shndx = byte_get ((unsigned char *) &shndx[j], sizeof (shndx[j])); else if (psym->st_shndx >= (SHN_LORESERVE & 0xffff)) psym->st_shndx += SHN_LORESERVE - (SHN_LORESERVE & 0xffff); + psym->st_value = BYTE_GET (esyms[j].st_value); psym->st_size = BYTE_GET (esyms[j].st_size); } - if (shndx) + exit_point: + if (shndx != NULL) free (shndx); - free (esyms); + if (esyms != NULL) + free (esyms); + + if (num_syms_return != NULL) + * num_syms_return = isyms == NULL ? 0 : number; return isyms; } @@ -4568,8 +4573,7 @@ process_section_headers (FILE * file) } CHECK_ENTSIZE (section, i, Sym); - num_dynamic_syms = section->sh_size / section->sh_entsize; - dynamic_symbols = GET_ELF_SYMBOLS (file, section); + dynamic_symbols = GET_ELF_SYMBOLS (file, section, & num_dynamic_syms); } else if (section->sh_type == SHT_STRTAB && streq (name, ".dynstr")) @@ -4924,6 +4928,7 @@ process_section_groups (FILE * file) Elf_Internal_Shdr * symtab_sec; Elf_Internal_Shdr * strtab_sec; Elf_Internal_Sym * symtab; + unsigned long num_syms; char * strtab; size_t strtab_size; @@ -4981,6 +4986,7 @@ process_section_groups (FILE * file) symtab_sec = NULL; strtab_sec = NULL; symtab = NULL; + num_syms = 0; strtab = NULL; strtab_size = 0; for (i = 0, section = section_headers, group = section_groups; @@ -5011,7 +5017,7 @@ process_section_groups (FILE * file) symtab_sec = sec; if (symtab) free (symtab); - symtab = GET_ELF_SYMBOLS (file, symtab_sec); + symtab = GET_ELF_SYMBOLS (file, symtab_sec, & num_syms); } if (symtab == NULL) @@ -5020,6 +5026,12 @@ process_section_groups (FILE * file) continue; } + if (section->sh_info >= num_syms) + { + error (_("Bad sh_info in group section `%s'\n"), name); + continue; + } + sym = symtab + section->sh_info; if (ELF_ST_TYPE (sym->st_info) == STT_SECTION) @@ -5457,8 +5469,7 @@ process_relocs (FILE * file) && symsec->sh_type != SHT_DYNSYM) continue; - nsyms = symsec->sh_size / symsec->sh_entsize; - symtab = GET_ELF_SYMBOLS (file, symsec); + symtab = GET_ELF_SYMBOLS (file, symsec, & nsyms); if (symtab == NULL) continue; @@ -5770,8 +5781,7 @@ ia64_process_unwind (FILE * file) if (sec->sh_type == SHT_SYMTAB && sec->sh_link < elf_header.e_shnum) { - aux.nsyms = sec->sh_size / sec->sh_entsize; - aux.symtab = GET_ELF_SYMBOLS (file, sec); + aux.symtab = GET_ELF_SYMBOLS (file, sec, & aux.nsyms); strsec = section_headers + sec->sh_link; assert (aux.strtab == NULL); @@ -6184,8 +6194,7 @@ hppa_process_unwind (FILE * file) if (sec->sh_type == SHT_SYMTAB && sec->sh_link < elf_header.e_shnum) { - aux.nsyms = sec->sh_size / sec->sh_entsize; - aux.symtab = GET_ELF_SYMBOLS (file, sec); + aux.symtab = GET_ELF_SYMBOLS (file, sec, & aux.nsyms); strsec = section_headers + sec->sh_link; assert (aux.strtab == NULL); @@ -7069,8 +7078,7 @@ arm_process_unwind (FILE *file) { if (sec->sh_type == SHT_SYMTAB && sec->sh_link < elf_header.e_shnum) { - aux.nsyms = sec->sh_size / sec->sh_entsize; - aux.symtab = GET_ELF_SYMBOLS (file, sec); + aux.symtab = GET_ELF_SYMBOLS (file, sec, & aux.nsyms); strsec = section_headers + sec->sh_link; assert (aux.strtab == NULL); @@ -7531,14 +7539,12 @@ process_dynamic_section (FILE * file) else section.sh_entsize = sizeof (Elf64_External_Sym); - num_dynamic_syms = section.sh_size / section.sh_entsize; + dynamic_symbols = GET_ELF_SYMBOLS (file, §ion, & num_dynamic_syms); if (num_dynamic_syms < 1) { error (_("Unable to determine the number of symbols to load\n")); continue; } - - dynamic_symbols = GET_ELF_SYMBOLS (file, §ion); } } @@ -8338,6 +8344,7 @@ process_version_sections (FILE * file) char * strtab; Elf_Internal_Sym * symbols; Elf_Internal_Shdr * string_sec; + unsigned long num_syms; long off; if (section->sh_link >= elf_header.e_shnum) @@ -8351,7 +8358,7 @@ process_version_sections (FILE * file) found = 1; - symbols = GET_ELF_SYMBOLS (file, link_section); + symbols = GET_ELF_SYMBOLS (file, link_section, & num_syms); if (symbols == NULL) break; @@ -8420,10 +8427,8 @@ process_version_sections (FILE * file) data[cnt + j] & VERSYM_HIDDEN ? '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)) + array, break to avoid an out-of-bounds read. */ + if ((unsigned long)(cnt + j) >= num_syms) { warn (_("invalid index into symbol array\n")); break; @@ -9155,6 +9160,7 @@ process_symbol_table (FILE * file) unsigned long int strtab_size = 0; Elf_Internal_Sym * symtab; Elf_Internal_Sym * psym; + unsigned long num_syms; if ((section->sh_type != SHT_SYMTAB && section->sh_type != SHT_DYNSYM) @@ -9178,7 +9184,7 @@ process_symbol_table (FILE * file) else printf (_(" Num: Value Size Type Bind Vis Ndx Name\n")); - symtab = GET_ELF_SYMBOLS (file, section); + symtab = GET_ELF_SYMBOLS (file, section, & num_syms); if (symtab == NULL) continue; @@ -9199,9 +9205,7 @@ process_symbol_table (FILE * file) strtab_size = strtab != NULL ? string_sec->sh_size : 0; } - for (si = 0, psym = symtab; - si < section->sh_size / section->sh_entsize; - si++, psym++) + for (si = 0, psym = symtab; si < num_syms; si++, psym++) { printf ("%6d: ", si); print_vma (psym->st_value, LONG_HEX); @@ -10057,6 +10061,7 @@ apply_relocations (void * file, Elf_Internal_Rela * rp; Elf_Internal_Shdr * symsec; Elf_Internal_Sym * symtab; + unsigned long num_syms; Elf_Internal_Sym * sym; if ((relsec->sh_type != SHT_RELA && relsec->sh_type != SHT_REL) @@ -10086,7 +10091,7 @@ apply_relocations (void * file, is_rela = FALSE; symsec = section_headers + relsec->sh_link; - symtab = GET_ELF_SYMBOLS ((FILE *) file, symsec); + symtab = GET_ELF_SYMBOLS ((FILE *) file, symsec, & num_syms); for (rp = relocs; rp < relocs + num_relocs; ++rp) { @@ -10094,6 +10099,7 @@ apply_relocations (void * file, unsigned int reloc_type; unsigned int reloc_size; unsigned char * rloc; + unsigned long sym_index; reloc_type = get_reloc_type (rp->r_info); @@ -10127,7 +10133,14 @@ apply_relocations (void * file, continue; } - sym = symtab + get_reloc_symindex (rp->r_info); + sym_index = (unsigned long) get_reloc_symindex (rp->r_info); + if (sym_index >= num_syms) + { + warn (_("skipping invalid relocation symbol index 0x%lx in section %s\n"), + sym_index, SECTION_NAME (section)); + continue; + } + sym = symtab + sym_index; /* If the reloc has a symbol associated with it, make sure that it is of an appropriate type. -- 2.7.4