2
1
mirror of https://github.com/qpdf/qpdf.git synced 2024-11-09 23:00:57 +00:00

In qpdf_fuzzer and dct_fuzzer add a scan limit for Pl_DCT

This commit is contained in:
m-holger 2024-08-25 17:02:53 +01:00
parent ef49291682
commit 8ed10d71ea
4 changed files with 30 additions and 0 deletions

View File

@ -31,6 +31,7 @@ FuzzHelper::doChecks()
// 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(200'000'000); Pl_DCT::setMemoryLimit(200'000'000);
Pl_DCT::setScanLimit(50);
// 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.

View File

@ -181,6 +181,7 @@ FuzzHelper::doChecks()
// 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(100'000'000); Pl_DCT::setMemoryLimit(100'000'000);
Pl_DCT::setScanLimit(50);
Pl_PNGFilter::setMemoryLimit(1'000'000); Pl_PNGFilter::setMemoryLimit(1'000'000);
Pl_TIFFPredictor::setMemoryLimit(1'000'000); Pl_TIFFPredictor::setMemoryLimit(1'000'000);

View File

@ -39,6 +39,11 @@ class QPDF_DLL_CLASS Pl_DCT: public Pipeline
QPDF_DLL QPDF_DLL
static void setMemoryLimit(long limit); static void setMemoryLimit(long limit);
// Limit the number of scans used by jpeglib when decompressing progressive jpegs.
// NB This is a static option affecting all Pl_DCT instances.
QPDF_DLL
static void setScanLimit(int limit);
// Treat corrupt data as a runtime error rather than attempting to decompress regardless. This // Treat corrupt data as a runtime error rather than attempting to decompress regardless. This
// is the qpdf default behaviour. To attempt to decompress corrupt data set 'treat_as_error' to // is the qpdf default behaviour. To attempt to decompress corrupt data set 'treat_as_error' to
// false. // false.

View File

@ -22,6 +22,7 @@ namespace
}; };
long memory_limit{0}; long memory_limit{0};
int scan_limit{0};
bool throw_on_corrupt_data{true}; bool throw_on_corrupt_data{true};
} // namespace } // namespace
@ -45,6 +46,17 @@ emit_message(j_common_ptr cinfo, int msg_level)
} }
} }
static void
progress_monitor(j_common_ptr cinfo)
{
if (cinfo->is_decompressor &&
reinterpret_cast<jpeg_decompress_struct*>(cinfo)->input_scan_number > scan_limit) {
auto* jerr = reinterpret_cast<qpdf_jpeg_error_mgr*>(cinfo->err);
jerr->msg = "Pl_DCT::decompress: JPEG data has too many scans";
longjmp(jerr->jmpbuf, 1);
}
}
Pl_DCT::Members::Members() : Pl_DCT::Members::Members() :
action(a_decompress), action(a_decompress),
buf("DCT compressed image") buf("DCT compressed image")
@ -74,6 +86,12 @@ Pl_DCT::setMemoryLimit(long limit)
memory_limit = limit; memory_limit = limit;
} }
void
Pl_DCT::setScanLimit(int limit)
{
scan_limit = limit;
}
void void
Pl_DCT::setThrowOnCorruptData(bool treat_as_error) Pl_DCT::setThrowOnCorruptData(bool treat_as_error)
{ {
@ -341,6 +359,11 @@ Pl_DCT::decompress(void* cinfo_p, Buffer* b)
// first warning is encountered causing a timeout in oss-fuzz. // first warning is encountered causing a timeout in oss-fuzz.
throw std::runtime_error("Pl_DCT::decompress: JPEG data large - may be too slow"); throw std::runtime_error("Pl_DCT::decompress: JPEG data large - may be too slow");
} }
jpeg_progress_mgr progress_mgr;
if (scan_limit > 0) {
progress_mgr.progress_monitor = &progress_monitor;
cinfo->progress = &progress_mgr;
}
JSAMPARRAY buffer = JSAMPARRAY buffer =
(*cinfo->mem->alloc_sarray)(reinterpret_cast<j_common_ptr>(cinfo), JPOOL_IMAGE, width, 1); (*cinfo->mem->alloc_sarray)(reinterpret_cast<j_common_ptr>(cinfo), JPOOL_IMAGE, width, 1);