Skip to content

Commit b4d6cf6

Browse files
committed
Limit depth of nesting in direct objects (fixes #202)
This fixes CVE-2018-9918.
1 parent f8c8e4d commit b4d6cf6

File tree

7 files changed

+33
-9
lines changed

7 files changed

+33
-9
lines changed

Diff for: ChangeLog

+5
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,8 @@
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+
16
2018-03-06 Jay Berkenbilt <ejb@ql.org>
27

38
* 8.0.2: release

Diff for: libqpdf/QPDFObjectHandle.cc

+20-6
Original file line numberDiff line numberDiff line change
@@ -1487,12 +1487,26 @@ QPDFObjectHandle::parseInternal(PointerHolder<InputSource> input,
14871487

14881488
case QPDFTokenizer::tt_array_open:
14891489
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+
}
14961510
break;
14971511

14981512
case QPDFTokenizer::tt_bool:

Diff for: qpdf/qpdf.testcov

+1
Original file line numberDiff line numberDiff line change
@@ -335,3 +335,4 @@ QPDFObjectHandle numeric non-numeric 0
335335
QPDFObjectHandle erase array bounds 0
336336
qpdf-c called qpdf_check_pdf 0
337337
QPDF xref loop 0
338+
QPDFObjectHandle too deep 0

Diff for: qpdf/qtest/qpdf.test

+1
Original file line numberDiff line numberDiff line change
@@ -236,6 +236,7 @@ my @bug_tests = (
236236
["148", "free memory on bad flate", 2],
237237
["149", "xref prev pointer loop", 3],
238238
["150", "integer overflow", 2],
239+
["202", "even more deeply nested dictionary", 2],
239240
);
240241
$n_tests += scalar(@bug_tests);
241242
foreach my $d (@bug_tests)

Diff for: qpdf/qtest/qpdf/issue-146.out

+1-3
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
11
WARNING: issue-146.pdf: file is damaged
22
WARNING: issue-146.pdf: can't find startxref
33
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
75
issue-146.pdf: unable to find trailer dictionary while recovering damaged file

Diff for: qpdf/qtest/qpdf/issue-202.out

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
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

Diff for: qpdf/qtest/qpdf/issue-202.pdf

321 KB
Binary file not shown.

0 commit comments

Comments
 (0)