2
1
mirror of https://github.com/qpdf/qpdf.git synced 2024-12-22 19:08:59 +00:00

Merge pull request #1258 from m-holger/fuzz

Adjust fuzzer memory limits and refactor Pl_RunLength::decode
This commit is contained in:
m-holger 2024-08-04 00:28:50 +01:00 committed by GitHub
commit 2856b288e4
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
8 changed files with 16 additions and 11 deletions

View File

@ -100,6 +100,7 @@ set(CORPUS_OTHER
16953.fuzz 16953.fuzz
17630.fuzz 17630.fuzz
17630a.fuzz 17630a.fuzz
17630b.fuzz
18241.fuzz 18241.fuzz
18247.fuzz 18247.fuzz
23172.fuzz 23172.fuzz
@ -128,6 +129,7 @@ set(CORPUS_OTHER
69977b.fuzz 69977b.fuzz
69977c.fuzz 69977c.fuzz
69977d.fuzz 69977d.fuzz
69977e.fuzz
70055.fuzz 70055.fuzz
70245.fuzz 70245.fuzz
70306.fuzz 70306.fuzz

View File

@ -30,7 +30,7 @@ FuzzHelper::doChecks()
// fuzzing is due to corrupt JPEG data which sometimes cannot be detected before // 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 // 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. // occur legitimately and therefore must be allowed during normal operations.
Pl_DCT::setMemoryLimit(1'000'000'000); Pl_DCT::setMemoryLimit(200'000'000);
// Do not decompress corrupt data. This may cause extended runtime within jpeglib without // Do not decompress corrupt data. This may cause extended runtime within jpeglib without
// exercising additional code paths in qpdf. // exercising additional code paths in qpdf.

BIN
fuzz/qpdf_extra/17630b.fuzz Normal file

Binary file not shown.

BIN
fuzz/qpdf_extra/69977e.fuzz Normal file

Binary file not shown.

View File

@ -180,11 +180,11 @@ FuzzHelper::doChecks()
// fuzzing is due to corrupt JPEG data which sometimes cannot be detected before // 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 // 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. // occur legitimately and therefore must be allowed during normal operations.
Pl_DCT::setMemoryLimit(1'000'000'000); Pl_DCT::setMemoryLimit(100'000'000);
Pl_PNGFilter::setMemoryLimit(1'000'000); Pl_PNGFilter::setMemoryLimit(1'000'000);
Pl_TIFFPredictor::setMemoryLimit(1'000'000); Pl_TIFFPredictor::setMemoryLimit(1'000'000);
Pl_Flate::setMemoryLimit(10'000'000); Pl_Flate::setMemoryLimit(1'000'000);
// Do not decompress corrupt data. This may cause extended runtime within jpeglib without // Do not decompress corrupt data. This may cause extended runtime within jpeglib without
// exercising additional code paths in qpdf, and potentially causing counterproductive timeouts. // exercising additional code paths in qpdf, and potentially causing counterproductive timeouts.

View File

@ -21,7 +21,7 @@ my @fuzzers = (
['pngpredictor' => 1], ['pngpredictor' => 1],
['runlength' => 6], ['runlength' => 6],
['tiffpredictor' => 2], ['tiffpredictor' => 2],
['qpdf' => 73], # increment when adding new files ['qpdf' => 75], # increment when adding new files
); );
my $n_tests = 0; my $n_tests = 0;

View File

@ -62,6 +62,7 @@ class QPDF_DLL_CLASS Pl_RunLength: public Pipeline
state_e state; state_e state;
unsigned char buf[128]; unsigned char buf[128];
unsigned int length; unsigned int length;
std::string out;
}; };
std::shared_ptr<Members> m; std::shared_ptr<Members> m;

View File

@ -66,8 +66,9 @@ Pl_RunLength::encode(unsigned char const* data, size_t len)
void void
Pl_RunLength::decode(unsigned char const* data, size_t len) Pl_RunLength::decode(unsigned char const* data, size_t len)
{ {
m->out.reserve(len);
for (size_t i = 0; i < len; ++i) { for (size_t i = 0; i < len; ++i) {
unsigned char ch = data[i]; unsigned char const& ch = data[i];
switch (m->state) { switch (m->state) {
case st_top: case st_top:
if (ch < 128) { if (ch < 128) {
@ -85,16 +86,14 @@ Pl_RunLength::decode(unsigned char const* data, size_t len)
break; break;
case st_copying: case st_copying:
this->getNext()->write(&ch, 1); m->out.append(1, static_cast<char>(ch));
if (--m->length == 0) { if (--m->length == 0) {
m->state = st_top; m->state = st_top;
} }
break; break;
case st_run: case st_run:
for (unsigned int j = 0; j < m->length; ++j) { m->out.append(m->length, static_cast<char>(ch));
this->getNext()->write(&ch, 1);
}
m->state = st_top; m->state = st_top;
break; break;
} }
@ -137,10 +136,13 @@ Pl_RunLength::finish()
// When decoding, we might have read a length byte not followed by data, which means the stream // When decoding, we might have read a length byte not followed by data, which means the stream
// was terminated early, but we will just ignore this case since this is the only sensible thing // was terminated early, but we will just ignore this case since this is the only sensible thing
// to do. // to do.
auto next = getNext();
if (m->action == a_encode) { if (m->action == a_encode) {
flush_encode(); flush_encode();
unsigned char ch = 128; unsigned char ch = 128;
this->getNext()->write(&ch, 1); next->write(&ch, 1);
} else {
next->writeString(m->out);
} }
this->getNext()->finish(); next->finish();
} }