CVE-2017-18183 (published 2018-02-13T19:29Z)

An issue was discovered in QPDF before 7.0.0. There is an infinite loop in the QPDFWriter::enqueueObject() function in libqpdf/QPDFWriter.cc.

Severity: MEDIUM
CVSS v2 base score: 4.3 (AV:N/AC:M/Au:N/C:N/I:N/A:P)
CVSS v3 base score: 5.5, MEDIUM (CVSS:3.0/AV:L/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/qpdf/qpdf
commit_details: repo_url: https://github.com/qpdf/qpdf
author: Jay Berkenbilt
author_date: 2017-08-12 07:35:04-04:00
msg: Fix infinite loop in QPDFWriter (fixes #143)
repository: repo_url: https://github.com/qpdf/qpdf
repo_name: qpdf/qpdf
description: qpdf: A content-preserving PDF document transformer
repo_language: C++
owner: qpdf
file_changes: filename: QPDFWriter.cc
change_type: ModificationType.MODIFY
diff: @@ -1054,6 +1054,9 @@ QPDFWriter::enqueueObject(QPDFObjectHandle object)
 		// here.  Instead, enqueue the object stream.  Object
 		// streams always have generation 0.
 		int stream_id = this->object_to_object_stream[og];
+                // Detect loops by storing invalid object ID 0, which
+                // will get overwritten later.
+                obj_renumber[og] = 0;
 		enqueueObject(this->pdf.getObjectByID(stream_id, 0));
 	    }
 	    else
@@ -1079,6 +1082,12 @@ QPDFWriter::enqueueObject(QPDFObjectHandle object)
 		}
 	    }
 	}
+        else if (obj_renumber[og] == 0)
+        {
+            // This can happen if a specially constructed file
+            // indicates that an object stream is inside itself.
+            QTC::TC("qpdf", "QPDFWriter ignore self-referential object stream");
+        }
     }
     else if (object.isArray())
     {

programming_language: C++
filename: qpdf.testcov
change_type: ModificationType.MODIFY
diff: @@ -294,3 +294,4 @@ QPDF ignore first extra space in xref entry 0
 QPDF ignore second extra space in xref entry 0
 QPDF ignore length error xref entry 0
 QPDF_encryption pad short parameter 0
+QPDFWriter ignore self-referential object stream 0

programming_language: Markdown
filename: qpdf.test
change_type: ModificationType.MODIFY
diff: @@ -220,6 +220,7 @@ my @bug_tests = (
     ["106", "zlib data error", 3],
     ["141a", "/W entry size 0", 2],
     ["141b", "/W entry size 0", 2],
+    ["143", "self-referential ostream", 3],
     );
 $n_tests += scalar(@bug_tests);
 foreach my $d (@bug_tests)

programming_language: Perl
filename: issue-143.out
change_type: ModificationType.ADD
diff: @@ -0,0 +1,19 @@
+WARNING: issue-143.pdf: can't find PDF header
+WARNING: issue-143.pdf (xref stream: object 3 0, file position 654): stream keyword not followed by proper line terminator
+WARNING: issue-143.pdf (xref stream: object 3 0, file position 607): stream dictionary lacks /Length key
+WARNING: issue-143.pdf (xref stream: object 3 0, file position 654): attempting to recover stream length
+WARNING: issue-143.pdf (xref stream: object 3 0, file position 654): recovered stream length: 36
+WARNING: issue-143.pdf (xref stream: object 3 0, file position 694): expected endobj
+WARNING: issue-143.pdf: file is damaged
+WARNING: issue-143.pdf (object 1 0, file position 48): expected n n obj
+WARNING: issue-143.pdf: Attempting to reconstruct cross-reference table
+WARNING: issue-143.pdf (file position 24): expected dictionary key but found non-name object; inserting key /QPDFFake1
+WARNING: issue-143.pdf (file position 24): expected dictionary key but found non-name object; inserting key /QPDFFake2
+WARNING: issue-143.pdf (file position 24): expected dictionary key but found non-name object; inserting key /QPDFFake3
+WARNING: issue-143.pdf (file position 24): expected dictionary key but found non-name object; inserting key /QPDFFake4
+WARNING: issue-143.pdf (object 1 0, file position 21): stream dictionary lacks /Length key
+WARNING: issue-143.pdf (object 1 0, file position 84): attempting to recover stream length
+WARNING: issue-143.pdf (object 1 0, file position 84): recovered stream length: 606
+WARNING: issue-143.pdf (object 1 0, file position 694): expected endobj
+WARNING: object stream 1 (file position 33): expected dictionary key but found non-name object; inserting key /QPDFFake1
+qpdf: operation succeeded with warnings; resulting file may have some problems

programming_language: Markdown