From c5967f38de59c7375970c09b2c8b8702a01eb9d2 Mon Sep 17 00:00:00 2001 From: Alan Modra Date: Fri, 5 Nov 2021 14:07:56 +1030 Subject: 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. --- bfd/compress.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) (limited to 'bfd') diff --git a/bfd/compress.c b/bfd/compress.c index 4a2ada3..70daf4e 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); -- cgit v1.1