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

An issue was discovered in QPDF before 7.0.0. There is an infinite loop due to looping xref tables in QPDF.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-25 19:58:31-04:00
msg: Detect xref pointer infinite loop (fixes #149)
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: ChangeLog
change_type: ModificationType.MODIFY
diff: @@ -1,3 +1,8 @@
+2017-08-25  Jay Berkenbilt  <ejb@ql.org>
+
+	* Detect infinite loop while finding additional xref tables. Fixes
+	#149.
+
 2017-08-22  Jay Berkenbilt  <ejb@ql.org>
 
 	* 7.0.b1: release

programming_language: Markdown
filename: QPDF.cc
change_type: ModificationType.MODIFY
diff: @@ -491,8 +491,10 @@ void
 QPDF::read_xref(qpdf_offset_t xref_offset)
 {
     std::map<int, int> free_table;
+    std::set<qpdf_offset_t> visited;
     while (xref_offset)
     {
+        visited.insert(xref_offset);
         char buf[7];
         memset(buf, 0, sizeof(buf));
 	this->m->file->seek(xref_offset, SEEK_SET);
@@ -520,6 +522,10 @@ QPDF::read_xref(qpdf_offset_t xref_offset)
 	{
 	    xref_offset = read_xrefStream(xref_offset);
 	}
+        if (visited.count(xref_offset) != 0)
+        {
+            xref_offset = 0;
+        }
     }
 
     if (! this->m->trailer.isInitialized())

programming_language: C++
filename: qpdf.test
change_type: ModificationType.MODIFY
diff: @@ -221,6 +221,7 @@ my @bug_tests = (
     ["141a", "/W entry size 0", 2],
     ["141b", "/W entry size 0", 2],
     ["143", "self-referential ostream", 3],
+    ["149", "xref prev pointer loop", 3],
     );
 $n_tests += scalar(@bug_tests);
 foreach my $d (@bug_tests)

programming_language: Perl
filename: issue-149.out
change_type: ModificationType.ADD
diff: @@ -0,0 +1,2 @@
+WARNING: issue-149.pdf: reported number of objects (11) inconsistent with actual number of objects (7)
+qpdf: operation succeeded with warnings; resulting file may have some problems

programming_language: Markdown
filename: issue-149.pdf
change_type: ModificationType.ADD
diff: @@ -0,0 +1,120 @@
+%PDF-1.7
+%Á∑·∂
+% vim: set tw=76 ts=2 et :
+% convert with:
+% ./fixlengths < hello.txt > hello.pdf ; ./genxref hello.pdf
+1 0 obj
+  <<  /Type /Catalog
+      /Outlines 6 0 R
+      /Pages 2 0 R
+  >>
+endobj
+
+2 0 obj
+  <<  /Type /Pages
+      /Kids [3 0 R]
+      /Count 1
+  >>
+endobj
+
+3 0 obj
+  <<  /Type /Page
+      /Parent 2 0 R
+      /MediaBox [0 0 595.276 841.89]
+      /Contents 4 0 R
+      /Resources <<
+        /ProcSet [/PDF /Text]
+        /Font << /F1 5 0 R >>
+        >>
+  >>
+endobj
+
+4 0 obj
+  <<  /Length 36  >>
+stream
+  BT 80 100 Td /F1 48 Tf (foo) Tj ET
+endstream
+endobj
+
+5 0 obj
+  <<  /Type /Font
+      /Subtype /Type1
+      /Name /F1
+      /BaseFont /Helvetica
+      /Encoding /MacRomanEncoding
+  >>
+endobj
+
+6 0 obj
+  <<  /Type /Outlines
+      /Count 0
+  >>
+endobj
+
+xref
+0 7
+0000000000 65535 f
+0000000125 00000 n
+0000000208 00000 n
+0000000283 00000 n
+0000000492 00000 n
+0000000583 00000 n
+0000000721 00000 n
+
+trailer
+  <<  /Size 7
+      /Prev 1516
+      /Root 1 0 R
+  >>
+startxref
+779%%EOF
+
+% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+1 1 obj
+  <<  /Type /Catalog
+      /Outlines 6 0 R
+      /Pages 2 1 R
+  >>
+endobj
+
+2 1 obj
+  <<  /Type /Pages
+      /Kids [3 1 R]
+      /Count 1
+  >>
+endobj
+
+3 1 obj
+  <<  /Type /Page
+      /Parent 2 1 R
+      /MediaBox [0 0 595.276 841.89]
+      /Contents 4 1 R
+      /Resources <<
+        /ProcSet [/PDF /Text]
+        /Font << /F1 5 0 R >>
+        >>
+  >>
+endobj
+
+4 1 obj
+  <<  /Length 36  >>
+stream
+  BT 80 100 Td /F1 48 Tf (bar) Tj ET
+endstream
+endobj
+
+xref
+1 4
+0000001058 00001 n
+0000001141 00001 n
+0000001216 00001 n
+0000001425 00001 n
+
+trailer
+  <<  /Size 11
+      /Prev 779
+      /Root 1 1 R
+  >>
+startxref
+1516
+%%EOF

programming_language: Shell