More fixes for memory corruption when readelf processes corrupt files.

PR binutils/17531
	(get_32bit_program_headers): Verify program header entry size
	before reading in the program headers.
	(get_64bit_program_headers): Likewise.
	(get_unwind_section_word): Do nothing if no section was provided.
	Fail if the offset is outside of the section.
	(print_dynamic_symbol): Catch out of range symbol indicies.
	(process_mips_specific): Likewise.
	(process_attributes): Make sure that there is enough space left in
	the section before attempting to read the length of the next
	attribute.
This commit is contained in:
Nick Clifton 2014-11-04 15:29:03 +00:00
parent bb0d867169
commit e0a31db1b1
2 changed files with 138 additions and 46 deletions

View file

@ -11,6 +11,17 @@
(process_dynamic_section): Change an assert to an error message.
(process_symbol_table): Handle corrupt histograms.
(get_32bit_program_headers): Verify program header entry size
before reading in the program headers.
(get_64bit_program_headers): Likewise.
(get_unwind_section_word): Do nothing if no section was provided.
Fail if the offset is outside of the section.
(print_dynamic_symbol): Catch out of range symbol indicies.
(process_mips_specific): Likewise.
(process_attributes): Make sure that there is enough space left in
the section before attempting to read the length of the next
attribute.
2014-11-03 Nick Clifton <nickc@redhat.com>
PR binutils/17512

View file

@ -4104,21 +4104,31 @@ process_file_header (void)
return 1;
}
static int
static bfd_boolean
get_32bit_program_headers (FILE * file, Elf_Internal_Phdr * pheaders)
{
Elf32_External_Phdr * phdrs;
Elf32_External_Phdr * external;
Elf_Internal_Phdr * internal;
unsigned int i;
unsigned int size = elf_header.e_phentsize;
unsigned int num = elf_header.e_phnum;
/* PR binutils/17531: Cope with unexpected section header sizes. */
if (size == 0 || num == 0)
return FALSE;
if (size < sizeof * phdrs)
{
error (_("The e_phentsize field in the ELF header is less than the size of an ELF program header\n"));
return FALSE;
}
if (size > sizeof * phdrs)
warn (_("The e_phentsize field in the ELF header is larger than the size of an ELF program header\n"));
phdrs = (Elf32_External_Phdr *) get_data (NULL, file, elf_header.e_phoff,
elf_header.e_phentsize,
elf_header.e_phnum,
_("program headers"));
if (!phdrs)
return 0;
size, num, _("program headers"));
if (phdrs == NULL)
return FALSE;
for (i = 0, internal = pheaders, external = phdrs;
i < elf_header.e_phnum;
@ -4135,24 +4145,34 @@ get_32bit_program_headers (FILE * file, Elf_Internal_Phdr * pheaders)
}
free (phdrs);
return 1;
return TRUE;
}
static int
static bfd_boolean
get_64bit_program_headers (FILE * file, Elf_Internal_Phdr * pheaders)
{
Elf64_External_Phdr * phdrs;
Elf64_External_Phdr * external;
Elf_Internal_Phdr * internal;
unsigned int i;
unsigned int size = elf_header.e_phentsize;
unsigned int num = elf_header.e_phnum;
/* PR binutils/17531: Cope with unexpected section header sizes. */
if (size == 0 || num == 0)
return FALSE;
if (size < sizeof * phdrs)
{
error (_("The e_phentsize field in the ELF header is less than the size of an ELF program header\n"));
return FALSE;
}
if (size > sizeof * phdrs)
warn (_("The e_phentsize field in the ELF header is larger than the size of an ELF program header\n"));
phdrs = (Elf64_External_Phdr *) get_data (NULL, file, elf_header.e_phoff,
elf_header.e_phentsize,
elf_header.e_phnum,
_("program headers"));
size, num, _("program headers"));
if (!phdrs)
return 0;
return FALSE;
for (i = 0, internal = pheaders, external = phdrs;
i < elf_header.e_phnum;
@ -4169,8 +4189,7 @@ get_64bit_program_headers (FILE * file, Elf_Internal_Phdr * pheaders)
}
free (phdrs);
return 1;
return TRUE;
}
/* Returns 1 if the program headers were read into `program_headers'. */
@ -6903,6 +6922,9 @@ get_unwind_section_word (struct arm_unw_aux_info * aux,
unsigned int word;
bfd_boolean wrapped;
if (sec == NULL || arm_sec == NULL)
return FALSE;
addr->section = SHN_UNDEF;
addr->offset = 0;
@ -6958,6 +6980,10 @@ get_unwind_section_word (struct arm_unw_aux_info * aux,
if (arm_sec->data == NULL)
return FALSE;
/* If the offset is invalid then fail. */
if (word_offset > sec->sh_size - 4)
return FALSE;
/* Get the word at the required offset. */
word = byte_get (arm_sec->data + word_offset, 4);
@ -9585,7 +9611,7 @@ get_symbol_index_type (unsigned int type)
else if (type >= SHN_LORESERVE)
sprintf (buff, "RSV[0x%04x]", type & 0xffff);
else if (type >= elf_header.e_shnum)
sprintf (buff, "bad section index[%3d]", type);
sprintf (buff, _("bad section index[%3d]"), type);
else
sprintf (buff, "%3d", type);
break;
@ -9637,12 +9663,18 @@ print_dynamic_symbol (bfd_vma si, unsigned long hn)
Elf_Internal_Sym * psym;
int n;
psym = dynamic_symbols + si;
n = print_vma (si, DEC_5);
if (n < 5)
fputs (&" "[n], stdout);
printf (" %3lu: ", hn);
if (dynamic_symbols == NULL || si >= num_dynamic_syms)
{
printf (_("<No info available>\n"));
return;
}
psym = dynamic_symbols + si;
print_vma (psym->st_value, LONG_HEX);
putchar (' ');
print_vma (psym->st_size, DEC_5);
@ -10313,6 +10345,7 @@ process_syminfo (FILE * file ATTRIBUTE_UNUSED)
unsigned short int flags = dynamic_syminfo[i].si_flags;
printf ("%4d: ", i);
assert (i < num_dynamic_syms);
if (VALID_DYNAMIC_NAME (dynamic_symbols[i].st_name))
print_symbol (30, GET_DYNAMIC_NAME (dynamic_symbols[i].st_name));
else
@ -12426,6 +12459,7 @@ display_raw_attribute (unsigned char * p, unsigned char * end)
unsigned long addr = 0;
size_t bytes = end - p;
assert (end > p);
while (bytes)
{
int j;
@ -12577,6 +12611,11 @@ process_attributes (FILE * file,
bfd_boolean public_section;
bfd_boolean gnu_section;
if (len <= 4)
{
error (_("Tag section ends prematurely\n"));
break;
}
section_len = byte_get (p, 4);
p += 4;
@ -12611,12 +12650,22 @@ process_attributes (FILE * file,
p += namelen;
section_len -= namelen;
while (section_len > 0)
{
int tag = *(p++);
int tag;
int val;
bfd_vma size;
/* PR binutils/17531: Safe handling of corrupt files. */
if (section_len < 6)
{
error (_("Unused bytes at end of section\n"));
section_len = 0;
break;
}
tag = *(p++);
size = byte_get (p, 4);
if (size > section_len)
{
@ -12624,6 +12673,14 @@ process_attributes (FILE * file,
(unsigned) size, (unsigned) section_len);
size = section_len;
}
/* PR binutils/17531: Safe handling of corrupt files. */
if (size < 6)
{
error (_("Bad subsection length (%u < 6)\n"),
(unsigned) size);
section_len = 0;
break;
}
section_len -= size;
end = p + size - 1;
@ -13349,15 +13406,22 @@ process_mips_specific (FILE * file)
for (cnt = 0; cnt < conflictsno; ++cnt)
{
Elf_Internal_Sym * psym = & dynamic_symbols[iconf[cnt]];
printf ("%5lu: %8lu ", (unsigned long) cnt, iconf[cnt]);
print_vma (psym->st_value, FULL_HEX);
putchar (' ');
if (VALID_DYNAMIC_NAME (psym->st_name))
print_symbol (25, GET_DYNAMIC_NAME (psym->st_name));
if (iconf[cnt] >= num_dynamic_syms)
printf (_("<corrupt symbol index>"));
else
printf (_("<corrupt: %14ld>"), psym->st_name);
{
Elf_Internal_Sym * psym;
psym = & dynamic_symbols[iconf[cnt]];
print_vma (psym->st_value, FULL_HEX);
putchar (' ');
if (VALID_DYNAMIC_NAME (psym->st_name))
print_symbol (25, GET_DYNAMIC_NAME (psym->st_name));
else
printf (_("<corrupt: %14ld>"), psym->st_name);
}
putchar ('\n');
}
@ -13432,21 +13496,31 @@ process_mips_specific (FILE * file)
_("Ndx"), _("Name"));
sym_width = (is_32bit_elf ? 80 : 160) - 28 - addr_size * 6 - 1;
for (i = gotsym; i < symtabno; i++)
{
Elf_Internal_Sym * psym;
psym = dynamic_symbols + i;
ent = print_mips_got_entry (data, pltgot, ent);
printf (" ");
print_vma (psym->st_value, LONG_HEX);
printf (" %-7s %3s ",
get_symbol_type (ELF_ST_TYPE (psym->st_info)),
get_symbol_index_type (psym->st_shndx));
if (VALID_DYNAMIC_NAME (psym->st_name))
print_symbol (sym_width, GET_DYNAMIC_NAME (psym->st_name));
if (dynamic_symbols == NULL)
printf (_("<no dynamic symbols>"));
else if (i < num_dynamic_syms)
{
Elf_Internal_Sym * psym = dynamic_symbols + i;
print_vma (psym->st_value, LONG_HEX);
printf (" %-7s %3s ",
get_symbol_type (ELF_ST_TYPE (psym->st_info)),
get_symbol_index_type (psym->st_shndx));
if (VALID_DYNAMIC_NAME (psym->st_name))
print_symbol (sym_width, GET_DYNAMIC_NAME (psym->st_name));
else
printf (_("<corrupt: %14ld>"), psym->st_name);
}
else
printf (_("<corrupt: %14ld>"), psym->st_name);
printf (_("<symbol index %lu exceeds number of dynamic symbols>"), i);
printf ("\n");
}
printf ("\n");
@ -13505,19 +13579,26 @@ process_mips_specific (FILE * file)
sym_width = (is_32bit_elf ? 80 : 160) - 17 - addr_size * 6 - 1;
for (i = 0; i < count; i++)
{
Elf_Internal_Sym * psym;
unsigned long index = get_reloc_symindex (rels[i].r_info);
psym = dynamic_symbols + get_reloc_symindex (rels[i].r_info);
ent = print_mips_pltgot_entry (data, mips_pltgot, ent);
printf (" ");
print_vma (psym->st_value, LONG_HEX);
printf (" %-7s %3s ",
get_symbol_type (ELF_ST_TYPE (psym->st_info)),
get_symbol_index_type (psym->st_shndx));
if (VALID_DYNAMIC_NAME (psym->st_name))
print_symbol (sym_width, GET_DYNAMIC_NAME (psym->st_name));
if (index >= num_dynamic_syms)
printf (_("<corrupt symbol index: %lu>"), index);
else
printf (_("<corrupt: %14ld>"), psym->st_name);
{
Elf_Internal_Sym * psym = dynamic_symbols + index;
print_vma (psym->st_value, LONG_HEX);
printf (" %-7s %3s ",
get_symbol_type (ELF_ST_TYPE (psym->st_info)),
get_symbol_index_type (psym->st_shndx));
if (VALID_DYNAMIC_NAME (psym->st_name))
print_symbol (sym_width, GET_DYNAMIC_NAME (psym->st_name));
else
printf (_("<corrupt: %14ld>"), psym->st_name);
}
printf ("\n");
}
printf ("\n");