Commit 4a8c821e3efc961d9c58631bcbbc9125167e41a4
1 parent
e62973d2
In QPDF::reconstruct_xref add sanity check for object ids
Showing
2 changed files
with
12 additions
and
5 deletions
libqpdf/QPDF.cc
| ... | ... | @@ -473,7 +473,7 @@ QPDF::parse(char const* password) |
| 473 | 473 | m->parsed = true; |
| 474 | 474 | if (m->xref_table.size() > 0 && !getRoot().getKey("/Pages").isDictionary()) { |
| 475 | 475 | // QPDFs created from JSON have an empty xref table and no root object yet. |
| 476 | - throw damagedPDF("", 0, "unable to find page tree"); | |
| 476 | + throw damagedPDF("", 0, "unable to find page tree"); | |
| 477 | 477 | } |
| 478 | 478 | } |
| 479 | 479 | |
| ... | ... | @@ -547,6 +547,9 @@ QPDF::reconstruct_xref(QPDFExc& e) |
| 547 | 547 | |
| 548 | 548 | m->file->seek(0, SEEK_END); |
| 549 | 549 | qpdf_offset_t eof = m->file->tell(); |
| 550 | + // Sanity check on object ids. All objects must appear in xref table / stream. In all realistic | |
| 551 | + // scenarios at leat 3 bytes are required. | |
| 552 | + auto max_obj_id = eof / 3; | |
| 550 | 553 | m->file->seek(0, SEEK_SET); |
| 551 | 554 | qpdf_offset_t line_start = 0; |
| 552 | 555 | // Don't allow very long tokens here during recovery. |
| ... | ... | @@ -564,7 +567,12 @@ QPDF::reconstruct_xref(QPDFExc& e) |
| 564 | 567 | if ((t2.isInteger()) && (readToken(m->file, MAX_LEN).isWord("obj"))) { |
| 565 | 568 | int obj = QUtil::string_to_int(t1.getValue().c_str()); |
| 566 | 569 | int gen = QUtil::string_to_int(t2.getValue().c_str()); |
| 567 | - insertReconstructedXrefEntry(obj, token_start, gen); | |
| 570 | + if (obj <= max_obj_id) { | |
| 571 | + insertReconstructedXrefEntry(obj, token_start, gen); | |
| 572 | + } else { | |
| 573 | + warn(damagedPDF( | |
| 574 | + "", 0, "ignoring object with impossibly large id " + std::to_string(obj))); | |
| 575 | + } | |
| 568 | 576 | } |
| 569 | 577 | } else if (!m->trailer.isInitialized() && t1.isWord("trailer")) { |
| 570 | 578 | QPDFObjectHandle t = readTrailer(); | ... | ... |
qpdf/qtest/qpdf/issue-147.out
| ... | ... | @@ -3,6 +3,5 @@ WARNING: issue-147.pdf: file is damaged |
| 3 | 3 | WARNING: issue-147.pdf: can't find startxref |
| 4 | 4 | WARNING: issue-147.pdf: Attempting to reconstruct cross-reference table |
| 5 | 5 | WARNING: issue-147.pdf (trailer, offset 9): expected dictionary key but found non-name object; inserting key /QPDFFake1 |
| 6 | -WARNING: issue-147.pdf (object 62 0, offset 88): expected endobj | |
| 7 | -WARNING: issue-147.pdf (trailer, offset 90): invalid /ID in trailer dictionary | |
| 8 | -qpdf: issue-147.pdf: invalid password | |
| 6 | +WARNING: issue-147.pdf: ignoring object with impossibly large id 62 | |
| 7 | +qpdf: issue-147.pdf: unable to find /Root dictionary | ... | ... |