Commit 2bb9e06d1eb779edfe17f8ce37871ee3b1959211

Authored by m-holger
1 parent bc68003c

In qpdf_fuzzer add a memory limit for Pl_Flate

fuzz/qpdf_fuzzer.cc
... ... @@ -2,6 +2,7 @@
2 2 #include <qpdf/BufferInputSource.hh>
3 3 #include <qpdf/Pl_DCT.hh>
4 4 #include <qpdf/Pl_Discard.hh>
  5 +#include <qpdf/Pl_Flate.hh>
5 6 #include <qpdf/Pl_PNGFilter.hh>
6 7 #include <qpdf/Pl_TIFFPredictor.hh>
7 8 #include <qpdf/QPDF.hh>
... ... @@ -183,6 +184,7 @@ FuzzHelper::doChecks()
183 184  
184 185 Pl_PNGFilter::setMemoryLimit(1'000'000);
185 186 Pl_TIFFPredictor::setMemoryLimit(1'000'000);
  187 + Pl_Flate::setMemoryLimit(10'000'000);
186 188  
187 189 // Do not decompress corrupt data. This may cause extended runtime within jpeglib without
188 190 // exercising additional code paths in qpdf, and potentially causing counterproductive timeouts.
... ...
include/qpdf/Pl_Flate.hh
... ... @@ -42,6 +42,11 @@ class QPDF_DLL_CLASS Pl_Flate: public Pipeline
42 42 QPDF_DLL
43 43 ~Pl_Flate() override;
44 44  
  45 + // Limit the memory used.
  46 + // NB This is a static option affecting all Pl_PNGFilter instances.
  47 + QPDF_DLL
  48 + static void setMemoryLimit(unsigned long long limit);
  49 +
45 50 QPDF_DLL
46 51 void write(unsigned char const* data, size_t len) override;
47 52 QPDF_DLL
... ... @@ -87,6 +92,7 @@ class QPDF_DLL_CLASS Pl_Flate: public Pipeline
87 92 action_e action;
88 93 bool initialized;
89 94 void* zdata;
  95 + unsigned long long written{0};
90 96 std::function<void(char const*, int)> callback;
91 97 };
92 98  
... ...
libqpdf/Pl_Flate.cc
... ... @@ -7,6 +7,11 @@
7 7 #include <qpdf/QIntC.hh>
8 8 #include <qpdf/QUtil.hh>
9 9  
  10 +namespace
  11 +{
  12 + unsigned long long memory_limit{0};
  13 +} // namespace
  14 +
10 15 int Pl_Flate::compression_level = Z_DEFAULT_COMPRESSION;
11 16  
12 17 Pl_Flate::Members::Members(size_t out_bufsize, action_e action) :
... ... @@ -64,6 +69,12 @@ Pl_Flate::~Pl_Flate() // NOLINT (modernize-use-equals-default)
64 69 }
65 70  
66 71 void
  72 +Pl_Flate::setMemoryLimit(unsigned long long limit)
  73 +{
  74 + memory_limit = limit;
  75 +}
  76 +
  77 +void
67 78 Pl_Flate::setWarnCallback(std::function<void(char const*, int)> callback)
68 79 {
69 80 m->callback = callback;
... ... @@ -170,6 +181,12 @@ Pl_Flate::handleData(unsigned char const* data, size_t len, int flush)
170 181 }
171 182 uLong ready = QIntC::to_ulong(m->out_bufsize - zstream.avail_out);
172 183 if (ready > 0) {
  184 + if (memory_limit) {
  185 + m->written += ready;
  186 + if (m->written > memory_limit) {
  187 + throw std::runtime_error("PL_Flate memory limit exceeded");
  188 + }
  189 + }
173 190 this->getNext()->write(m->outbuf.get(), ready);
174 191 zstream.next_out = m->outbuf.get();
175 192 zstream.avail_out = QIntC::to_uint(m->out_bufsize);
... ...