Commit b4d6cf6836ce025ba1811b7bbec52680c7204223

Authored by Jay Berkenbilt
1 parent f8c8e4dc

Limit depth of nesting in direct objects (fixes #202)

This fixes CVE-2018-9918.
ChangeLog
  1 +2018-04-15 Jay Berkenbilt <ejb@ql.org>
  2 +
  3 + * Arbitrarily limit the depth of data structures represented by
  4 + direct object. This is CVE-2018-9918. Fixes #202.
  5 +
1 6 2018-03-06 Jay Berkenbilt <ejb@ql.org>
2 7  
3 8 * 8.0.2: release
... ...
libqpdf/QPDFObjectHandle.cc
... ... @@ -1487,12 +1487,26 @@ QPDFObjectHandle::parseInternal(PointerHolder&lt;InputSource&gt; input,
1487 1487  
1488 1488 case QPDFTokenizer::tt_array_open:
1489 1489 case QPDFTokenizer::tt_dict_open:
1490   - olist_stack.push_back(std::vector<QPDFObjectHandle>());
1491   - state = st_start;
1492   - offset_stack.push_back(input->tell());
1493   - state_stack.push_back(
1494   - (token.getType() == QPDFTokenizer::tt_array_open) ?
1495   - st_array : st_dictionary);
  1490 + if (olist_stack.size() > 500)
  1491 + {
  1492 + QTC::TC("qpdf", "QPDFObjectHandle too deep");
  1493 + warn(context,
  1494 + QPDFExc(qpdf_e_damaged_pdf, input->getName(),
  1495 + object_description,
  1496 + input->getLastOffset(),
  1497 + "ignoring excessively deeply nested data structure"));
  1498 + object = newNull();
  1499 + state = st_top;
  1500 + }
  1501 + else
  1502 + {
  1503 + olist_stack.push_back(std::vector<QPDFObjectHandle>());
  1504 + state = st_start;
  1505 + offset_stack.push_back(input->tell());
  1506 + state_stack.push_back(
  1507 + (token.getType() == QPDFTokenizer::tt_array_open) ?
  1508 + st_array : st_dictionary);
  1509 + }
1496 1510 break;
1497 1511  
1498 1512 case QPDFTokenizer::tt_bool:
... ...
qpdf/qpdf.testcov
... ... @@ -335,3 +335,4 @@ QPDFObjectHandle numeric non-numeric 0
335 335 QPDFObjectHandle erase array bounds 0
336 336 qpdf-c called qpdf_check_pdf 0
337 337 QPDF xref loop 0
  338 +QPDFObjectHandle too deep 0
... ...
qpdf/qtest/qpdf.test
... ... @@ -236,6 +236,7 @@ my @bug_tests = (
236 236 ["148", "free memory on bad flate", 2],
237 237 ["149", "xref prev pointer loop", 3],
238 238 ["150", "integer overflow", 2],
  239 + ["202", "even more deeply nested dictionary", 2],
239 240 );
240 241 $n_tests += scalar(@bug_tests);
241 242 foreach my $d (@bug_tests)
... ...
qpdf/qtest/qpdf/issue-146.out
1 1 WARNING: issue-146.pdf: file is damaged
2 2 WARNING: issue-146.pdf: can't find startxref
3 3 WARNING: issue-146.pdf: Attempting to reconstruct cross-reference table
4   -WARNING: issue-146.pdf (trailer, offset 20728): unknown token while reading object; treating as string
5   -WARNING: issue-146.pdf (trailer, offset 20732): unexpected EOF
6   -WARNING: issue-146.pdf (trailer, offset 20732): parse error while reading object
  4 +WARNING: issue-146.pdf (trailer, offset 695): ignoring excessively deeply nested data structure
7 5 issue-146.pdf: unable to find trailer dictionary while recovering damaged file
... ...
qpdf/qtest/qpdf/issue-202.out 0 → 100644
  1 +WARNING: issue-202.pdf (trailer, offset 55770): ignoring excessively deeply nested data structure
  2 +WARNING: issue-202.pdf: file is damaged
  3 +WARNING: issue-202.pdf (offset 54769): expected trailer dictionary
  4 +WARNING: issue-202.pdf: Attempting to reconstruct cross-reference table
  5 +issue-202.pdf: unable to find trailer dictionary while recovering damaged file
... ...
qpdf/qtest/qpdf/issue-202.pdf 0 → 100644
No preview for this file type