Handle object ID 0 (fixes #99)

This is CVE-2017-9208.

The QPDF library uses object ID 0 internally as a sentinel to
represent a direct object, but prior to this fix, was not blocking
handling of 0 0 obj or 0 0 R as a special case. Creating an object in
the file with 0 0 obj could cause various infinite loops. The PDF spec
doesn't allow for object 0. Having qpdf handle object 0 might be a
better fix, but changing all the places in the code that assumes objid
== 0 means direct would be risky.
This commit is contained in:
Jay Berkenbilt 2017-07-26 04:30:32 -04:00
parent 315092dd98
commit afe0242b26
9 changed files with 116 additions and 1 deletions

View File

@ -1,5 +1,9 @@
2017-07-26 Jay Berkenbilt <ejb@ql.org>
* CVE-2017-9208: Handle references to and appearance of object 0
as a special case. Object 0 is not allowed, and qpdf was using it
internally to represent direct objects.
* CVE-2017-9209: Fix infinite loop caused by attempting to
reconstruct the xref table while already in the process of
reconstructing the xref table.

View File

@ -1350,6 +1350,14 @@ QPDF::readObjectAtOffset(bool try_recovery,
objid = atoi(tobjid.getValue().c_str());
generation = atoi(tgen.getValue().c_str());
if (objid == 0)
{
QTC::TC("qpdf", "QPDF object id 0");
throw QPDFExc(qpdf_e_damaged_pdf, this->file->getName(),
this->last_object_description, offset,
"object with ID 0");
}
if ((exp_objid >= 0) &&
(! ((objid == exp_objid) && (generation == exp_generation))))
{

View File

@ -1089,6 +1089,16 @@ QPDFObjectHandle::parseInternal(PointerHolder<InputSource> input,
QPDFObjectHandle
QPDFObjectHandle::newIndirect(QPDF* qpdf, int objid, int generation)
{
if (objid == 0)
{
// Special case: QPDF uses objid 0 as a sentinel for direct
// objects, and the PDF specification doesn't allow for object
// 0. Treat indirect references to object 0 as null so that we
// never create an indirect object with objid 0.
QTC::TC("qpdf", "QPDFObjectHandle indirect with 0 objid");
return newNull();
}
return QPDFObjectHandle(qpdf, objid, generation);
}

View File

@ -273,3 +273,6 @@ QPDFWriter standard deterministic ID 1
QPDFWriter linearized deterministic ID 1
QPDFWriter deterministic with no data 0
qpdf-c called qpdf_set_deterministic_ID 0
QPDFObjectHandle indirect with 0 objid 0
QPDF object id 0 0
QPDF caught recursive xref reconstruction 0

View File

@ -206,7 +206,7 @@ $td->runtest("remove page we don't have",
show_ntests();
# ----------
$td->notify("--- Miscellaneous Tests ---");
$n_tests += 79;
$n_tests += 81;
$td->runtest("qpdf version",
{$td->COMMAND => "qpdf --version"},
@ -220,6 +220,8 @@ $td->runtest("C API: qpdf version",
# Files to reproduce various bugs
foreach my $d (
["99", "object 0"],
["99b", "object 0"],
["100","xref reconstruction loop"],
["101", "resolve for exception text"],
)

View File

@ -0,0 +1,4 @@
WARNING: issue-99.pdf: file is damaged
WARNING: issue-99.pdf (file position 3526): xref not found
WARNING: issue-99.pdf: Attempting to reconstruct cross-reference table
operation for Dictionary object attempted on object of wrong type

Binary file not shown.

View File

@ -0,0 +1,5 @@
WARNING: issue-99b.pdf: file is damaged
WARNING: issue-99b.pdf (object 1 0, file position 9): object with ID 0
WARNING: issue-99b.pdf: Attempting to reconstruct cross-reference table
WARNING: issue-99b.pdf: object 1 0 not found in file after regenerating cross reference table
operation for Dictionary object attempted on object of wrong type

View File

@ -0,0 +1,79 @@
%PDF-1.3
0 0 obj
<<
/Type /Catalog
/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 612 792]
/Contents 4 0 R
/Resources <<
/ProcSet 5 0 R
/Font <<
/F1 6 0 R
>>
>>
>>
endobj
4 0 obj
<<
/Length 44
>>
stream
BT
/F1 24 Tf
72 720 Td
(Potato) Tj
ET
endstream
endobj
5 0 obj
[
/PDF
/Text
]
endobj
6 0 obj
<<
/Type /Font
/Subtype /Type1
/Name /F1
/BaseFont /Helvetica
/Encoding /WinAnsiEncoding
>>
endobj
xref
0 7
0000000000 65535 f
0000000009 00000 n
0000000063 00000 n
0000000135 00000 n
0000000307 00000 n
0000000403 00000 n
0000000438 00000 n
trailer <<
/Size 7
/Root 1 0 R
>>
startxref
556
%%EOF