Commit e063f3237dff54e547ba78e3d34eb9a77f3e2a00
Committed by
GitHub
Merge pull request #1384 from m-holger/ostream
Enhance error checking of object stream object ids and offsets
Showing
6 changed files
with
45 additions
and
3 deletions
include/qpdf/QPDFXRefEntry.hh
| ... | ... | @@ -62,6 +62,9 @@ class QPDFXRefEntry |
| 62 | 62 | private: |
| 63 | 63 | // This class does not use the Members pattern to avoid a memory allocation for every one of |
| 64 | 64 | // these. A lot of these get created. |
| 65 | + | |
| 66 | + // The layout can be changed to reduce the size from 24 to 16 bytes. However, this would have a | |
| 67 | + // definite runtime cost. | |
| 65 | 68 | int type{0}; |
| 66 | 69 | qpdf_offset_t field1{0}; |
| 67 | 70 | int field2{0}; | ... | ... |
libqpdf/QPDF.cc
| ... | ... | @@ -25,6 +25,7 @@ |
| 25 | 25 | #include <qpdf/Util.hh> |
| 26 | 26 | |
| 27 | 27 | using namespace qpdf; |
| 28 | +using namespace std::literals; | |
| 28 | 29 | |
| 29 | 30 | // This must be a fixed value. This API returns a const reference to it, and the C API relies on its |
| 30 | 31 | // being static as well. |
| ... | ... | @@ -1967,6 +1968,7 @@ QPDF::resolveObjectsInStream(int obj_stream_number) |
| 1967 | 1968 | (m->file->getName() + " object stream " + std::to_string(obj_stream_number)), |
| 1968 | 1969 | bp.get())); |
| 1969 | 1970 | |
| 1971 | + long long last_offset = -1; | |
| 1970 | 1972 | for (int i = 0; i < n; ++i) { |
| 1971 | 1973 | QPDFTokenizer::Token tnum = readToken(*input); |
| 1972 | 1974 | QPDFTokenizer::Token toffset = readToken(*input); |
| ... | ... | @@ -1980,9 +1982,7 @@ QPDF::resolveObjectsInStream(int obj_stream_number) |
| 1980 | 1982 | |
| 1981 | 1983 | int num = QUtil::string_to_int(tnum.getValue().c_str()); |
| 1982 | 1984 | long long offset = QUtil::string_to_int(toffset.getValue().c_str()); |
| 1983 | - if (num > m->xref_table_max_id) { | |
| 1984 | - continue; | |
| 1985 | - } | |
| 1985 | + | |
| 1986 | 1986 | if (num == obj_stream_number) { |
| 1987 | 1987 | QTC::TC("qpdf", "QPDF ignore self-referential object stream"); |
| 1988 | 1988 | warn(damagedPDF( |
| ... | ... | @@ -1992,6 +1992,33 @@ QPDF::resolveObjectsInStream(int obj_stream_number) |
| 1992 | 1992 | "object stream claims to contain itself")); |
| 1993 | 1993 | continue; |
| 1994 | 1994 | } |
| 1995 | + | |
| 1996 | + if (num < 1) { | |
| 1997 | + QTC::TC("qpdf", "QPDF object stream contains id < 1"); | |
| 1998 | + warn(damagedPDF( | |
| 1999 | + *input, | |
| 2000 | + "object "s + std::to_string(num) + " 0, offset " + std::to_string(offset), | |
| 2001 | + 0, | |
| 2002 | + "object id is invalid"s)); | |
| 2003 | + continue; | |
| 2004 | + } | |
| 2005 | + | |
| 2006 | + if (offset <= last_offset) { | |
| 2007 | + QTC::TC("qpdf", "QPDF object stream offsets not increasing"); | |
| 2008 | + warn(damagedPDF( | |
| 2009 | + *input, | |
| 2010 | + "object "s + std::to_string(num) + " 0, offset " + std::to_string(offset), | |
| 2011 | + 0, | |
| 2012 | + "offset is invalid (must be larger than previous offset " + | |
| 2013 | + std::to_string(last_offset) + ")")); | |
| 2014 | + continue; | |
| 2015 | + } | |
| 2016 | + last_offset = offset; | |
| 2017 | + | |
| 2018 | + if (num > m->xref_table_max_id) { | |
| 2019 | + continue; | |
| 2020 | + } | |
| 2021 | + | |
| 1995 | 2022 | offsets[num] = toI(offset + first); |
| 1996 | 2023 | } |
| 1997 | 2024 | ... | ... |
manual/release-notes.rst
| ... | ... | @@ -81,6 +81,12 @@ more detail. |
| 81 | 81 | copies the file ``check`` to ``out.pdf`` but may in future check ``out.pdf``. |
| 82 | 82 | Use ``qpdf ./check out.pdf`` or ``qpdf -- check out.pdf`` instead. |
| 83 | 83 | |
| 84 | + | |
| 85 | + - Bug fixes | |
| 86 | + | |
| 87 | + - In object streams ignore objects with invalid offset. Report objects with invalid | |
| 88 | + id or offset. | |
| 89 | + | |
| 84 | 90 | - Library Enhancements |
| 85 | 91 | |
| 86 | 92 | - ``QPDFObjectHandle`` supports move construction/assignment. | ... | ... |
qpdf/qpdf.testcov
| ... | ... | @@ -4,7 +4,9 @@ QPDF err wrong objid/generation 0 |
| 4 | 4 | QPDF check objid 1 |
| 5 | 5 | QPDF check generation 1 |
| 6 | 6 | QPDF check obj 1 |
| 7 | +QPDF object stream offsets not increasing 0 | |
| 7 | 8 | QPDF ignore self-referential object stream 0 |
| 9 | +QPDF object stream contains id < 1 0 | |
| 8 | 10 | QPDF hint table length indirect 0 |
| 9 | 11 | QPDF hint table length direct 0 |
| 10 | 12 | QPDF P absent in lindict 0 | ... | ... |
qpdf/qtest/qpdf/issue-143.out
| ... | ... | @@ -14,5 +14,9 @@ WARNING: issue-143.pdf (object 1 0, offset 24): expected dictionary key but foun |
| 14 | 14 | WARNING: issue-143.pdf (object 1 0, offset 21): stream dictionary lacks /Length key |
| 15 | 15 | WARNING: issue-143.pdf (object 1 0, offset 84): attempting to recover stream length |
| 16 | 16 | WARNING: issue-143.pdf (object 1 0, offset 84): recovered stream length: 606 |
| 17 | +WARNING: issue-143.pdf object stream 1 (object 0 0, offset 0): object id is invalid | |
| 18 | +WARNING: issue-143.pdf object stream 1 (object 0 0, offset 0): object id is invalid | |
| 19 | +WARNING: issue-143.pdf object stream 1 (object 6 0, offset 0): offset is invalid (must be larger than previous offset 0) | |
| 20 | +WARNING: issue-143.pdf object stream 1 (object 0 0, offset 0): object id is invalid | |
| 17 | 21 | WARNING: issue-143.pdf object stream 1 (object 2 0, offset 33): expected dictionary key but found non-name object; inserting key /QPDFFake1 |
| 18 | 22 | qpdf: issue-143.pdf: unable to find page tree | ... | ... |
qpdf/qtest/qpdf/issue-143.pdf
No preview for this file type