From 746b5edb275f818ab05ae5172fe28d30575c56e9 Mon Sep 17 00:00:00 2001 From: m-holger Date: Fri, 16 May 2025 00:25:14 +0100 Subject: [PATCH] Temporarily rename qpdf_pages_fuzzer to qpdf_page_fuzzer --- fuzz/CMakeLists.txt | 2 +- fuzz/qpdf_page_fuzzer.cc | 152 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ fuzz/qpdf_page_fuzzer.options | 2 ++ fuzz/qpdf_pages_fuzzer.cc | 152 -------------------------------------------------------------------------------------------------------------------------------------------------------- fuzz/qpdf_pages_fuzzer.options | 2 -- fuzz/qtest/fuzz.test | 2 +- 6 files changed, 156 insertions(+), 156 deletions(-) create mode 100644 fuzz/qpdf_page_fuzzer.cc create mode 100644 fuzz/qpdf_page_fuzzer.options delete mode 100644 fuzz/qpdf_pages_fuzzer.cc delete mode 100644 fuzz/qpdf_pages_fuzzer.options diff --git a/fuzz/CMakeLists.txt b/fuzz/CMakeLists.txt index 7377833..38b55c6 100644 --- a/fuzz/CMakeLists.txt +++ b/fuzz/CMakeLists.txt @@ -6,7 +6,7 @@ set(FUZZERS qpdf_crypt_fuzzer qpdf_crypt_insecure_fuzzer qpdf_lin_fuzzer - qpdf_pages_fuzzer + qpdf_page_fuzzer qpdf_outlines_fuzzer ascii85_fuzzer dct_fuzzer diff --git a/fuzz/qpdf_page_fuzzer.cc b/fuzz/qpdf_page_fuzzer.cc new file mode 100644 index 0000000..4dd7ae5 --- /dev/null +++ b/fuzz/qpdf_page_fuzzer.cc @@ -0,0 +1,152 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +class DiscardContents: public QPDFObjectHandle::ParserCallbacks +{ + public: + ~DiscardContents() override = default; + void + handleObject(QPDFObjectHandle) override + { + } + void + handleEOF() override + { + } +}; + +class FuzzHelper +{ + public: + FuzzHelper(unsigned char const* data, size_t size); + void run(); + + private: + std::shared_ptr getQpdf(); + void testPages(); + void doChecks(); + + Buffer input_buffer; + Pl_Discard discard; +}; + +FuzzHelper::FuzzHelper(unsigned char const* data, size_t size) : + // We do not modify data, so it is safe to remove the const for Buffer + input_buffer(const_cast(data), size) +{ +} + +std::shared_ptr +FuzzHelper::getQpdf() +{ + auto is = + std::shared_ptr(new BufferInputSource("fuzz input", &this->input_buffer)); + auto qpdf = QPDF::create(); + qpdf->setMaxWarnings(200); + qpdf->processInputSource(is); + return qpdf; +} + +void +FuzzHelper::testPages() +{ + // Parse all content streams, and exercise some helpers that + // operate on pages. + std::shared_ptr q = getQpdf(); + QPDFPageDocumentHelper pdh(*q); + QPDFPageLabelDocumentHelper pldh(*q); + QPDFOutlineDocumentHelper odh(*q); + QPDFAcroFormDocumentHelper afdh(*q); + afdh.generateAppearancesIfNeeded(); + pdh.flattenAnnotations(); + DiscardContents discard_contents; + int pageno = 0; + for (auto& page: pdh.getAllPages()) { + ++pageno; + try { + page.coalesceContentStreams(); + page.parseContents(&discard_contents); + page.getImages(); + pldh.getLabelForPage(pageno); + QPDFObjectHandle page_obj(page.getObjectHandle()); + page_obj.getJSON(JSON::LATEST, true).unparse(); + odh.getOutlinesForPage(page_obj); + + for (auto& aoh: afdh.getWidgetAnnotationsForPage(page)) { + afdh.getFieldForAnnotation(aoh); + } + } catch (QPDFExc& e) { + std::cerr << "page " << pageno << ": " << e.what() << '\n'; + } + } +} + +void +FuzzHelper::doChecks() +{ + // Limit the memory used to decompress JPEG files during fuzzing. Excessive memory use during + // fuzzing is due to corrupt JPEG data which sometimes cannot be detected before + // jpeg_start_decompress is called. During normal use of qpdf very large JPEGs can occasionally + // occur legitimately and therefore must be allowed during normal operations. + Pl_DCT::setMemoryLimit(100'000'000); + Pl_DCT::setScanLimit(50); + + Pl_PNGFilter::setMemoryLimit(1'000'000); + Pl_RunLength::setMemoryLimit(1'000'000); + Pl_TIFFPredictor::setMemoryLimit(1'000'000); + Pl_Flate::memory_limit(200'000); + + // Do not decompress corrupt data. This may cause extended runtime within jpeglib without + // exercising additional code paths in qpdf, and potentially causing counterproductive timeouts. + Pl_DCT::setThrowOnCorruptData(true); + + // Get as much coverage as possible in parts of the library that + // might benefit from fuzzing. + std::cerr << "\ninfo: starting testPages\n"; + testPages(); +} + +void +FuzzHelper::run() +{ + // The goal here is that you should be able to throw anything at + // libqpdf and it will respond without any memory errors and never + // do anything worse than throwing a QPDFExc or + // std::runtime_error. Throwing any other kind of exception, + // segfaulting, or having a memory error (when built with + // appropriate sanitizers) will all cause abnormal exit. + try { + doChecks(); + } catch (QPDFExc const& e) { + std::cerr << "QPDFExc: " << e.what() << '\n'; + } catch (std::runtime_error const& e) { + std::cerr << "runtime_error: " << e.what() << '\n'; + } +} + +extern "C" int +LLVMFuzzerTestOneInput(unsigned char const* data, size_t size) +{ +#ifndef _WIN32 + // Used by jpeg library to work around false positives in memory + // sanitizer. + setenv("JSIMD_FORCENONE", "1", 1); +#endif + FuzzHelper f(data, size); + f.run(); + return 0; +} diff --git a/fuzz/qpdf_page_fuzzer.options b/fuzz/qpdf_page_fuzzer.options new file mode 100644 index 0000000..a15a774 --- /dev/null +++ b/fuzz/qpdf_page_fuzzer.options @@ -0,0 +1,2 @@ +[libfuzzer] +dict = pdf.dict diff --git a/fuzz/qpdf_pages_fuzzer.cc b/fuzz/qpdf_pages_fuzzer.cc deleted file mode 100644 index 4dd7ae5..0000000 --- a/fuzz/qpdf_pages_fuzzer.cc +++ /dev/null @@ -1,152 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -class DiscardContents: public QPDFObjectHandle::ParserCallbacks -{ - public: - ~DiscardContents() override = default; - void - handleObject(QPDFObjectHandle) override - { - } - void - handleEOF() override - { - } -}; - -class FuzzHelper -{ - public: - FuzzHelper(unsigned char const* data, size_t size); - void run(); - - private: - std::shared_ptr getQpdf(); - void testPages(); - void doChecks(); - - Buffer input_buffer; - Pl_Discard discard; -}; - -FuzzHelper::FuzzHelper(unsigned char const* data, size_t size) : - // We do not modify data, so it is safe to remove the const for Buffer - input_buffer(const_cast(data), size) -{ -} - -std::shared_ptr -FuzzHelper::getQpdf() -{ - auto is = - std::shared_ptr(new BufferInputSource("fuzz input", &this->input_buffer)); - auto qpdf = QPDF::create(); - qpdf->setMaxWarnings(200); - qpdf->processInputSource(is); - return qpdf; -} - -void -FuzzHelper::testPages() -{ - // Parse all content streams, and exercise some helpers that - // operate on pages. - std::shared_ptr q = getQpdf(); - QPDFPageDocumentHelper pdh(*q); - QPDFPageLabelDocumentHelper pldh(*q); - QPDFOutlineDocumentHelper odh(*q); - QPDFAcroFormDocumentHelper afdh(*q); - afdh.generateAppearancesIfNeeded(); - pdh.flattenAnnotations(); - DiscardContents discard_contents; - int pageno = 0; - for (auto& page: pdh.getAllPages()) { - ++pageno; - try { - page.coalesceContentStreams(); - page.parseContents(&discard_contents); - page.getImages(); - pldh.getLabelForPage(pageno); - QPDFObjectHandle page_obj(page.getObjectHandle()); - page_obj.getJSON(JSON::LATEST, true).unparse(); - odh.getOutlinesForPage(page_obj); - - for (auto& aoh: afdh.getWidgetAnnotationsForPage(page)) { - afdh.getFieldForAnnotation(aoh); - } - } catch (QPDFExc& e) { - std::cerr << "page " << pageno << ": " << e.what() << '\n'; - } - } -} - -void -FuzzHelper::doChecks() -{ - // Limit the memory used to decompress JPEG files during fuzzing. Excessive memory use during - // fuzzing is due to corrupt JPEG data which sometimes cannot be detected before - // jpeg_start_decompress is called. During normal use of qpdf very large JPEGs can occasionally - // occur legitimately and therefore must be allowed during normal operations. - Pl_DCT::setMemoryLimit(100'000'000); - Pl_DCT::setScanLimit(50); - - Pl_PNGFilter::setMemoryLimit(1'000'000); - Pl_RunLength::setMemoryLimit(1'000'000); - Pl_TIFFPredictor::setMemoryLimit(1'000'000); - Pl_Flate::memory_limit(200'000); - - // Do not decompress corrupt data. This may cause extended runtime within jpeglib without - // exercising additional code paths in qpdf, and potentially causing counterproductive timeouts. - Pl_DCT::setThrowOnCorruptData(true); - - // Get as much coverage as possible in parts of the library that - // might benefit from fuzzing. - std::cerr << "\ninfo: starting testPages\n"; - testPages(); -} - -void -FuzzHelper::run() -{ - // The goal here is that you should be able to throw anything at - // libqpdf and it will respond without any memory errors and never - // do anything worse than throwing a QPDFExc or - // std::runtime_error. Throwing any other kind of exception, - // segfaulting, or having a memory error (when built with - // appropriate sanitizers) will all cause abnormal exit. - try { - doChecks(); - } catch (QPDFExc const& e) { - std::cerr << "QPDFExc: " << e.what() << '\n'; - } catch (std::runtime_error const& e) { - std::cerr << "runtime_error: " << e.what() << '\n'; - } -} - -extern "C" int -LLVMFuzzerTestOneInput(unsigned char const* data, size_t size) -{ -#ifndef _WIN32 - // Used by jpeg library to work around false positives in memory - // sanitizer. - setenv("JSIMD_FORCENONE", "1", 1); -#endif - FuzzHelper f(data, size); - f.run(); - return 0; -} diff --git a/fuzz/qpdf_pages_fuzzer.options b/fuzz/qpdf_pages_fuzzer.options deleted file mode 100644 index a15a774..0000000 --- a/fuzz/qpdf_pages_fuzzer.options +++ /dev/null @@ -1,2 +0,0 @@ -[libfuzzer] -dict = pdf.dict diff --git a/fuzz/qtest/fuzz.test b/fuzz/qtest/fuzz.test index fe7a043..8d1f863 100644 --- a/fuzz/qtest/fuzz.test +++ b/fuzz/qtest/fuzz.test @@ -27,7 +27,7 @@ my @fuzzers = ( ['qpdf_crypt' => $n_qpdf_files], ['qpdf_crypt_insecure' => $n_qpdf_files], ['qpdf_lin' => $n_qpdf_files], - ['qpdf_pages' => $n_qpdf_files], + ['qpdf_page' => $n_qpdf_files], ['qpdf_outlines' => $n_qpdf_files], ); -- libgit2 0.21.4