2
1
mirror of https://github.com/qpdf/qpdf.git synced 2024-12-22 19:08:59 +00:00

In QPDF::reconstruct_xref add sanity check for object ids

This commit is contained in:
m-holger 2024-06-25 15:46:47 +01:00
parent e62973d277
commit 4a8c821e3e
2 changed files with 12 additions and 5 deletions

View File

@ -473,7 +473,7 @@ QPDF::parse(char const* password)
m->parsed = true; m->parsed = true;
if (m->xref_table.size() > 0 && !getRoot().getKey("/Pages").isDictionary()) { if (m->xref_table.size() > 0 && !getRoot().getKey("/Pages").isDictionary()) {
// QPDFs created from JSON have an empty xref table and no root object yet. // QPDFs created from JSON have an empty xref table and no root object yet.
throw damagedPDF("", 0, "unable to find page tree"); throw damagedPDF("", 0, "unable to find page tree");
} }
} }
@ -547,6 +547,9 @@ QPDF::reconstruct_xref(QPDFExc& e)
m->file->seek(0, SEEK_END); m->file->seek(0, SEEK_END);
qpdf_offset_t eof = m->file->tell(); qpdf_offset_t eof = m->file->tell();
// Sanity check on object ids. All objects must appear in xref table / stream. In all realistic
// scenarios at leat 3 bytes are required.
auto max_obj_id = eof / 3;
m->file->seek(0, SEEK_SET); m->file->seek(0, SEEK_SET);
qpdf_offset_t line_start = 0; qpdf_offset_t line_start = 0;
// Don't allow very long tokens here during recovery. // Don't allow very long tokens here during recovery.
@ -564,7 +567,12 @@ QPDF::reconstruct_xref(QPDFExc& e)
if ((t2.isInteger()) && (readToken(m->file, MAX_LEN).isWord("obj"))) { if ((t2.isInteger()) && (readToken(m->file, MAX_LEN).isWord("obj"))) {
int obj = QUtil::string_to_int(t1.getValue().c_str()); int obj = QUtil::string_to_int(t1.getValue().c_str());
int gen = QUtil::string_to_int(t2.getValue().c_str()); int gen = QUtil::string_to_int(t2.getValue().c_str());
insertReconstructedXrefEntry(obj, token_start, gen); if (obj <= max_obj_id) {
insertReconstructedXrefEntry(obj, token_start, gen);
} else {
warn(damagedPDF(
"", 0, "ignoring object with impossibly large id " + std::to_string(obj)));
}
} }
} else if (!m->trailer.isInitialized() && t1.isWord("trailer")) { } else if (!m->trailer.isInitialized() && t1.isWord("trailer")) {
QPDFObjectHandle t = readTrailer(); QPDFObjectHandle t = readTrailer();

View File

@ -3,6 +3,5 @@ WARNING: issue-147.pdf: file is damaged
WARNING: issue-147.pdf: can't find startxref WARNING: issue-147.pdf: can't find startxref
WARNING: issue-147.pdf: Attempting to reconstruct cross-reference table WARNING: issue-147.pdf: Attempting to reconstruct cross-reference table
WARNING: issue-147.pdf (trailer, offset 9): expected dictionary key but found non-name object; inserting key /QPDFFake1 WARNING: issue-147.pdf (trailer, offset 9): expected dictionary key but found non-name object; inserting key /QPDFFake1
WARNING: issue-147.pdf (object 62 0, offset 88): expected endobj WARNING: issue-147.pdf: ignoring object with impossibly large id 62
WARNING: issue-147.pdf (trailer, offset 90): invalid /ID in trailer dictionary qpdf: issue-147.pdf: unable to find /Root dictionary
qpdf: issue-147.pdf: invalid password