mirror of
https://sourceware.org/git/binutils-gdb.git
synced 2024-11-23 10:03:47 +08:00
PR28834, PR26946 sanity checking section size
This patch provides a new function to sanity check section sizes. It's mostly extracted from what we had in bfd_get_full_section_contents but also handles compressed debug sections. Improvements are: - section file offset is taken into account, - added checks that a compressed section can be read from file. The function is then used when handling multiple .debug_* sections that need to be read into a single buffer, to sanity check sizes before allocating the buffer. PR 26946, PR 28834 * Makefile.am (LIBBFD_H_FILES): Add section.c. * compress.c (bfd_get_full_section_contents): Move section size sanity checks.. * section.c (_bfd_section_size_insane): ..to here. New function. * dwarf2.c (read_section): Use _bfd_section_size_insane. (_bfd_dwarf2_slurp_debug_info): Likewise. * Makefile.in: Regenerate. * libbfd.h: Regenerate.
This commit is contained in:
parent
d0e5049d8f
commit
f7502dfe3f
@ -929,7 +929,7 @@ BFD_H_FILES = bfd-in.h init.c opncls.c libbfd.c \
|
||||
linker.c simple.c compress.c
|
||||
BFD64_H_FILES = archive64.c
|
||||
LIBBFD_H_FILES = libbfd-in.h libbfd.c bfdio.c bfdwin.c \
|
||||
cache.c reloc.c targets.c archures.c linker.c
|
||||
cache.c reloc.c section.c targets.c archures.c linker.c
|
||||
LIBCOFF_H_FILES = libcoff-in.h coffcode.h
|
||||
|
||||
headers: stmp-bin2-h stmp-lbfd-h stmp-lcoff-h
|
||||
|
@ -1223,7 +1223,7 @@ BFD_H_FILES = bfd-in.h init.c opncls.c libbfd.c \
|
||||
|
||||
BFD64_H_FILES = archive64.c
|
||||
LIBBFD_H_FILES = libbfd-in.h libbfd.c bfdio.c bfdwin.c \
|
||||
cache.c reloc.c targets.c archures.c linker.c
|
||||
cache.c reloc.c section.c targets.c archures.c linker.c
|
||||
|
||||
LIBCOFF_H_FILES = libcoff-in.h coffcode.h
|
||||
|
||||
|
@ -244,7 +244,7 @@ DESCRIPTION
|
||||
bool
|
||||
bfd_get_full_section_contents (bfd *abfd, sec_ptr sec, bfd_byte **ptr)
|
||||
{
|
||||
bfd_size_type sz;
|
||||
bfd_size_type sz = bfd_get_section_limit_octets (abfd, sec);
|
||||
bfd_byte *p = *ptr;
|
||||
bool ret;
|
||||
bfd_size_type save_size;
|
||||
@ -253,45 +253,30 @@ bfd_get_full_section_contents (bfd *abfd, sec_ptr sec, bfd_byte **ptr)
|
||||
unsigned int compression_header_size;
|
||||
const unsigned int compress_status = sec->compress_status;
|
||||
|
||||
if (abfd->direction != write_direction && sec->rawsize != 0)
|
||||
sz = sec->rawsize;
|
||||
else
|
||||
sz = sec->size;
|
||||
if (sz == 0)
|
||||
{
|
||||
*ptr = NULL;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (p == NULL
|
||||
&& compress_status != COMPRESS_SECTION_DONE
|
||||
&& _bfd_section_size_insane (abfd, sec))
|
||||
{
|
||||
/* PR 24708: Avoid attempts to allocate a ridiculous amount
|
||||
of memory. */
|
||||
_bfd_error_handler
|
||||
/* xgettext:c-format */
|
||||
(_("error: %pB(%pA) is too large (%#" PRIx64 " bytes)"),
|
||||
abfd, sec, (uint64_t) sz);
|
||||
return false;
|
||||
}
|
||||
|
||||
switch (compress_status)
|
||||
{
|
||||
case COMPRESS_SECTION_NONE:
|
||||
if (p == NULL)
|
||||
{
|
||||
ufile_ptr filesize = bfd_get_file_size (abfd);
|
||||
if (filesize > 0
|
||||
&& filesize < sz
|
||||
&& (bfd_section_flags (sec) & SEC_IN_MEMORY) == 0
|
||||
/* PR 24753: Linker created sections can be larger than
|
||||
the file size, eg if they are being used to hold stubs. */
|
||||
&& (bfd_section_flags (sec) & SEC_LINKER_CREATED) == 0
|
||||
/* PR 24753: Sections which have no content should also be
|
||||
excluded as they contain no size on disk. */
|
||||
&& (bfd_section_flags (sec) & SEC_HAS_CONTENTS) != 0
|
||||
/* The MMO file format supports its own special compression
|
||||
technique, but it uses COMPRESS_SECTION_NONE when loading
|
||||
a section's contents. */
|
||||
&& bfd_get_flavour (abfd) != bfd_target_mmo_flavour)
|
||||
{
|
||||
/* PR 24708: Avoid attempts to allocate a ridiculous amount
|
||||
of memory. */
|
||||
bfd_set_error (bfd_error_file_truncated);
|
||||
_bfd_error_handler
|
||||
/* xgettext:c-format */
|
||||
(_("error: %pB(%pA) section size (%#" PRIx64 " bytes) is larger than file size (%#" PRIx64 " bytes)"),
|
||||
abfd, sec, (uint64_t) sz, (uint64_t) filesize);
|
||||
return false;
|
||||
}
|
||||
p = (bfd_byte *) bfd_malloc (sz);
|
||||
if (p == NULL)
|
||||
{
|
||||
|
20
bfd/dwarf2.c
20
bfd/dwarf2.c
@ -690,7 +690,6 @@ read_section (bfd *abfd,
|
||||
{
|
||||
bfd_size_type amt;
|
||||
asection *msec;
|
||||
ufile_ptr filesize;
|
||||
|
||||
msec = bfd_get_section_by_name (abfd, section_name);
|
||||
if (msec == NULL)
|
||||
@ -706,20 +705,14 @@ read_section (bfd *abfd,
|
||||
return false;
|
||||
}
|
||||
|
||||
amt = bfd_get_section_limit_octets (abfd, msec);
|
||||
filesize = bfd_get_file_size (abfd);
|
||||
/* PR 28834: A compressed debug section could well decompress to a size
|
||||
larger than the file, so we choose an arbitrary modifier of 10x in
|
||||
the test below. If this ever turns out to be insufficient, it can
|
||||
be changed by a future update. */
|
||||
if (amt >= filesize * 10)
|
||||
if (_bfd_section_size_insane (abfd, msec))
|
||||
{
|
||||
/* PR 26946 */
|
||||
_bfd_error_handler (_("DWARF error: section %s is larger than 10x its filesize! (0x%lx vs 0x%lx)"),
|
||||
section_name, (long) amt, (long) filesize);
|
||||
bfd_set_error (bfd_error_bad_value);
|
||||
_bfd_error_handler (_("DWARF error: section %s is too big"),
|
||||
section_name);
|
||||
return false;
|
||||
}
|
||||
amt = bfd_get_section_limit_octets (abfd, msec);
|
||||
*section_size = amt;
|
||||
/* Paranoia - alloc one extra so that we can make sure a string
|
||||
section is NUL terminated. */
|
||||
@ -5496,9 +5489,10 @@ _bfd_dwarf2_slurp_debug_info (bfd *abfd, bfd *debug_bfd,
|
||||
msec;
|
||||
msec = find_debug_info (debug_bfd, debug_sections, msec))
|
||||
{
|
||||
if (_bfd_section_size_insane (debug_bfd, msec))
|
||||
return false;
|
||||
/* Catch PR25070 testcase overflowing size calculation here. */
|
||||
if (total_size + msec->size < total_size
|
||||
|| total_size + msec->size < msec->size)
|
||||
if (total_size + msec->size < total_size)
|
||||
{
|
||||
bfd_set_error (bfd_error_no_memory);
|
||||
return false;
|
||||
|
@ -1,6 +1,7 @@
|
||||
/* DO NOT EDIT! -*- buffer-read-only: t -*- This file is automatically
|
||||
generated from "libbfd-in.h", "libbfd.c", "bfdio.c", "bfdwin.c",
|
||||
"cache.c", "reloc.c", "targets.c", "archures.c" and "linker.c".
|
||||
"cache.c", "reloc.c", "section.c", "targets.c", "archures.c"
|
||||
and "linker.c".
|
||||
Run "make headers" in your build bfd/ to regenerate. */
|
||||
|
||||
/* libbfd.h -- Declarations used by bfd library *implementation*.
|
||||
@ -3549,6 +3550,9 @@ bool _bfd_unrecognized_reloc
|
||||
sec_ptr section,
|
||||
unsigned int r_type);
|
||||
|
||||
/* Extracted from section.c. */
|
||||
bool _bfd_section_size_insane (bfd *abfd, asection *sec);
|
||||
|
||||
/* Extracted from targets.c. */
|
||||
const char **_bfd_per_xvec_warn (const bfd_target *);
|
||||
|
||||
|
@ -1703,3 +1703,69 @@ _bfd_nowrite_set_section_contents (bfd *abfd,
|
||||
{
|
||||
return _bfd_bool_bfd_false_error (abfd);
|
||||
}
|
||||
|
||||
/*
|
||||
INTERNAL_FUNCTION
|
||||
_bfd_section_size_insane
|
||||
|
||||
SYNOPSIS
|
||||
bool _bfd_section_size_insane (bfd *abfd, asection *sec);
|
||||
|
||||
DESCRIPTION
|
||||
Returns true if the given section has a size that indicates
|
||||
it cannot be read from file. Return false if the size is OK
|
||||
*or* this function can't say one way or the other.
|
||||
|
||||
*/
|
||||
|
||||
bool
|
||||
_bfd_section_size_insane (bfd *abfd, asection *sec)
|
||||
{
|
||||
bfd_size_type size = bfd_get_section_limit_octets (abfd, sec);
|
||||
if (size == 0)
|
||||
return false;
|
||||
|
||||
if ((bfd_section_flags (sec) & SEC_IN_MEMORY) != 0
|
||||
/* PR 24753: Linker created sections can be larger than
|
||||
the file size, eg if they are being used to hold stubs. */
|
||||
|| (bfd_section_flags (sec) & SEC_LINKER_CREATED) != 0
|
||||
/* PR 24753: Sections which have no content should also be
|
||||
excluded as they contain no size on disk. */
|
||||
|| (bfd_section_flags (sec) & SEC_HAS_CONTENTS) == 0
|
||||
/* The MMO file format supports its own special compression
|
||||
technique, but it uses COMPRESS_SECTION_NONE when loading
|
||||
a section's contents. */
|
||||
|| bfd_get_flavour (abfd) == bfd_target_mmo_flavour)
|
||||
return false;
|
||||
|
||||
ufile_ptr filesize = bfd_get_file_size (abfd);
|
||||
if (filesize == 0)
|
||||
return false;
|
||||
|
||||
if (sec->compress_status == DECOMPRESS_SECTION_ZSTD
|
||||
|| sec->compress_status == DECOMPRESS_SECTION_ZLIB)
|
||||
{
|
||||
/* PR26946, PR28834: Sanity check compress header uncompressed
|
||||
size against the original file size, and check that the
|
||||
compressed section can be read from file. We choose an
|
||||
arbitrary uncompressed size of 10x the file size, rather than
|
||||
a compress ratio. The reason being that compiling
|
||||
"int aaa..a;" with "a" repeated enough times can result in
|
||||
compression ratios without limit for .debug_str, whereas such
|
||||
a file will usually also have the enormous symbol
|
||||
uncompressed in .symtab. */
|
||||
if (size / 10 > filesize)
|
||||
{
|
||||
bfd_set_error (bfd_error_bad_value);
|
||||
return true;
|
||||
}
|
||||
size = sec->compressed_size;
|
||||
}
|
||||
|
||||
if ((ufile_ptr) sec->filepos > filesize || size > filesize - sec->filepos)
|
||||
{
|
||||
bfd_set_error (bfd_error_file_truncated);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user