From 7f2d76b78d5bf7331f99039804c01320673bde13 Mon Sep 17 00:00:00 2001 From: m-holger Date: Tue, 16 Jul 2024 14:35:32 +0100 Subject: [PATCH 1/4] Remove non-dictionary objects from pages tree --- include/qpdf/QPDF.hh | 1 + libqpdf/QPDF_pages.cc | 13 +++++++++++-- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/include/qpdf/QPDF.hh b/include/qpdf/QPDF.hh index 0044e58a..a57925ac 100644 --- a/include/qpdf/QPDF.hh +++ b/include/qpdf/QPDF.hh @@ -1515,6 +1515,7 @@ class QPDF std::set resolving; QPDFObjectHandle trailer; std::vector all_pages; + bool invalid_page_found{false}; std::map pageobj_to_pages_pos; bool pushed_inherited_attributes_to_pages{false}; bool ever_pushed_inherited_attributes_to_pages{false}; diff --git a/libqpdf/QPDF_pages.cc b/libqpdf/QPDF_pages.cc index aeae7ceb..8c6a20e7 100644 --- a/libqpdf/QPDF_pages.cc +++ b/libqpdf/QPDF_pages.cc @@ -40,7 +40,7 @@ std::vector const& QPDF::getAllPages() { // Note that pushInheritedAttributesToPage may also be used to initialize m->all_pages. - if (m->all_pages.empty()) { + if (m->all_pages.empty() && !m->invalid_page_found) { m->ever_called_get_all_pages = true; QPDFObjGen::set visited; QPDFObjGen::set seen; @@ -70,6 +70,10 @@ QPDF::getAllPages() // Ensure we actually found a /Pages object. getAllPagesInternal(pages, visited, seen, false); } + if (m->invalid_page_found) { + flattenPagesTree(); + m->invalid_page_found = false; + } } return m->all_pages; } @@ -100,6 +104,7 @@ QPDF::getAllPagesInternal( auto kid = kids.getArrayItem(i); if (!kid.isDictionary()) { kid.warnIfPossible("Pages tree includes non-dictionary object; ignoring"); + m->invalid_page_found = true; continue; } if (kid.hasKey("/Kids")) { @@ -181,7 +186,11 @@ QPDF::flattenPagesTree() pages.replaceKey("/Kids", QPDFObjectHandle::newArray(m->all_pages)); // /Count has not changed if (pages.getKey("/Count").getUIntValue() != len) { - throw std::runtime_error("/Count is wrong after flattening pages tree"); + if (m->invalid_page_found && pages.getKey("/Count").getUIntValue() > len) { + pages.replaceKey("/Count", QPDFObjectHandle::newInteger(toI(len))); + } else { + throw std::runtime_error("/Count is wrong after flattening pages tree"); + } } } From 25e11a444a25840e2b4635dbcb0197d5bb935d25 Mon Sep 17 00:00:00 2001 From: m-holger Date: Tue, 16 Jul 2024 14:44:47 +0100 Subject: [PATCH 2/4] Throw an exception if the root of the pages tree misses the /Kids array --- libqpdf/QPDF_pages.cc | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/libqpdf/QPDF_pages.cc b/libqpdf/QPDF_pages.cc index 8c6a20e7..0c8f3829 100644 --- a/libqpdf/QPDF_pages.cc +++ b/libqpdf/QPDF_pages.cc @@ -66,10 +66,12 @@ QPDF::getAllPages() getRoot().replaceKey("/Pages", pages); } seen.clear(); - if (pages.hasKey("/Kids")) { + if (!pages.hasKey("/Kids")) { // Ensure we actually found a /Pages object. - getAllPagesInternal(pages, visited, seen, false); + throw QPDFExc( + qpdf_e_pages, m->file->getName(), "", 0, "root of pages tree has no /Kids array"); } + getAllPagesInternal(pages, visited, seen, false); if (m->invalid_page_found) { flattenPagesTree(); m->invalid_page_found = false; From e14e828c3df09bcf741b45f3aea6f5db599e7b92 Mon Sep 17 00:00:00 2001 From: m-holger Date: Tue, 16 Jul 2024 14:45:56 +0100 Subject: [PATCH 3/4] Add further fuzz tests --- fuzz/CMakeLists.txt | 4 +++- fuzz/qpdf_extra/4826608268017664.fuzz | Bin 0 -> 871948 bytes fuzz/qpdf_extra/70245.fuzz | 0 .../{4599089157701632.fuzz => 70306.fuzz} | Bin fuzz/qtest/fuzz.test | 2 +- 5 files changed, 4 insertions(+), 2 deletions(-) create mode 100644 fuzz/qpdf_extra/4826608268017664.fuzz create mode 100644 fuzz/qpdf_extra/70245.fuzz rename fuzz/qpdf_extra/{4599089157701632.fuzz => 70306.fuzz} (100%) diff --git a/fuzz/CMakeLists.txt b/fuzz/CMakeLists.txt index bb0f616c..05a23bd9 100644 --- a/fuzz/CMakeLists.txt +++ b/fuzz/CMakeLists.txt @@ -127,7 +127,9 @@ set(CORPUS_OTHER 69977b.fuzz 69977c.fuzz 70055.fuzz - 4599089157701632.fuzz + 70245.fuzz + 70306.fuzz + 4826608268017664.fuzz ) set(CORPUS_DIR ${CMAKE_CURRENT_BINARY_DIR}/qpdf_corpus) diff --git a/fuzz/qpdf_extra/4826608268017664.fuzz b/fuzz/qpdf_extra/4826608268017664.fuzz new file mode 100644 index 0000000000000000000000000000000000000000..2ae60ffb9c47e8d4bbd8897bf7c7ccff9ddcee9e GIT binary patch literal 871948 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 VV}4k@H;~GOrXZ}VyEpJK_&={ORg?e# literal 0 HcmV?d00001 diff --git a/fuzz/qpdf_extra/70245.fuzz b/fuzz/qpdf_extra/70245.fuzz new file mode 100644 index 00000000..e69de29b diff --git a/fuzz/qpdf_extra/4599089157701632.fuzz b/fuzz/qpdf_extra/70306.fuzz similarity index 100% rename from fuzz/qpdf_extra/4599089157701632.fuzz rename to fuzz/qpdf_extra/70306.fuzz diff --git a/fuzz/qtest/fuzz.test b/fuzz/qtest/fuzz.test index 952a26ef..c1e8ecb7 100644 --- a/fuzz/qtest/fuzz.test +++ b/fuzz/qtest/fuzz.test @@ -21,7 +21,7 @@ my @fuzzers = ( ['pngpredictor' => 1], ['runlength' => 6], ['tiffpredictor' => 2], - ['qpdf' => 70], # increment when adding new files + ['qpdf' => 72], # increment when adding new files ); my $n_tests = 0; From 992b7911ce743a87589e6ddf0fe84de1ee4d9366 Mon Sep 17 00:00:00 2001 From: m-holger Date: Tue, 16 Jul 2024 15:36:58 +0100 Subject: [PATCH 4/4] Limit the number of warnings in json_fuzzer before giving up --- fuzz/json_fuzzer.cc | 1 + libqpdf/QPDF_json.cc | 17 +++++++++++------ 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/fuzz/json_fuzzer.cc b/fuzz/json_fuzzer.cc index 3ac644a7..8b46a0ad 100644 --- a/fuzz/json_fuzzer.cc +++ b/fuzz/json_fuzzer.cc @@ -33,6 +33,7 @@ FuzzHelper::doChecks() std::cerr << "runtime_error parsing json: " << e.what() << std::endl; } QPDF q; + q.setMaxWarnings(1000); Buffer buf(const_cast(data), size); auto is = std::make_shared("json", &buf); q.createFromJSON(is); diff --git a/libqpdf/QPDF_json.cc b/libqpdf/QPDF_json.cc index b06b70c9..ffdd7112 100644 --- a/libqpdf/QPDF_json.cc +++ b/libqpdf/QPDF_json.cc @@ -233,12 +233,13 @@ provide_data(std::shared_ptr is, qpdf_offset_t start, qpdf_offset_t class QPDF::JSONReactor: public JSON::Reactor { public: - JSONReactor(QPDF& pdf, std::shared_ptr is, bool must_be_complete) : + JSONReactor(QPDF& pdf, std::shared_ptr is, bool must_be_complete, int max_warnings) : pdf(pdf), is(is), must_be_complete(must_be_complete), descr(std::make_shared( - QPDFValue::JSON_Descr(std::make_shared(is->getName()), ""))) + QPDFValue::JSON_Descr(std::make_shared(is->getName()), ""))), + max_warnings(max_warnings) { for (auto& oc: pdf.m->obj_cache) { if (oc.second.object->getTypeCode() == ::ot_reserved) { @@ -291,7 +292,8 @@ class QPDF::JSONReactor: public JSON::Reactor std::shared_ptr is; bool must_be_complete{true}; std::shared_ptr descr; - bool errors{false}; + int errors{0}; + int max_warnings{0}; bool saw_qpdf{false}; bool saw_qpdf_meta{false}; bool saw_objects{false}; @@ -314,18 +316,21 @@ class QPDF::JSONReactor: public JSON::Reactor void QPDF::JSONReactor::error(qpdf_offset_t offset, std::string const& msg) { - this->errors = true; + ++errors; std::string object = this->cur_object; if (is->getName() != pdf.getFilename()) { object += " from " + is->getName(); } this->pdf.warn(qpdf_e_json, object, offset, msg); + if (max_warnings > 0 && errors >= max_warnings) { + throw std::runtime_error("errors found in JSON"); + } } bool QPDF::JSONReactor::anyErrors() const { - return this->errors; + return errors > 0; } void @@ -820,7 +825,7 @@ QPDF::updateFromJSON(std::shared_ptr is) void QPDF::importJSON(std::shared_ptr is, bool must_be_complete) { - JSONReactor reactor(*this, is, must_be_complete); + JSONReactor reactor(*this, is, must_be_complete, m->max_warnings); try { JSON::parse(*is, &reactor); } catch (std::runtime_error& e) {