PR28530, Hang in objdump on machine with 196GB RAM

Message ID YYSq+gDzuFdpRsYQ@squeak.grove.modra.org
State New
Headers show
Series
  • PR28530, Hang in objdump on machine with 196GB RAM
Related show

Commit Message

Mike Frysinger via Binutils Nov. 5, 2021, 3:54 a.m.
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.


-- 
Alan Modra
Australia Development Lab, IBM

Patch

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);