summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJay Berkenbilt <ejb@ql.org>2015-02-21 23:40:41 +0100
committerJay Berkenbilt <ejb@ql.org>2015-02-21 23:51:08 +0100
commitc729e07d55c870e7e08f158f0a80a3d452c59cdc (patch)
tree2130876f9bf7f6ec45cc6bcaec75c921976ab317
parentd8900c2255d12adbe9342ea751403740ca7a826d (diff)
downloadqpdf-c729e07d55c870e7e08f158f0a80a3d452c59cdc.tar.zst
Avoid resolving arguments to R
When checking two objects preceding R while parsing, ensure that the objects are direct. This avoids stuff like 1 0 obj containing 1 0 R 0 R from causing an infinite loop in object resolution.
-rw-r--r--ChangeLog8
-rw-r--r--libqpdf/QPDFObjectHandle.cc2
-rw-r--r--qpdf/qtest/qpdf.test6
-rw-r--r--qpdf/qtest/qpdf/indirect-r-arg.out1
-rw-r--r--qpdf/qtest/qpdf/indirect-r-arg.pdf102
5 files changed, 118 insertions, 1 deletions
diff --git a/ChangeLog b/ChangeLog
index 72cef333..c049bc3b 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,11 @@
+2015-02-21 Jay Berkenbilt <ejb@ql.org>
+
+ * Ensure that arguments to "R" when parsing the file are direct
+ objects before trying to resolve them. This prevents specially
+ crafted files from causing qpdf to crash with a stack overflow.
+ Thanks to Gynvael Coldwind and Mateusz Jurczyk of the Google
+ Security Team for providing a sample file with this problem.
+
2014-12-01 Jay Berkenbilt <ejb@ql.org>
* Some broken PDF files lack the required /Type key for /Page and
diff --git a/libqpdf/QPDFObjectHandle.cc b/libqpdf/QPDFObjectHandle.cc
index eec4fae3..64a4e3c3 100644
--- a/libqpdf/QPDFObjectHandle.cc
+++ b/libqpdf/QPDFObjectHandle.cc
@@ -966,7 +966,9 @@ QPDFObjectHandle::parseInternal(PointerHolder<InputSource> input,
std::string const& value = token.getValue();
if ((value == "R") && (in_array || in_dictionary) &&
(olist.size() >= 2) &&
+ (! olist.at(olist.size() - 1).isIndirect()) &&
(olist.at(olist.size() - 1).isInteger()) &&
+ (! olist.at(olist.size() - 2).isIndirect()) &&
(olist.at(olist.size() - 2).isInteger()))
{
if (context == 0)
diff --git a/qpdf/qtest/qpdf.test b/qpdf/qtest/qpdf.test
index 3bd1a2fa..75726ca4 100644
--- a/qpdf/qtest/qpdf.test
+++ b/qpdf/qtest/qpdf.test
@@ -199,7 +199,7 @@ $td->runtest("remove page we don't have",
show_ntests();
# ----------
$td->notify("--- Miscellaneous Tests ---");
-$n_tests += 74;
+$n_tests += 75;
$td->runtest("qpdf version",
{$td->COMMAND => "qpdf --version"},
@@ -562,6 +562,10 @@ $td->runtest("no type key for page nodes",
{$td->COMMAND => "qpdf --check no-pages-types.pdf"},
{$td->FILE => "no-pages-types.out", $td->EXIT_STATUS => 0},
$td->NORMALIZE_NEWLINES);
+$td->runtest("ensure arguments to R are direct",
+ {$td->COMMAND => "qpdf --check indirect-r-arg.pdf"},
+ {$td->FILE => "indirect-r-arg.out", $td->EXIT_STATUS => 2},
+ $td->NORMALIZE_NEWLINES);
show_ntests();
# ----------
diff --git a/qpdf/qtest/qpdf/indirect-r-arg.out b/qpdf/qtest/qpdf/indirect-r-arg.out
new file mode 100644
index 00000000..e065ec16
--- /dev/null
+++ b/qpdf/qtest/qpdf/indirect-r-arg.out
@@ -0,0 +1 @@
+indirect-r-arg.pdf (file position 76): unknown token while reading object (R)
diff --git a/qpdf/qtest/qpdf/indirect-r-arg.pdf b/qpdf/qtest/qpdf/indirect-r-arg.pdf
new file mode 100644
index 00000000..2a6d18e2
--- /dev/null
+++ b/qpdf/qtest/qpdf/indirect-r-arg.pdf
@@ -0,0 +1,102 @@
+%PDF-1.3
+%¿÷¢þ
+%QDF-1.0
+
+%% Original object ID: 1 0
+1 0 obj
+<<
+ /X 1 0 R 0 R
+ /Pages 2 0 R
+ /Type /Catalog
+>>
+endobj
+
+%% Original object ID: 2 0
+2 0 obj
+<<
+ /Count 1
+ /Kids [
+ 3 0 R
+ ]
+ /Type /Pages
+>>
+endobj
+
+%% Page 1
+%% Original object ID: 3 0
+3 0 obj
+<<
+ /Contents 4 0 R
+ /MediaBox [
+ 0
+ 0
+ 612
+ 792
+ ]
+ /Parent 2 0 R
+ /Resources <<
+ /Font <<
+ /F1 6 0 R
+ >>
+ /ProcSet 7 0 R
+ >>
+ /Type /Page
+>>
+endobj
+
+%% Contents for page 1
+%% Original object ID: 4 0
+4 0 obj
+<<
+ /Length 5 0 R
+>>
+stream
+BT
+ /F1 24 Tf
+ 72 720 Td
+ (Potato) Tj
+ET
+endstream
+endobj
+
+5 0 obj
+44
+endobj
+
+%% Original object ID: 6 0
+6 0 obj
+<<
+ /BaseFont /Helvetica
+ /Encoding /WinAnsiEncoding
+ /Name /F1
+ /Subtype /Type1
+ /Type /Font
+>>
+endobj
+
+%% Original object ID: 5 0
+7 0 obj
+[
+ /PDF
+ /Text
+]
+endobj
+
+xref
+0 8
+0000000000 65535 f
+0000000052 00000 n
+0000000148 00000 n
+0000000257 00000 n
+0000000499 00000 n
+0000000598 00000 n
+0000000644 00000 n
+0000000789 00000 n
+trailer <<
+ /Root 1 0 R
+ /Size 8
+ /ID [<9e2756c6254602d0b896148e97ee7414><9e2756c6254602d0b896148e97ee7414>]
+>>
+startxref
+824
+%%EOF