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,6 +62,9 @@ class QPDFXRefEntry | ||
| 62 | private: | 62 | private: |
| 63 | // This class does not use the Members pattern to avoid a memory allocation for every one of | 63 | // This class does not use the Members pattern to avoid a memory allocation for every one of |
| 64 | // these. A lot of these get created. | 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 | int type{0}; | 68 | int type{0}; |
| 66 | qpdf_offset_t field1{0}; | 69 | qpdf_offset_t field1{0}; |
| 67 | int field2{0}; | 70 | int field2{0}; |
libqpdf/QPDF.cc
| @@ -25,6 +25,7 @@ | @@ -25,6 +25,7 @@ | ||
| 25 | #include <qpdf/Util.hh> | 25 | #include <qpdf/Util.hh> |
| 26 | 26 | ||
| 27 | using namespace qpdf; | 27 | using namespace qpdf; |
| 28 | +using namespace std::literals; | ||
| 28 | 29 | ||
| 29 | // This must be a fixed value. This API returns a const reference to it, and the C API relies on its | 30 | // This must be a fixed value. This API returns a const reference to it, and the C API relies on its |
| 30 | // being static as well. | 31 | // being static as well. |
| @@ -1967,6 +1968,7 @@ QPDF::resolveObjectsInStream(int obj_stream_number) | @@ -1967,6 +1968,7 @@ QPDF::resolveObjectsInStream(int obj_stream_number) | ||
| 1967 | (m->file->getName() + " object stream " + std::to_string(obj_stream_number)), | 1968 | (m->file->getName() + " object stream " + std::to_string(obj_stream_number)), |
| 1968 | bp.get())); | 1969 | bp.get())); |
| 1969 | 1970 | ||
| 1971 | + long long last_offset = -1; | ||
| 1970 | for (int i = 0; i < n; ++i) { | 1972 | for (int i = 0; i < n; ++i) { |
| 1971 | QPDFTokenizer::Token tnum = readToken(*input); | 1973 | QPDFTokenizer::Token tnum = readToken(*input); |
| 1972 | QPDFTokenizer::Token toffset = readToken(*input); | 1974 | QPDFTokenizer::Token toffset = readToken(*input); |
| @@ -1980,9 +1982,7 @@ QPDF::resolveObjectsInStream(int obj_stream_number) | @@ -1980,9 +1982,7 @@ QPDF::resolveObjectsInStream(int obj_stream_number) | ||
| 1980 | 1982 | ||
| 1981 | int num = QUtil::string_to_int(tnum.getValue().c_str()); | 1983 | int num = QUtil::string_to_int(tnum.getValue().c_str()); |
| 1982 | long long offset = QUtil::string_to_int(toffset.getValue().c_str()); | 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 | if (num == obj_stream_number) { | 1986 | if (num == obj_stream_number) { |
| 1987 | QTC::TC("qpdf", "QPDF ignore self-referential object stream"); | 1987 | QTC::TC("qpdf", "QPDF ignore self-referential object stream"); |
| 1988 | warn(damagedPDF( | 1988 | warn(damagedPDF( |
| @@ -1992,6 +1992,33 @@ QPDF::resolveObjectsInStream(int obj_stream_number) | @@ -1992,6 +1992,33 @@ QPDF::resolveObjectsInStream(int obj_stream_number) | ||
| 1992 | "object stream claims to contain itself")); | 1992 | "object stream claims to contain itself")); |
| 1993 | continue; | 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 | offsets[num] = toI(offset + first); | 2022 | offsets[num] = toI(offset + first); |
| 1996 | } | 2023 | } |
| 1997 | 2024 |
manual/release-notes.rst
| @@ -81,6 +81,12 @@ more detail. | @@ -81,6 +81,12 @@ more detail. | ||
| 81 | copies the file ``check`` to ``out.pdf`` but may in future check ``out.pdf``. | 81 | copies the file ``check`` to ``out.pdf`` but may in future check ``out.pdf``. |
| 82 | Use ``qpdf ./check out.pdf`` or ``qpdf -- check out.pdf`` instead. | 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 | - Library Enhancements | 90 | - Library Enhancements |
| 85 | 91 | ||
| 86 | - ``QPDFObjectHandle`` supports move construction/assignment. | 92 | - ``QPDFObjectHandle`` supports move construction/assignment. |
qpdf/qpdf.testcov
| @@ -4,7 +4,9 @@ QPDF err wrong objid/generation 0 | @@ -4,7 +4,9 @@ QPDF err wrong objid/generation 0 | ||
| 4 | QPDF check objid 1 | 4 | QPDF check objid 1 |
| 5 | QPDF check generation 1 | 5 | QPDF check generation 1 |
| 6 | QPDF check obj 1 | 6 | QPDF check obj 1 |
| 7 | +QPDF object stream offsets not increasing 0 | ||
| 7 | QPDF ignore self-referential object stream 0 | 8 | QPDF ignore self-referential object stream 0 |
| 9 | +QPDF object stream contains id < 1 0 | ||
| 8 | QPDF hint table length indirect 0 | 10 | QPDF hint table length indirect 0 |
| 9 | QPDF hint table length direct 0 | 11 | QPDF hint table length direct 0 |
| 10 | QPDF P absent in lindict 0 | 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,5 +14,9 @@ WARNING: issue-143.pdf (object 1 0, offset 24): expected dictionary key but foun | ||
| 14 | WARNING: issue-143.pdf (object 1 0, offset 21): stream dictionary lacks /Length key | 14 | WARNING: issue-143.pdf (object 1 0, offset 21): stream dictionary lacks /Length key |
| 15 | WARNING: issue-143.pdf (object 1 0, offset 84): attempting to recover stream length | 15 | WARNING: issue-143.pdf (object 1 0, offset 84): attempting to recover stream length |
| 16 | WARNING: issue-143.pdf (object 1 0, offset 84): recovered stream length: 606 | 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 | WARNING: issue-143.pdf object stream 1 (object 2 0, offset 33): expected dictionary key but found non-name object; inserting key /QPDFFake1 | 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 | qpdf: issue-143.pdf: unable to find page tree | 22 | qpdf: issue-143.pdf: unable to find page tree |
qpdf/qtest/qpdf/issue-143.pdf
No preview for this file type