CVE-2023-24808 (published 2023-02-07T01:15Z)

 PDFio is a C library for reading and writing PDF files. In versions prior to 1.1.0 a denial of service (DOS) vulnerability exists in the pdfio parser. Crafted pdf files can cause the program to run at 100% utilization and never terminate. The pdf which causes this crash found in testing is about 28kb in size and was discovered via fuzzing. Anyone who uses this library either as a standalone binary or as a library can be DOSed when attempting to parse this type of file. Web servers or other automated processes which rely on this code to turn pdf submissions into plaintext can be DOSed when an attacker uploads the pdf. Please see the linked GHSA for an example pdf. Users are advised to upgrade. There are no known workarounds for this vulnerability.

CVSS v3 base score: 6.5, MEDIUM (CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:N/I:N/A:H)

Weakness information:
cwe_id: CWE-835
cwe_name: Loop with Unreachable Exit Condition ('Infinite Loop')
description: The product contains an iteration or loop with an exit condition that cannot be reached, i.e., an infinite loop.
extended_description: If the loop can be influenced by an attacker, this weakness could allow attackers to consume excessive resources such as CPU or memory.
         

Fix information:
repo_url: https://github.com/michaelrsweet/pdfio
commit_details: repo_url: https://github.com/michaelrsweet/pdfio
author: Michael R Sweet
author_date: 2023-02-03 20:39:04-05:00
msg: Fix denial-of-service attack when reading corrupt PDF files.
repository: repo_url: https://github.com/michaelrsweet/pdfio
repo_name: michaelrsweet/pdfio
description: PDFio is a simple C library for reading and writing PDF files.
repo_language: C
owner: michaelrsweet
file_changes: filename: CHANGES.md
change_type: ModificationType.MODIFY
diff: @@ -2,9 +2,10 @@ Changes in PDFio
 ================
 
 
-v1.1.0 (Month DD, YYYY)
------------------------
+v1.1.0 (February 3, 2023)
+-------------------------
 
+- CVE-2023-nnnn: Fixed a potential denial-of-service with corrupt PDF files.
 - Added `pdfioFileCreateTemporary` function (Issue #29)
 - Added `pdfioDictIterateKeys` function (Issue #31)
 - Added `pdfioContentPathEnd` function.

programming_language: Markdown
filename: Makefile
change_type: ModificationType.MODIFY
diff: @@ -1,7 +1,7 @@
 #
 # Makefile for PDFio.
 #
-# Copyright © 2021-2022 by Michael R Sweet.
+# Copyright © 2021-2023 by Michael R Sweet.
 #
 # Licensed under Apache License v2.0.  See the file "LICENSE" for more
 # information.
@@ -29,7 +29,7 @@ DSONAME		=
 LDFLAGS		=
 LIBS		=	-lm -lz
 RANLIB		=	ranlib
-VERSION		=	1.1
+VERSION		=	1.1.0
 prefix		=	/usr/local
 
 

programming_language: Shell
filename: NOTICE
change_type: ModificationType.MODIFY
diff: @@ -1,6 +1,6 @@
 PDFio - PDF Read/Write Library
 
-Copyright © 2021-2022 by Michael R Sweet.
+Copyright © 2021-2023 by Michael R Sweet.
 
 (Optional) Exceptions to the Apache 2.0 License:
 ================================================

programming_language: Markdown
filename: pdfio-common.c
change_type: ModificationType.MODIFY
diff: @@ -1,7 +1,7 @@
 //
 // Common support functions for pdfio.
 //
-// Copyright © 2021 by Michael R Sweet.
+// Copyright © 2021-2023 by Michael R Sweet.
 //
 // Licensed under Apache License v2.0.  See the file "LICENSE" for more
 // information.
@@ -38,6 +38,8 @@ _pdfioFileConsume(pdfio_file_t *pdf,	// I - PDF file
   else if (_pdfioFileSeek(pdf, (off_t)bytes, SEEK_CUR) < 0)
     return (false);
 
+  PDFIO_DEBUG("_pdfioFileConsume: pos=%ld\n", (long)(pdf->bufpos + pdf->bufptr - pdf->buffer));
+
   return (true);
 }
 
@@ -525,7 +527,7 @@ read_buffer(pdfio_file_t *pdf,		// I - PDF file
   return (rbytes);
 }
 
-  
+
 //
 // 'write_buffer()' - Write a buffer to a PDF file.
 //

programming_language: C
filename: pdfio-dict.c
change_type: ModificationType.MODIFY
diff: @@ -1,7 +1,7 @@
 //
 // PDF dictionary functions for PDFio.
 //
-// Copyright © 2021-2022 by Michael R Sweet.
+// Copyright © 2021-2023 by Michael R Sweet.
 //
 // Licensed under Apache License v2.0.  See the file "LICENSE" for more
 // information.
@@ -541,8 +541,15 @@ _pdfioDictRead(pdfio_file_t   *pdf,	// I - PDF file
       _pdfioFileError(pdf, "Invalid dictionary contents.");
       break;
     }
+    else if (_pdfioDictGetValue(dict, key + 1))
+    {
+      _pdfioFileError(pdf, "Duplicate dictionary key '%s'.", key + 1);
+      return (NULL);
+    }
 
     // Then get the next value...
+    PDFIO_DEBUG("_pdfioDictRead: Reading value for '%s'.\n", key + 1);
+
     if (!_pdfioValueRead(pdf, obj, tb, &value, depth))
     {
       _pdfioFileError(pdf, "Missing value for dictionary key.");
@@ -932,9 +939,9 @@ _pdfioDictSetValue(
 
 #ifdef DEBUG
   PDFIO_DEBUG("_pdfioDictSetValue(%p): %lu pairs\n", (void *)dict, (unsigned long)dict->num_pairs);
-  PDFIO_DEBUG("_pdfioDictSetValue(%p): ", (void *)dict);
-  PDFIO_DEBUG_DICT(dict);
-  PDFIO_DEBUG("\n");
+//  PDFIO_DEBUG("_pdfioDictSetValue(%p): ", (void *)dict);
+//  PDFIO_DEBUG_DICT(dict);
+//  PDFIO_DEBUG("\n");
 #endif // DEBUG
 
   return (true);

programming_language: C
filename: pdfio-file.c
change_type: ModificationType.MODIFY
diff: @@ -1,7 +1,7 @@
 //
 // PDF file functions for PDFio.
 //
-// Copyright © 2021-2022 by Michael R Sweet.
+// Copyright © 2021-2023 by Michael R Sweet.
 //
 // Licensed under Apache License v2.0.  See the file "LICENSE" for more
 // information.
@@ -1984,6 +1984,8 @@ load_xref(
 	return (false);
       }
 
+      PDFIO_DEBUG("load_xref: Got trailer dict.\n");
+
       _pdfioTokenFlush(&tb);
 
       if (!pdf->trailer_dict)

programming_language: C
filename: pdfio-object.c
change_type: ModificationType.MODIFY
diff: @@ -1,7 +1,7 @@
 //
 // PDF object functions for PDFio.
 //
-// Copyright © 2021-2022 by Michael R Sweet.
+// Copyright © 2021-2023 by Michael R Sweet.
 //
 // Licensed under Apache License v2.0.  See the file "LICENSE" for more
 // information.

programming_language: Objective-C
filename: pdfio-token.c
change_type: ModificationType.MODIFY
diff: @@ -1,7 +1,7 @@
 //
 // PDF token parsing functions for PDFio.
 //
-// Copyright © 2021 by Michael R Sweet.
+// Copyright © 2021-2023 by Michael R Sweet.
 //
 // Licensed under Apache License v2.0.  See the file "LICENSE" for more
 // information.
@@ -129,9 +129,20 @@ _pdfioTokenGet(_pdfio_token_t *tb,	// I - Token buffer/stack
   if (tb->num_tokens > 0)
   {
     // Yes, return it...
+    size_t len;				// Length of token
+
     tb->num_tokens --;
-    strncpy(buffer, tb->tokens[tb->num_tokens], bufsize - 1);
-    buffer[bufsize - 1] = '\0';
+
+    if ((len = strlen(tb->tokens[tb->num_tokens])) > (bufsize - 1))
+    {
+      // Value too large...
+      PDFIO_DEBUG("_pdfioTokenGet(tb=%p, buffer=%p, bufsize=%u): Token '%s' from stack too large.\n", tb, buffer, (unsigned)bufsize, tb->tokens[tb->num_tokens]);
+      *buffer = '\0';
+      return (false);
+    }
+
+    memcpy(buffer, tb->tokens[tb->num_tokens], len);
+    buffer[len] = '\0';
 
     PDFIO_DEBUG("_pdfioTokenGet(tb=%p, buffer=%p, bufsize=%u): Popping '%s' from stack.\n", tb, buffer, (unsigned)bufsize, buffer);
 
@@ -536,7 +547,7 @@ _pdfioTokenRead(_pdfio_token_t *tb,	// I - Token buffer/stack
 
   *bufptr = '\0';
 
-  PDFIO_DEBUG("_pdfioTokenRead: Read '%s'.\n", buffer);
+//  PDFIO_DEBUG("_pdfioTokenRead: Read '%s'.\n", buffer);
 
   return (bufptr > buffer);
 }
@@ -573,6 +584,7 @@ get_char(_pdfio_token_t *tb)		// I - Token buffer
     tb->bufptr = tb->buffer;
     tb->bufend = tb->buffer + bytes;
 
+#if 0
 #ifdef DEBUG
     unsigned char *ptr;			// Pointer into buffer
 
@@ -586,6 +598,7 @@ get_char(_pdfio_token_t *tb)		// I - Token buffer
     }
     PDFIO_DEBUG("'\n");
 #endif // DEBUG
+#endif // 0
   }
 
   // Return the next character...

programming_language: C
filename: pdfio-value.c
change_type: ModificationType.MODIFY
diff: @@ -1,7 +1,7 @@
 //
 // PDF value functions for PDFio.
 //
-// Copyright © 2021 by Michael R Sweet.
+// Copyright © 2021-2023 by Michael R Sweet.
 //
 // Licensed under Apache License v2.0.  See the file "LICENSE" for more
 // information.

programming_language: C