Commit f5cac93ac63559ddc0aec1b1c61c9e2503c7b8e0
Committed by
GitHub
Merge pull request #1349 from m-holger/fuzz
Fix bugs found during fuzzing
Showing
17 changed files
with
44 additions
and
4 deletions
fuzz/CMakeLists.txt
| ... | ... | @@ -147,10 +147,13 @@ set(CORPUS_OTHER |
| 147 | 147 | 369662293.fuzz |
| 148 | 148 | 369662293a.fuzz |
| 149 | 149 | 376305073.fuzz |
| 150 | + 376305073a.fuzz | |
| 150 | 151 | 377977949.fuzz |
| 152 | + 388571629.fuzz | |
| 151 | 153 | 389339260.fuzz |
| 152 | 154 | 389974979.fuzz |
| 153 | 155 | 391974927.fuzz |
| 156 | + 394129398.fuzz | |
| 154 | 157 | ) |
| 155 | 158 | |
| 156 | 159 | set(CORPUS_DIR ${CMAKE_CURRENT_BINARY_DIR}/qpdf_corpus) | ... | ... |
fuzz/qpdf_crypt_fuzzer.cc
| ... | ... | @@ -4,6 +4,7 @@ |
| 4 | 4 | #include <qpdf/Pl_Discard.hh> |
| 5 | 5 | #include <qpdf/Pl_Flate.hh> |
| 6 | 6 | #include <qpdf/Pl_PNGFilter.hh> |
| 7 | +#include <qpdf/Pl_RunLength.hh> | |
| 7 | 8 | #include <qpdf/Pl_TIFFPredictor.hh> |
| 8 | 9 | #include <qpdf/QPDF.hh> |
| 9 | 10 | #include <qpdf/QPDFPageObjectHelper.hh> |
| ... | ... | @@ -108,6 +109,7 @@ FuzzHelper::doChecks() |
| 108 | 109 | Pl_DCT::setScanLimit(50); |
| 109 | 110 | |
| 110 | 111 | Pl_PNGFilter::setMemoryLimit(1'000'000); |
| 112 | + Pl_RunLength::setMemoryLimit(1'000'000); | |
| 111 | 113 | Pl_TIFFPredictor::setMemoryLimit(1'000'000); |
| 112 | 114 | Pl_Flate::setMemoryLimit(200'000); |
| 113 | 115 | ... | ... |
fuzz/qpdf_crypt_insecure_fuzzer.cc
| ... | ... | @@ -4,6 +4,7 @@ |
| 4 | 4 | #include <qpdf/Pl_Discard.hh> |
| 5 | 5 | #include <qpdf/Pl_Flate.hh> |
| 6 | 6 | #include <qpdf/Pl_PNGFilter.hh> |
| 7 | +#include <qpdf/Pl_RunLength.hh> | |
| 7 | 8 | #include <qpdf/Pl_TIFFPredictor.hh> |
| 8 | 9 | #include <qpdf/QPDF.hh> |
| 9 | 10 | #include <qpdf/QPDFPageObjectHelper.hh> |
| ... | ... | @@ -108,6 +109,7 @@ FuzzHelper::doChecks() |
| 108 | 109 | Pl_DCT::setScanLimit(50); |
| 109 | 110 | |
| 110 | 111 | Pl_PNGFilter::setMemoryLimit(1'000'000); |
| 112 | + Pl_RunLength::setMemoryLimit(1'000'000); | |
| 111 | 113 | Pl_TIFFPredictor::setMemoryLimit(1'000'000); |
| 112 | 114 | Pl_Flate::setMemoryLimit(200'000); |
| 113 | 115 | ... | ... |
fuzz/qpdf_extra/376305073a.fuzz
0 โ 100644
No preview for this file type
fuzz/qpdf_extra/388571629.fuzz
0 โ 100644
No preview for this file type
fuzz/qpdf_extra/394129398.fuzz
0 โ 100644
No preview for this file type
fuzz/qpdf_fuzzer.cc
| ... | ... | @@ -4,6 +4,7 @@ |
| 4 | 4 | #include <qpdf/Pl_Discard.hh> |
| 5 | 5 | #include <qpdf/Pl_Flate.hh> |
| 6 | 6 | #include <qpdf/Pl_PNGFilter.hh> |
| 7 | +#include <qpdf/Pl_RunLength.hh> | |
| 7 | 8 | #include <qpdf/Pl_TIFFPredictor.hh> |
| 8 | 9 | #include <qpdf/QPDF.hh> |
| 9 | 10 | #include <qpdf/QPDFPageObjectHelper.hh> |
| ... | ... | @@ -106,6 +107,7 @@ FuzzHelper::doChecks() |
| 106 | 107 | Pl_DCT::setScanLimit(50); |
| 107 | 108 | |
| 108 | 109 | Pl_PNGFilter::setMemoryLimit(1'000'000); |
| 110 | + Pl_RunLength::setMemoryLimit(1'000'000); | |
| 109 | 111 | Pl_TIFFPredictor::setMemoryLimit(1'000'000); |
| 110 | 112 | Pl_Flate::setMemoryLimit(200'000); |
| 111 | 113 | ... | ... |
fuzz/qpdf_lin_fuzzer.cc
| ... | ... | @@ -4,6 +4,7 @@ |
| 4 | 4 | #include <qpdf/Pl_Discard.hh> |
| 5 | 5 | #include <qpdf/Pl_Flate.hh> |
| 6 | 6 | #include <qpdf/Pl_PNGFilter.hh> |
| 7 | +#include <qpdf/Pl_RunLength.hh> | |
| 7 | 8 | #include <qpdf/Pl_TIFFPredictor.hh> |
| 8 | 9 | #include <qpdf/QPDF.hh> |
| 9 | 10 | #include <qpdf/QPDFPageObjectHelper.hh> |
| ... | ... | @@ -107,6 +108,7 @@ FuzzHelper::doChecks() |
| 107 | 108 | Pl_DCT::setScanLimit(50); |
| 108 | 109 | |
| 109 | 110 | Pl_PNGFilter::setMemoryLimit(1'000'000); |
| 111 | + Pl_RunLength::setMemoryLimit(1'000'000); | |
| 110 | 112 | Pl_TIFFPredictor::setMemoryLimit(1'000'000); |
| 111 | 113 | Pl_Flate::setMemoryLimit(200'000); |
| 112 | 114 | ... | ... |
fuzz/qpdf_outlines_fuzzer.cc
| ... | ... | @@ -4,6 +4,7 @@ |
| 4 | 4 | #include <qpdf/Pl_Discard.hh> |
| 5 | 5 | #include <qpdf/Pl_Flate.hh> |
| 6 | 6 | #include <qpdf/Pl_PNGFilter.hh> |
| 7 | +#include <qpdf/Pl_RunLength.hh> | |
| 7 | 8 | #include <qpdf/Pl_TIFFPredictor.hh> |
| 8 | 9 | #include <qpdf/QPDF.hh> |
| 9 | 10 | #include <qpdf/QPDFOutlineDocumentHelper.hh> |
| ... | ... | @@ -84,6 +85,7 @@ FuzzHelper::doChecks() |
| 84 | 85 | Pl_DCT::setScanLimit(50); |
| 85 | 86 | |
| 86 | 87 | Pl_PNGFilter::setMemoryLimit(1'000'000); |
| 88 | + Pl_RunLength::setMemoryLimit(1'000'000); | |
| 87 | 89 | Pl_TIFFPredictor::setMemoryLimit(1'000'000); |
| 88 | 90 | Pl_Flate::setMemoryLimit(200'000); |
| 89 | 91 | ... | ... |
fuzz/qpdf_pages_fuzzer.cc
| ... | ... | @@ -4,6 +4,7 @@ |
| 4 | 4 | #include <qpdf/Pl_Discard.hh> |
| 5 | 5 | #include <qpdf/Pl_Flate.hh> |
| 6 | 6 | #include <qpdf/Pl_PNGFilter.hh> |
| 7 | +#include <qpdf/Pl_RunLength.hh> | |
| 7 | 8 | #include <qpdf/Pl_TIFFPredictor.hh> |
| 8 | 9 | #include <qpdf/QPDF.hh> |
| 9 | 10 | #include <qpdf/QPDFAcroFormDocumentHelper.hh> |
| ... | ... | @@ -105,6 +106,7 @@ FuzzHelper::doChecks() |
| 105 | 106 | Pl_DCT::setScanLimit(50); |
| 106 | 107 | |
| 107 | 108 | Pl_PNGFilter::setMemoryLimit(1'000'000); |
| 109 | + Pl_RunLength::setMemoryLimit(1'000'000); | |
| 108 | 110 | Pl_TIFFPredictor::setMemoryLimit(1'000'000); |
| 109 | 111 | Pl_Flate::setMemoryLimit(200'000); |
| 110 | 112 | ... | ... |
fuzz/qtest/fuzz.test
| ... | ... | @@ -11,7 +11,7 @@ my $td = new TestDriver('fuzz'); |
| 11 | 11 | |
| 12 | 12 | my $qpdf_corpus = $ENV{'QPDF_FUZZ_CORPUS'} || die "must set QPDF_FUZZ_CORPUS"; |
| 13 | 13 | |
| 14 | -my $n_qpdf_files = 88; # increment when adding new files | |
| 14 | +my $n_qpdf_files = 91; # increment when adding new files | |
| 15 | 15 | |
| 16 | 16 | my @fuzzers = ( |
| 17 | 17 | ['ascii85' => 1], | ... | ... |
fuzz/runlength_fuzzer.cc
| ... | ... | @@ -25,6 +25,7 @@ FuzzHelper::FuzzHelper(unsigned char const* data, size_t size) : |
| 25 | 25 | void |
| 26 | 26 | FuzzHelper::doChecks() |
| 27 | 27 | { |
| 28 | + Pl_RunLength::setMemoryLimit(1'000'000); | |
| 28 | 29 | Pl_Discard discard; |
| 29 | 30 | Pl_RunLength p("decode", &discard, Pl_RunLength::a_decode); |
| 30 | 31 | p.write(const_cast<unsigned char*>(data), size); | ... | ... |
include/qpdf/Pl_Flate.hh
| ... | ... | @@ -46,7 +46,7 @@ class QPDF_DLL_CLASS Pl_Flate: public Pipeline |
| 46 | 46 | ~Pl_Flate() override; |
| 47 | 47 | |
| 48 | 48 | // Limit the memory used. |
| 49 | - // NB This is a static option affecting all Pl_PNGFilter instances. | |
| 49 | + // NB This is a static option affecting all Pl_Flate instances. | |
| 50 | 50 | QPDF_DLL |
| 51 | 51 | static void setMemoryLimit(unsigned long long limit); |
| 52 | 52 | ... | ... |
include/qpdf/Pl_RunLength.hh
| ... | ... | @@ -32,6 +32,11 @@ class QPDF_DLL_CLASS Pl_RunLength: public Pipeline |
| 32 | 32 | QPDF_DLL |
| 33 | 33 | ~Pl_RunLength() override; |
| 34 | 34 | |
| 35 | + // Limit the memory used. | |
| 36 | + // NB This is a static option affecting all Pl_RunLength instances. | |
| 37 | + QPDF_DLL | |
| 38 | + static void setMemoryLimit(unsigned long long limit); | |
| 39 | + | |
| 35 | 40 | QPDF_DLL |
| 36 | 41 | void write(unsigned char const* data, size_t len) override; |
| 37 | 42 | QPDF_DLL | ... | ... |
libqpdf/Pl_RunLength.cc
| ... | ... | @@ -3,6 +3,11 @@ |
| 3 | 3 | #include <qpdf/QTC.hh> |
| 4 | 4 | #include <qpdf/QUtil.hh> |
| 5 | 5 | |
| 6 | +namespace | |
| 7 | +{ | |
| 8 | + unsigned long long memory_limit{0}; | |
| 9 | +} // namespace | |
| 10 | + | |
| 6 | 11 | Pl_RunLength::Members::Members(action_e action) : |
| 7 | 12 | action(action) |
| 8 | 13 | { |
| ... | ... | @@ -17,6 +22,12 @@ Pl_RunLength::Pl_RunLength(char const* identifier, Pipeline* next, action_e acti |
| 17 | 22 | } |
| 18 | 23 | } |
| 19 | 24 | |
| 25 | +void | |
| 26 | +Pl_RunLength::setMemoryLimit(unsigned long long limit) | |
| 27 | +{ | |
| 28 | + memory_limit = limit; | |
| 29 | +} | |
| 30 | + | |
| 20 | 31 | Pl_RunLength::~Pl_RunLength() // NOLINT (modernize-use-equals-default) |
| 21 | 32 | { |
| 22 | 33 | // Must be explicit and not inline -- see QPDF_DLL_CLASS in README-maintainer |
| ... | ... | @@ -67,6 +78,9 @@ Pl_RunLength::encode(unsigned char const* data, size_t len) |
| 67 | 78 | void |
| 68 | 79 | Pl_RunLength::decode(unsigned char const* data, size_t len) |
| 69 | 80 | { |
| 81 | + if (memory_limit && (len + m->out.size()) > memory_limit) { | |
| 82 | + throw std::runtime_error("Pl_RunLength memory limit exceeded"); | |
| 83 | + } | |
| 70 | 84 | m->out.reserve(len); |
| 71 | 85 | for (size_t i = 0; i < len; ++i) { |
| 72 | 86 | unsigned char const& ch = data[i]; | ... | ... |
libqpdf/QPDFParser.cc
| ... | ... | @@ -470,6 +470,11 @@ bool |
| 470 | 470 | QPDFParser::tooManyBadTokens() |
| 471 | 471 | { |
| 472 | 472 | if (--max_bad_count > 0 && good_count > 4) { |
| 473 | + if (frame->olist.size() > 100'000 || frame->dict.size() > 100'000) { | |
| 474 | + warn("encountered errors while parsing an array or dictionary with more than 100000 " | |
| 475 | + "elements; giving up on reading object"); | |
| 476 | + return true; | |
| 477 | + } | |
| 473 | 478 | good_count = 0; |
| 474 | 479 | bad_count = 1; |
| 475 | 480 | return false; | ... | ... |
libqpdf/QPDFWriter.cc
| ... | ... | @@ -1877,8 +1877,8 @@ QPDFWriter::generateID() |
| 1877 | 1877 | if (m->deterministic_id_data.empty()) { |
| 1878 | 1878 | QTC::TC("qpdf", "QPDFWriter deterministic with no data"); |
| 1879 | 1879 | throw std::runtime_error("INTERNAL ERROR: QPDFWriter::generateID has no data for " |
| 1880 | - "deterministic ID. This may happen if deterministic ID and " | |
| 1881 | - "file encryption are requested together."); | |
| 1880 | + "deterministic ID. This may happen if deterministic ID " | |
| 1881 | + "and file encryption are requested together."); | |
| 1882 | 1882 | } |
| 1883 | 1883 | seed += m->deterministic_id_data; |
| 1884 | 1884 | } else { | ... | ... |