ELF core file size checks

Catch fuzzed segments where p_offset + p_filesz wraps, and limit error
output.

	* elfcore.h (elf_core_file_p): Rewrite segment checks using
	bfd_get_file_size.  Set read_only on file size errors.
	* elfcode.h (elf_swap_shdr_in): Don't repeat error message.
This commit is contained in:
Alan Modra
2021-10-29 15:09:52 +10:30
parent c82ebeb7e6
commit c45c3dba8c
2 changed files with 19 additions and 25 deletions

View File

@ -325,9 +325,10 @@ elf_swap_shdr_in (bfd *abfd,
&& ((ufile_ptr) dst->sh_offset > filesize && ((ufile_ptr) dst->sh_offset > filesize
|| dst->sh_size > filesize - dst->sh_offset)) || dst->sh_size > filesize - dst->sh_offset))
{ {
if (!abfd->read_only)
_bfd_error_handler (_("warning: %pB has a section "
"extending past end of file"), abfd);
abfd->read_only = 1; abfd->read_only = 1;
_bfd_error_handler (_("warning: %pB has a section "
"extending past end of file"), abfd);
} }
} }
dst->sh_link = H_GET_32 (abfd, src->sh_link); dst->sh_link = H_GET_32 (abfd, src->sh_link);

View File

@ -92,6 +92,7 @@ elf_core_file_p (bfd *abfd)
unsigned int phindex; unsigned int phindex;
const struct elf_backend_data *ebd; const struct elf_backend_data *ebd;
bfd_size_type amt; bfd_size_type amt;
ufile_ptr filesize;
/* Read in the ELF header in external format. */ /* Read in the ELF header in external format. */
if (bfd_bread (&x_ehdr, sizeof (x_ehdr), abfd) != sizeof (x_ehdr)) if (bfd_bread (&x_ehdr, sizeof (x_ehdr), abfd) != sizeof (x_ehdr))
@ -286,29 +287,21 @@ elf_core_file_p (bfd *abfd)
goto fail; goto fail;
/* Check for core truncation. */ /* Check for core truncation. */
{ filesize = bfd_get_file_size (abfd);
bfd_size_type high = 0; if (filesize != 0)
struct stat statbuf; {
for (phindex = 0; phindex < i_ehdrp->e_phnum; ++phindex) for (phindex = 0; phindex < i_ehdrp->e_phnum; ++phindex)
{ {
Elf_Internal_Phdr *p = i_phdrp + phindex; Elf_Internal_Phdr *p = i_phdrp + phindex;
if (p->p_filesz) if (p->p_filesz
{ && (p->p_offset >= filesize
bfd_size_type current = p->p_offset + p->p_filesz; || p->p_filesz > filesize - p->p_offset))
if (high < current) {
high = current; _bfd_error_handler (_("warning: %pB has a segment "
} "extending past end of file"), abfd);
} abfd->read_only = 1;
if (bfd_stat (abfd, &statbuf) == 0) break;
{ }
if ((bfd_size_type) statbuf.st_size < high)
{
_bfd_error_handler
/* xgettext:c-format */
(_("warning: %pB is truncated: expected core file "
"size >= %" PRIu64 ", found: %" PRIu64),
abfd, (uint64_t) high, (uint64_t) statbuf.st_size);
}
} }
} }