Fix address violation problems when parsing corrupt ELF binaries.

PR 21916
	* elf-attrs.c (_bfd_elf_parse_attributes): Complain about very
	small section lengths.
	* elf.c (_bfd_elf_setup_sections): Skip empty entries in the group
	table.
	(elfcore_grok_freebsd_prstatus): Add checks to make sure that
	there is enough data present in the note.
This commit is contained in:
Nick Clifton
2017-08-08 13:20:02 +01:00
parent 1fea592a7d
commit 24d3e51bf0
3 changed files with 80 additions and 47 deletions

View File

@ -1,3 +1,13 @@
2017-08-08 Nick Clifton <nickc@redhat.com>
PR 21916
* elf-attrs.c (_bfd_elf_parse_attributes): Complain about very
small section lengths.
* elf.c (_bfd_elf_setup_sections): Skip empty entries in the group
table.
(elfcore_grok_freebsd_prstatus): Add checks to make sure that
there is enough data present in the note.
2017-08-08 Alan Modra <amodra@gmail.com> 2017-08-08 Alan Modra <amodra@gmail.com>
PR 21017 PR 21017

View File

@ -468,6 +468,12 @@ _bfd_elf_parse_attributes (bfd *abfd, Elf_Internal_Shdr * hdr)
if (section_len > len) if (section_len > len)
section_len = len; section_len = len;
len -= section_len; len -= section_len;
if (section_len <= 4)
{
_bfd_error_handler (_("%B: error: attribute section length too small: %ld"),
abfd, section_len);
break;
}
section_len -= 4; section_len -= 4;
namelen = strnlen ((char *) p, section_len) + 1; namelen = strnlen ((char *) p, section_len) + 1;
if (namelen == 0 || namelen >= section_len) if (namelen == 0 || namelen >= section_len)

111
bfd/elf.c
View File

@ -896,32 +896,39 @@ _bfd_elf_setup_sections (bfd *abfd)
n_elt = shdr->sh_size / 4; n_elt = shdr->sh_size / 4;
while (--n_elt != 0) while (--n_elt != 0)
if ((++idx)->shdr->bfd_section) {
elf_sec_group (idx->shdr->bfd_section) = shdr->bfd_section; ++ idx;
else if (idx->shdr->sh_type == SHT_RELA
|| idx->shdr->sh_type == SHT_REL) if (idx->shdr == NULL)
/* We won't include relocation sections in section groups in continue;
output object files. We adjust the group section size here else if (idx->shdr->bfd_section)
so that relocatable link will work correctly when elf_sec_group (idx->shdr->bfd_section) = shdr->bfd_section;
relocation sections are in section group in input object else if (idx->shdr->sh_type == SHT_RELA
files. */ || idx->shdr->sh_type == SHT_REL)
shdr->bfd_section->size -= 4; /* We won't include relocation sections in section groups in
else output object files. We adjust the group section size here
{ so that relocatable link will work correctly when
/* There are some unknown sections in the group. */ relocation sections are in section group in input object
_bfd_error_handler files. */
/* xgettext:c-format */ shdr->bfd_section->size -= 4;
(_("%B: unknown type [%#x] section `%s' in group [%A]"), else
abfd, {
idx->shdr->sh_type, /* There are some unknown sections in the group. */
bfd_elf_string_from_elf_section (abfd, _bfd_error_handler
(elf_elfheader (abfd) /* xgettext:c-format */
->e_shstrndx), (_("%B: unknown type [%#x] section `%s' in group [%A]"),
idx->shdr->sh_name), abfd,
shdr->bfd_section); idx->shdr->sh_type,
result = FALSE; bfd_elf_string_from_elf_section (abfd,
} (elf_elfheader (abfd)
->e_shstrndx),
idx->shdr->sh_name),
shdr->bfd_section);
result = FALSE;
}
}
} }
return result; return result;
} }
@ -8954,7 +8961,7 @@ elfcore_maybe_make_sect (bfd *abfd, char *name, asection *sect)
such a section already exists. such a section already exists.
- For the multi-threaded case, a section named "NAME/PID", where - For the multi-threaded case, a section named "NAME/PID", where
PID is elfcore_make_pid (abfd). PID is elfcore_make_pid (abfd).
Both pseudosections have identical contents. */ Both pseudosections have identical contents. */
bfd_boolean bfd_boolean
_bfd_elfcore_make_pseudosection (bfd *abfd, _bfd_elfcore_make_pseudosection (bfd *abfd,
char *name, char *name,
@ -9883,58 +9890,68 @@ elfcore_grok_freebsd_prstatus (bfd *abfd, Elf_Internal_Note *note)
{ {
size_t offset; size_t offset;
size_t size; size_t size;
size_t min_size;
/* Check for version 1 in pr_version. */ /* Compute offset of pr_getregsz, skipping over pr_statussz.
if (bfd_h_get_32 (abfd, (bfd_byte *) note->descdata) != 1) Also compute minimum size of this note. */
return FALSE;
offset = 4;
/* Skip over pr_statussz. */
switch (elf_elfheader (abfd)->e_ident[EI_CLASS]) switch (elf_elfheader (abfd)->e_ident[EI_CLASS])
{ {
case ELFCLASS32: case ELFCLASS32:
offset += 4; offset = 4 + 4;
min_size = offset + (4 * 2) + 4 + 4 + 4;
break; break;
case ELFCLASS64: case ELFCLASS64:
offset += 4; /* Padding before pr_statussz. */ offset = 4 + 4 + 8; /* Includes padding before pr_statussz. */
offset += 8; min_size = offset + (8 * 2) + 4 + 4 + 4 + 4;
break; break;
default: default:
return FALSE; return FALSE;
} }
if (note->descsz < min_size)
return FALSE;
/* Check for version 1 in pr_version. */
if (bfd_h_get_32 (abfd, (bfd_byte *) note->descdata) != 1)
return FALSE;
/* Extract size of pr_reg from pr_gregsetsz. */ /* Extract size of pr_reg from pr_gregsetsz. */
/* Skip over pr_gregsetsz and pr_fpregsetsz. */
if (elf_elfheader (abfd)->e_ident[EI_CLASS] == ELFCLASS32) if (elf_elfheader (abfd)->e_ident[EI_CLASS] == ELFCLASS32)
size = bfd_h_get_32 (abfd, (bfd_byte *) note->descdata + offset); {
size = bfd_h_get_32 (abfd, (bfd_byte *) note->descdata + offset);
offset += 4 * 2;
}
else else
size = bfd_h_get_64 (abfd, (bfd_byte *) note->descdata + offset); {
size = bfd_h_get_64 (abfd, (bfd_byte *) note->descdata + offset);
offset += 8 * 2;
}
/* Skip over pr_gregsetsz and pr_fpregsetsz. */ /* Skip over pr_osreldate. */
if (elf_elfheader (abfd)->e_ident[EI_CLASS] == ELFCLASS32)
offset += 4 * 2;
else
offset += 8 * 2;
/* Skip over pr_osreldate. */
offset += 4; offset += 4;
/* Read signal from pr_cursig. */ /* Read signal from pr_cursig. */
if (elf_tdata (abfd)->core->signal == 0) if (elf_tdata (abfd)->core->signal == 0)
elf_tdata (abfd)->core->signal elf_tdata (abfd)->core->signal
= bfd_h_get_32 (abfd, (bfd_byte *) note->descdata + offset); = bfd_h_get_32 (abfd, (bfd_byte *) note->descdata + offset);
offset += 4; offset += 4;
/* Read TID from pr_pid. */ /* Read TID from pr_pid. */
elf_tdata (abfd)->core->lwpid elf_tdata (abfd)->core->lwpid
= bfd_h_get_32 (abfd, (bfd_byte *) note->descdata + offset); = bfd_h_get_32 (abfd, (bfd_byte *) note->descdata + offset);
offset += 4; offset += 4;
/* Padding before pr_reg. */ /* Padding before pr_reg. */
if (elf_elfheader (abfd)->e_ident[EI_CLASS] == ELFCLASS64) if (elf_elfheader (abfd)->e_ident[EI_CLASS] == ELFCLASS64)
offset += 4; offset += 4;
/* Make sure that there is enough data remaining in the note. */
if ((note->descsz - offset) < size)
return FALSE;
/* Make a ".reg/999" section and a ".reg" section. */ /* Make a ".reg/999" section and a ".reg" section. */
return _bfd_elfcore_make_pseudosection (abfd, ".reg", return _bfd_elfcore_make_pseudosection (abfd, ".reg",
size, note->descpos + offset); size, note->descpos + offset);