CVE-2023-28428: Allocation of Resources Without Limits or Throttling (CWE-770)
value: PDFio is a C library for reading and writing PDF files. In versions 1.1.0 and prior, a denial of service vulnerability exists in the pdfio parser. Crafted pdf files can cause the program to run at 100% utilization and never terminate. This is different from CVE-2023-24808. A patch for this issue is available in version 1.1.1.
CWE description: The product allocates a reusable resource or group of resources on behalf of an actor without imposing any restrictions on the size or number of resources that can be allocated, in violation of the intended security policy for that actor.
CVSS v3 base score: 3.3
Published: 2023-03-20T15:15Z
Repository: https://github.com/michaelrsweet/pdfio
Language: C
Files changed: CHANGES.md, pdfio-stream.c
Commit date: 2023-03-20 09:27:19 -0400
Commit message: Fix potential denial-of-service in flate stream code.

Diff: diff --git a/CHANGES.md b/CHANGES.md
index 2b25bca..620c14a 100644
--- a/CHANGES.md
+++ b/CHANGES.md
@@ -1,12 +1,13 @@
 Changes in PDFio
 ================
 
 
-v1.1.1 (Month DD, YYYY)
+v1.1.1 (March 20, 2023)
 -----------------------
 
+- CVE-2023-NNNNN: Fixed a potential denial-of-service with corrupt PDF files.
 - Fixed a build issue.
 
 
 v1.1.0 (February 6, 2023)
 -------------------------
diff --git a/pdfio-stream.c b/pdfio-stream.c
index 45a21b0..2c6399a 100644
--- a/pdfio-stream.c
+++ b/pdfio-stream.c
@@ -1006,10 +1006,11 @@ static ssize_t				// O - Number of bytes read or `-1` on error
 stream_read(pdfio_stream_t *st,		// I - Stream
             char           *buffer,	// I - Buffer
             size_t         bytes)	// I - Number of bytes to read
 {
   ssize_t	rbytes;			// Bytes read
+  uInt		avail_in, avail_out;	// Previous flate values
 
 
   if (st->filter == PDFIO_FILTER_NONE)
   {
     // No filtering, but limit reads to the length of the stream...
@@ -1058,15 +1059,23 @@ stream_read(pdfio_stream_t *st,		// I - Stream
       }
 
       st->flate.next_out  = (Bytef *)buffer;
       st->flate.avail_out = (uInt)bytes;
 
+      avail_in  = st->flate.avail_in;
+      avail_out = st->flate.avail_out;
+
       if ((status = inflate(&(st->flate), Z_NO_FLUSH)) < Z_OK)
       {
 	_pdfioFileError(st->pdf, "Unable to decompress stream data: %s", zstrerror(status));
 	return (-1);
       }
+      else if (avail_in == st->flate.avail_in && avail_out == st->flate.avail_out)
+      {
+	_pdfioFileError(st->pdf, "Corrupt stream data.");
+	return (-1);
+      }
 
       return (st->flate.next_out - (Bytef *)buffer);
     }
     else if (st->predictor == _PDFIO_PREDICTOR_TIFF2)
     {
@@ -1111,16 +1120,19 @@ stream_read(pdfio_stream_t *st,		// I - Stream
 	  st->remaining      -= (size_t)rbytes;
 	  st->flate.next_in  = (Bytef *)st->cbuffer;
 	  st->flate.avail_in = (uInt)rbytes;
 	}
 
+        avail_in  = st->flate.avail_in;
+        avail_out = st->flate.avail_out;
+
 	if ((status = inflate(&(st->flate), Z_NO_FLUSH)) < Z_OK)
 	{
 	  _pdfioFileError(st->pdf, "Unable to decompress stream data: %s", zstrerror(status));
 	  return (-1);
 	}
-	else if (status == Z_STREAM_END)
+	else if (status == Z_STREAM_END || (avail_in == st->flate.avail_in && avail_out == st->flate.avail_out))
 	  break;
       }
 
       if (st->flate.avail_out > 0)
         return (-1);			// Early end of stream
@@ -1178,16 +1190,19 @@ stream_read(pdfio_stream_t *st,		// I - Stream
 	  st->remaining      -= (size_t)rbytes;
 	  st->flate.next_in  = (Bytef *)st->cbuffer;
 	  st->flate.avail_in = (uInt)rbytes;
 	}
 
+        avail_in  = st->flate.avail_in;
+        avail_out = st->flate.avail_out;
+
 	if ((status = inflate(&(st->flate), Z_NO_FLUSH)) < Z_OK)
 	{
 	  _pdfioFileError(st->pdf, "Unable to decompress stream data: %s", zstrerror(status));
 	  return (-1);
 	}
-	else if (status == Z_STREAM_END)
+	else if (status == Z_STREAM_END || (avail_in == st->flate.avail_in && avail_out == st->flate.avail_out))
 	  break;
       }
 
       if (st->flate.avail_out > 0)
       {

Vulnerable code: v1.1.1 (Month DD, YYYY)
	else if (status == Z_STREAM_END)
	else if (status == Z_STREAM_END)
Fixed code: v1.1.1 (March 20, 2023)
- CVE-2023-NNNNN: Fixed a potential denial-of-service with corrupt PDF files.
  uInt		avail_in, avail_out;	// Previous flate values
      avail_in  = st->flate.avail_in;
      avail_out = st->flate.avail_out;

      else if (avail_in == st->flate.avail_in && avail_out == st->flate.avail_out)
      {
	_pdfioFileError(st->pdf, "Corrupt stream data.");
	return (-1);
      }
        avail_in  = st->flate.avail_in;
        avail_out = st->flate.avail_out;

	else if (status == Z_STREAM_END || (avail_in == st->flate.avail_in && avail_out == st->flate.avail_out))
        avail_in  = st->flate.avail_in;
        avail_out = st->flate.avail_out;

	else if (status == Z_STREAM_END || (avail_in == st->flate.avail_in && avail_out == st->flate.avail_out))