mirror of
https://github.com/qpdf/qpdf.git
synced 2024-06-04 03:10:52 +00:00
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:
parent
315092dd98
commit
afe0242b26
|
@ -1,5 +1,9 @@
|
||||||
2017-07-26 Jay Berkenbilt <ejb@ql.org>
|
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
|
* CVE-2017-9209: Fix infinite loop caused by attempting to
|
||||||
reconstruct the xref table while already in the process of
|
reconstruct the xref table while already in the process of
|
||||||
reconstructing the xref table.
|
reconstructing the xref table.
|
||||||
|
|
|
@ -1350,6 +1350,14 @@ QPDF::readObjectAtOffset(bool try_recovery,
|
||||||
objid = atoi(tobjid.getValue().c_str());
|
objid = atoi(tobjid.getValue().c_str());
|
||||||
generation = atoi(tgen.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) &&
|
if ((exp_objid >= 0) &&
|
||||||
(! ((objid == exp_objid) && (generation == exp_generation))))
|
(! ((objid == exp_objid) && (generation == exp_generation))))
|
||||||
{
|
{
|
||||||
|
|
|
@ -1089,6 +1089,16 @@ QPDFObjectHandle::parseInternal(PointerHolder<InputSource> input,
|
||||||
QPDFObjectHandle
|
QPDFObjectHandle
|
||||||
QPDFObjectHandle::newIndirect(QPDF* qpdf, int objid, int generation)
|
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);
|
return QPDFObjectHandle(qpdf, objid, generation);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -273,3 +273,6 @@ QPDFWriter standard deterministic ID 1
|
||||||
QPDFWriter linearized deterministic ID 1
|
QPDFWriter linearized deterministic ID 1
|
||||||
QPDFWriter deterministic with no data 0
|
QPDFWriter deterministic with no data 0
|
||||||
qpdf-c called qpdf_set_deterministic_ID 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
|
||||||
|
|
|
@ -206,7 +206,7 @@ $td->runtest("remove page we don't have",
|
||||||
show_ntests();
|
show_ntests();
|
||||||
# ----------
|
# ----------
|
||||||
$td->notify("--- Miscellaneous Tests ---");
|
$td->notify("--- Miscellaneous Tests ---");
|
||||||
$n_tests += 79;
|
$n_tests += 81;
|
||||||
|
|
||||||
$td->runtest("qpdf version",
|
$td->runtest("qpdf version",
|
||||||
{$td->COMMAND => "qpdf --version"},
|
{$td->COMMAND => "qpdf --version"},
|
||||||
|
@ -220,6 +220,8 @@ $td->runtest("C API: qpdf version",
|
||||||
|
|
||||||
# Files to reproduce various bugs
|
# Files to reproduce various bugs
|
||||||
foreach my $d (
|
foreach my $d (
|
||||||
|
["99", "object 0"],
|
||||||
|
["99b", "object 0"],
|
||||||
["100","xref reconstruction loop"],
|
["100","xref reconstruction loop"],
|
||||||
["101", "resolve for exception text"],
|
["101", "resolve for exception text"],
|
||||||
)
|
)
|
||||||
|
|
4
qpdf/qtest/qpdf/issue-99.out
Normal file
4
qpdf/qtest/qpdf/issue-99.out
Normal 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
|
BIN
qpdf/qtest/qpdf/issue-99.pdf
Normal file
BIN
qpdf/qtest/qpdf/issue-99.pdf
Normal file
Binary file not shown.
5
qpdf/qtest/qpdf/issue-99b.out
Normal file
5
qpdf/qtest/qpdf/issue-99b.out
Normal 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
|
79
qpdf/qtest/qpdf/issue-99b.pdf
Normal file
79
qpdf/qtest/qpdf/issue-99b.pdf
Normal 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
|
Loading…
Reference in New Issue
Block a user