From 972cbf103da10df7d2dd89313b4ce985a1b06ab8 Mon Sep 17 00:00:00 2001 From: m-holger Date: Tue, 30 Apr 2024 10:38:59 +0100 Subject: [PATCH 1/3] In QPDF::processXRefStream avoid inserting objed id 0 into the xref table --- libqpdf/QPDF.cc | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/libqpdf/QPDF.cc b/libqpdf/QPDF.cc index 3f776852..d5e9c7c8 100644 --- a/libqpdf/QPDF.cc +++ b/libqpdf/QPDF.cc @@ -1117,8 +1117,7 @@ QPDF::processXRefStream(qpdf_offset_t xref_offset, QPDFObjectHandle& xref_obj) if (obj == 0) { // This is needed by checkLinearization() m->first_xref_item_offset = xref_offset; - } - if (fields[0] == 0) { + } else if (fields[0] == 0) { // Ignore fields[2], which we don't care about in this case. This works around the issue // of some PDF files that put invalid values, like -1, here for deleted objects. insertFreeXrefEntry(QPDFObjGen(obj, 0)); From 60c7d594b835ae2eac8235658179aedce7b3b007 Mon Sep 17 00:00:00 2001 From: m-holger Date: Tue, 30 Apr 2024 10:46:06 +0100 Subject: [PATCH 2/3] In QPDF::filterCompressedObjects ignore objects not in QPDFWriter tables Add fuzz case 68377. --- fuzz/CMakeLists.txt | 1 + fuzz/qpdf_extra/68377.fuzz | Bin 0 -> 124 bytes fuzz/qtest/fuzz.test | 2 +- libqpdf/QPDF_optimization.cc | 24 ++++++++++++++---------- libqpdf/qpdf/ObjTable.hh | 6 ++++++ 5 files changed, 22 insertions(+), 11 deletions(-) create mode 100644 fuzz/qpdf_extra/68377.fuzz diff --git a/fuzz/CMakeLists.txt b/fuzz/CMakeLists.txt index efa71528..73ecced1 100644 --- a/fuzz/CMakeLists.txt +++ b/fuzz/CMakeLists.txt @@ -114,6 +114,7 @@ set(CORPUS_OTHER 65681.fuzz 65773.fuzz 65777.fuzz + 68377.fuzz ) set(CORPUS_DIR ${CMAKE_CURRENT_BINARY_DIR}/qpdf_corpus) diff --git a/fuzz/qpdf_extra/68377.fuzz b/fuzz/qpdf_extra/68377.fuzz new file mode 100644 index 0000000000000000000000000000000000000000..61ce0e221693693eb03e82db597b8a558008b02e GIT binary patch literal 124 zcmY!|G*U27$WO|$v57VVvVs&0EiFKFteqXNDNIV=Ei|5vLIDIA}BRYKRnt{!C1i%sJXbLC^a!xA>&?B5(A^!|7HIjgcv=KrRJqT JCH^b?2LLgpCVl__ literal 0 HcmV?d00001 diff --git a/fuzz/qtest/fuzz.test b/fuzz/qtest/fuzz.test index 7235140d..3ba93156 100644 --- a/fuzz/qtest/fuzz.test +++ b/fuzz/qtest/fuzz.test @@ -21,7 +21,7 @@ my @fuzzers = ( ['pngpredictor' => 1], ['runlength' => 6], ['tiffpredictor' => 2], - ['qpdf' => 56], # increment when adding new files + ['qpdf' => 57], # increment when adding new files ); my $n_tests = 0; diff --git a/libqpdf/QPDF_optimization.cc b/libqpdf/QPDF_optimization.cc index 9f423a3a..75615436 100644 --- a/libqpdf/QPDF_optimization.cc +++ b/libqpdf/QPDF_optimization.cc @@ -416,22 +416,26 @@ QPDF::filterCompressedObjects(QPDFWriter::ObjTable const& obj) ObjUser const& ou = i1.first; // Loop over objects. for (auto const& og: i1.second) { - if (auto const& i2 = obj[og].object_stream; i2 <= 0) { - t_obj_user_to_objects[ou].insert(og); - } else { - t_obj_user_to_objects[ou].insert(QPDFObjGen(i2, 0)); + if (obj.contains(og)) { + if (auto const& i2 = obj[og].object_stream; i2 <= 0) { + t_obj_user_to_objects[ou].insert(og); + } else { + t_obj_user_to_objects[ou].insert(QPDFObjGen(i2, 0)); + } } } } for (auto const& i1: m->object_to_obj_users) { QPDFObjGen const& og = i1.first; - // Loop over obj_users. - for (auto const& ou: i1.second) { - if (auto i2 = obj[og].object_stream; i2 <= 0) { - t_object_to_obj_users[og].insert(ou); - } else { - t_object_to_obj_users[QPDFObjGen(i2, 0)].insert(ou); + if (obj.contains(og)) { + // Loop over obj_users. + for (auto const& ou: i1.second) { + if (auto i2 = obj[og].object_stream; i2 <= 0) { + t_object_to_obj_users[og].insert(ou); + } else { + t_object_to_obj_users[QPDFObjGen(i2, 0)].insert(ou); + } } } } diff --git a/libqpdf/qpdf/ObjTable.hh b/libqpdf/qpdf/ObjTable.hh index 1f0f8a2b..84b51b78 100644 --- a/libqpdf/qpdf/ObjTable.hh +++ b/libqpdf/qpdf/ObjTable.hh @@ -62,6 +62,12 @@ class ObjTable: public std::vector return idx < std::vector::size() || sparse_elements.count(idx); } + inline bool + contains(QPDFObjGen og) const + { + return contains(static_cast(og.getObj())); + } + inline bool contains(QPDFObjectHandle oh) const { From e85b98b7e8b8b330614fc31825c411260fc2eaef Mon Sep 17 00:00:00 2001 From: m-holger Date: Tue, 30 Apr 2024 10:58:31 +0100 Subject: [PATCH 3/3] Guard against object id == std::numeric_limits in QPDF::insertReconstructedXrefEntry --- fuzz/CMakeLists.txt | 1 + fuzz/qpdf_extra/68374.fuzz | Bin 0 -> 392 bytes fuzz/qtest/fuzz.test | 2 +- libqpdf/QPDF.cc | 4 +++- 4 files changed, 5 insertions(+), 2 deletions(-) create mode 100644 fuzz/qpdf_extra/68374.fuzz diff --git a/fuzz/CMakeLists.txt b/fuzz/CMakeLists.txt index 73ecced1..233a4571 100644 --- a/fuzz/CMakeLists.txt +++ b/fuzz/CMakeLists.txt @@ -114,6 +114,7 @@ set(CORPUS_OTHER 65681.fuzz 65773.fuzz 65777.fuzz + 68374.fuzz 68377.fuzz ) diff --git a/fuzz/qpdf_extra/68374.fuzz b/fuzz/qpdf_extra/68374.fuzz new file mode 100644 index 0000000000000000000000000000000000000000..748bad9283ec7892e530020df9441fc001c6f4f9 GIT binary patch literal 392 zcmcC9u(L6+)75uzbIVROH{~iRO3chjE#l&`vEkAW%Fi!RFjX*62;$Pu;kUEn%1Yn@ zar2Y16o3jCfPjmE!G?ha$oRif-zPOMy(B|U!N3Tt1*pE*wxlREF_)L?E0 1], ['runlength' => 6], ['tiffpredictor' => 2], - ['qpdf' => 57], # increment when adding new files + ['qpdf' => 58], # increment when adding new files ); my $n_tests = 0; diff --git a/libqpdf/QPDF.cc b/libqpdf/QPDF.cc index d5e9c7c8..ed32b386 100644 --- a/libqpdf/QPDF.cc +++ b/libqpdf/QPDF.cc @@ -1195,7 +1195,9 @@ QPDF::insertFreeXrefEntry(QPDFObjGen og) void QPDF::insertReconstructedXrefEntry(int obj, qpdf_offset_t f1, int f2) { - if (!(obj > 0 && 0 <= f2 && f2 < 65535)) { + // Various tables are indexed by object id, with potential size id + 1 + constexpr static int max_id = std::numeric_limits::max() - 1; + if (!(obj > 0 && obj <= max_id && 0 <= f2 && f2 < 65535)) { QTC::TC("qpdf", "QPDF xref overwrite invalid objgen"); return; }