From: Alan Modra Date: Fri, 5 Nov 2021 03:37:56 +0000 (+1030) Subject: PR28530, Hang in objdump on machine with 196GB RAM X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=c5967f38de59c7375970c09b2c8b8702a01eb9d2;p=binutils-gdb.git PR28530, Hang in objdump on machine with 196GB RAM Investigating the PR28530 testcase, which has a fuzzed compression header with an enormous size, I noticed that decompress_contents is broken when the size doesn't fit in strm.avail_out. It wouldn't be too hard to support larger sizes (patches welcome!) but for now just stop decompress_contents from returning rubbish. PR 28530 * compress.c (decompress_contents): Fail when uncompressed_size is too big. (bfd_init_section_decompress_status): Likewise. --- diff --git a/bfd/compress.c b/bfd/compress.c index 4a2ada3e3eb..70daf4ed3a5 100644 --- a/bfd/compress.c +++ b/bfd/compress.c @@ -46,6 +46,11 @@ decompress_contents (bfd_byte *compressed_buffer, strm.avail_in = compressed_size; strm.next_in = (Bytef*) compressed_buffer; strm.avail_out = uncompressed_size; + /* FIXME: strm.avail_in and strm.avail_out are typically unsigned + int. Supporting sizes that don't fit in an unsigned int is + possible but will require some rewriting of this function. */ + if (strm.avail_in != compressed_size || strm.avail_out != uncompressed_size) + return false; BFD_ASSERT (Z_OK == 0); rc = inflateInit (&strm); @@ -516,6 +521,7 @@ bfd_init_section_decompress_status (bfd *abfd, sec_ptr sec) int header_size; bfd_size_type uncompressed_size; unsigned int uncompressed_alignment_power = 0; + z_stream strm; compression_header_size = bfd_get_compression_header_size (abfd, sec); if (compression_header_size > MAX_COMPRESSION_HEADER_SIZE) @@ -551,6 +557,15 @@ bfd_init_section_decompress_status (bfd *abfd, sec_ptr sec) return false; } + /* PR28530, reject sizes unsupported by decompress_contents. */ + strm.avail_in = sec->size; + strm.avail_out = uncompressed_size; + if (strm.avail_in != sec->size || strm.avail_out != uncompressed_size) + { + bfd_set_error (bfd_error_nonrepresentable_section); + return false; + } + sec->compressed_size = sec->size; sec->size = uncompressed_size; bfd_set_section_alignment (sec, uncompressed_alignment_power);