2
1
mirror of https://github.com/qpdf/qpdf.git synced 2024-12-22 10:58:58 +00:00

In PL_DCT add option to limit the size of uncompressed corrupt data

Also, apply limit in dct_fuzzer
This commit is contained in:
m-holger 2024-06-26 11:23:15 +01:00
parent 3468ce362d
commit d83cf43811
3 changed files with 55 additions and 36 deletions

View File

@ -27,7 +27,7 @@ void
FuzzHelper::doChecks()
{
Pl_Discard discard;
Pl_DCT p("decode", &discard);
Pl_DCT p("decode", &discard, 20'000'000);
p.write(const_cast<unsigned char*>(data), size);
p.finish();
}

View File

@ -34,6 +34,11 @@ class QPDF_DLL_CLASS Pl_DCT: public Pipeline
QPDF_DLL
Pl_DCT(char const* identifier, Pipeline* next);
// Constructor for decompressing image data. If corrupt_data_limit is non-zero and the data is
// corrupt, only attempt to uncompress if the uncompressed size is less than corrupt_data_limit.
QPDF_DLL
Pl_DCT(char const* identifier, Pipeline* next, size_t corrupt_data_limit);
class QPDF_DLL_CLASS CompressConfig
{
public:
@ -80,26 +85,30 @@ class QPDF_DLL_CLASS Pl_DCT: public Pipeline
~Members() = default;
private:
// For compression
Members(
action_e action,
char const* buf_description,
JDIMENSION image_width = 0,
JDIMENSION image_height = 0,
int components = 1,
J_COLOR_SPACE color_space = JCS_GRAYSCALE,
CompressConfig* config_callback = nullptr);
JDIMENSION image_width,
JDIMENSION image_height,
int components,
J_COLOR_SPACE color_space,
CompressConfig* config_callback);
// For decompression
Members(size_t corrupt_data_limit);
Members(Members const&) = delete;
action_e action;
Pl_Buffer buf;
// Used for compression
JDIMENSION image_width;
JDIMENSION image_height;
int components;
J_COLOR_SPACE color_space;
// Used for decompression
size_t corrupt_data_limit{0};
CompressConfig* config_callback;
// Used for compression
JDIMENSION image_width{0};
JDIMENSION image_height{0};
int components{1};
J_COLOR_SPACE color_space{JCS_GRAYSCALE};
CompressConfig* config_callback{nullptr};
};
std::shared_ptr<Members> m;

View File

@ -1,5 +1,6 @@
#include <qpdf/Pl_DCT.hh>
#include "qpdf/QPDFLogger.hh"
#include <qpdf/QIntC.hh>
#include <qpdf/QTC.hh>
@ -31,16 +32,21 @@ error_handler(j_common_ptr cinfo)
longjmp(jerr->jmpbuf, 1);
}
Pl_DCT::Members::Members(size_t corrupt_data_limit) :
action(a_decompress),
buf("DCT compressed image"),
corrupt_data_limit(corrupt_data_limit)
{
}
Pl_DCT::Members::Members(
action_e action,
char const* buf_description,
JDIMENSION image_width,
JDIMENSION image_height,
int components,
J_COLOR_SPACE color_space,
CompressConfig* config_callback) :
action(action),
buf(buf_description),
action(a_compress),
buf("DCT uncompressed image"),
image_width(image_width),
image_height(image_height),
components(components),
@ -50,8 +56,13 @@ Pl_DCT::Members::Members(
}
Pl_DCT::Pl_DCT(char const* identifier, Pipeline* next) :
Pl_DCT(identifier, next, 0)
{
}
Pl_DCT::Pl_DCT(char const* identifier, Pipeline* next, size_t corrupt_data_limit) :
Pipeline(identifier, next),
m(new Members(a_decompress, "DCT compressed image"))
m(new Members(corrupt_data_limit))
{
}
@ -64,14 +75,7 @@ Pl_DCT::Pl_DCT(
J_COLOR_SPACE color_space,
CompressConfig* config_callback) :
Pipeline(identifier, next),
m(new Members(
a_compress,
"DCT uncompressed image",
image_width,
image_height,
components,
color_space,
config_callback))
m(new Members(image_width, image_height, components, color_space, config_callback))
{
}
@ -311,16 +315,22 @@ Pl_DCT::decompress(void* cinfo_p, Buffer* b)
(void)jpeg_read_header(cinfo, TRUE);
(void)jpeg_calc_output_dimensions(cinfo);
unsigned int width = cinfo->output_width * QIntC::to_uint(cinfo->output_components);
JSAMPARRAY buffer =
(*cinfo->mem->alloc_sarray)(reinterpret_cast<j_common_ptr>(cinfo), JPOOL_IMAGE, width, 1);
if (cinfo->err->num_warnings == 0 || m->corrupt_data_limit == 0 ||
(width * QIntC::to_uint(cinfo->output_height)) < m->corrupt_data_limit) {
// err->num_warnings is the number of corrupt data warnings emitted.
// err->msg_code could also be the code of an informational message.
JSAMPARRAY buffer = (*cinfo->mem->alloc_sarray)(
reinterpret_cast<j_common_ptr>(cinfo), JPOOL_IMAGE, width, 1);
(void)jpeg_start_decompress(cinfo);
while (cinfo->output_scanline < cinfo->output_height) {
(void)jpeg_read_scanlines(cinfo, buffer, 1);
this->getNext()->write(buffer[0], width * sizeof(buffer[0][0]));
(void)jpeg_start_decompress(cinfo);
while (cinfo->output_scanline < cinfo->output_height) {
(void)jpeg_read_scanlines(cinfo, buffer, 1);
getNext()->write(buffer[0], width * sizeof(buffer[0][0]));
}
(void)jpeg_finish_decompress(cinfo);
} else {
*QPDFLogger::defaultLogger()->getError() << "corrupt JPEG data ignored" << "\n";
}
(void)jpeg_finish_decompress(cinfo);
this->getNext()->finish();
getNext()->finish();
}