Commit 732aab86107e17770e1aedc2686411d1aa337839
Committed by
GitHub
Merge pull request #1222 from m-holger/fuzz2
In PL_DCT add option to limit the size of uncompressed corrupt data
Showing
7 changed files
with
63 additions
and
44 deletions
CMakeLists.txt
| ... | ... | @@ -7,7 +7,7 @@ cmake_minimum_required(VERSION 3.16) |
| 7 | 7 | # also find the version number here. generate_auto_job also reads the |
| 8 | 8 | # version from here. |
| 9 | 9 | project(qpdf |
| 10 | - VERSION 11.9.2 | |
| 10 | + VERSION 11.10.0 | |
| 11 | 11 | LANGUAGES C CXX) |
| 12 | 12 | |
| 13 | 13 | # Enable correct rpath handling for MacOSX | ... | ... |
fuzz/dct_fuzzer.cc
include/qpdf/DLL.h
| ... | ... | @@ -25,13 +25,13 @@ |
| 25 | 25 | |
| 26 | 26 | /* The first version of qpdf to include the version constants is 10.6.0. */ |
| 27 | 27 | #define QPDF_MAJOR_VERSION 11 |
| 28 | -#define QPDF_MINOR_VERSION 9 | |
| 29 | -#define QPDF_PATCH_VERSION 2 | |
| 28 | +#define QPDF_MINOR_VERSION 10 | |
| 29 | +#define QPDF_PATCH_VERSION 0 | |
| 30 | 30 | |
| 31 | 31 | #ifdef QPDF_FUTURE |
| 32 | -# define QPDF_VERSION "11.9.2+future" | |
| 32 | +# define QPDF_VERSION "11.10.0+future" | |
| 33 | 33 | #else |
| 34 | -# define QPDF_VERSION "11.9.2" | |
| 34 | +# define QPDF_VERSION "11.10.0" | |
| 35 | 35 | #endif |
| 36 | 36 | |
| 37 | 37 | /* | ... | ... |
include/qpdf/Pl_DCT.hh
| ... | ... | @@ -34,6 +34,11 @@ class QPDF_DLL_CLASS Pl_DCT: public Pipeline |
| 34 | 34 | QPDF_DLL |
| 35 | 35 | Pl_DCT(char const* identifier, Pipeline* next); |
| 36 | 36 | |
| 37 | + // Constructor for decompressing image data. If corrupt_data_limit is non-zero and the data is | |
| 38 | + // corrupt, only attempt to uncompress if the uncompressed size is less than corrupt_data_limit. | |
| 39 | + QPDF_DLL | |
| 40 | + Pl_DCT(char const* identifier, Pipeline* next, size_t corrupt_data_limit); | |
| 41 | + | |
| 37 | 42 | class QPDF_DLL_CLASS CompressConfig |
| 38 | 43 | { |
| 39 | 44 | public: |
| ... | ... | @@ -80,26 +85,30 @@ class QPDF_DLL_CLASS Pl_DCT: public Pipeline |
| 80 | 85 | ~Members() = default; |
| 81 | 86 | |
| 82 | 87 | private: |
| 88 | + // For compression | |
| 83 | 89 | Members( |
| 84 | - action_e action, | |
| 85 | - char const* buf_description, | |
| 86 | - JDIMENSION image_width = 0, | |
| 87 | - JDIMENSION image_height = 0, | |
| 88 | - int components = 1, | |
| 89 | - J_COLOR_SPACE color_space = JCS_GRAYSCALE, | |
| 90 | - CompressConfig* config_callback = nullptr); | |
| 90 | + JDIMENSION image_width, | |
| 91 | + JDIMENSION image_height, | |
| 92 | + int components, | |
| 93 | + J_COLOR_SPACE color_space, | |
| 94 | + CompressConfig* config_callback); | |
| 95 | + // For decompression | |
| 96 | + Members(size_t corrupt_data_limit); | |
| 91 | 97 | Members(Members const&) = delete; |
| 92 | 98 | |
| 93 | 99 | action_e action; |
| 94 | 100 | Pl_Buffer buf; |
| 95 | 101 | |
| 102 | + // Used for decompression | |
| 103 | + size_t corrupt_data_limit{0}; | |
| 104 | + | |
| 96 | 105 | // Used for compression |
| 97 | - JDIMENSION image_width; | |
| 98 | - JDIMENSION image_height; | |
| 99 | - int components; | |
| 100 | - J_COLOR_SPACE color_space; | |
| 106 | + JDIMENSION image_width{0}; | |
| 107 | + JDIMENSION image_height{0}; | |
| 108 | + int components{1}; | |
| 109 | + J_COLOR_SPACE color_space{JCS_GRAYSCALE}; | |
| 101 | 110 | |
| 102 | - CompressConfig* config_callback; | |
| 111 | + CompressConfig* config_callback{nullptr}; | |
| 103 | 112 | }; |
| 104 | 113 | |
| 105 | 114 | std::shared_ptr<Members> m; | ... | ... |
job.sums
| 1 | 1 | # Generated by generate_auto_job |
| 2 | -CMakeLists.txt 085e7290a43f2cc0cbac31aeab0a571731f4c26be25a243c458d93881ef8fc3d | |
| 2 | +CMakeLists.txt 47752f33b17fa526d46fc608a25ad6b8c61feba9deb1bd659fddf93e6e08b102 | |
| 3 | 3 | generate_auto_job f64733b79dcee5a0e3e8ccc6976448e8ddf0e8b6529987a66a7d3ab2ebc10a86 |
| 4 | 4 | include/qpdf/auto_job_c_att.hh 4c2b171ea00531db54720bf49a43f8b34481586ae7fb6cbf225099ee42bc5bb4 |
| 5 | 5 | include/qpdf/auto_job_c_copy_att.hh 50609012bff14fd82f0649185940d617d05d530cdc522185c7f3920a561ccb42 |
| ... | ... | @@ -16,5 +16,5 @@ libqpdf/qpdf/auto_job_json_init.hh a87256c082427ec0318223762472970b2eced535c0c8b |
| 16 | 16 | libqpdf/qpdf/auto_job_schema.hh 5dac568dff39614e161a0af59a0f328f1e28edf69b96f08bb76fd592d51bb053 |
| 17 | 17 | manual/_ext/qpdf.py 6add6321666031d55ed4aedf7c00e5662bba856dfcd66ccb526563bffefbb580 |
| 18 | 18 | manual/cli.rst 94057baba9ecffb4ce19ae61c8fa507ef07209c280fccae97b283c3dfce834e0 |
| 19 | -manual/qpdf.1 f39379c4921f4c22ba4a2ab28dcda8b1898347b149032de603fd423cbde56fe4 | |
| 19 | +manual/qpdf.1 0ec05f1392c160165cdf6adada4de84c0de75bd2fb5762caff4e1372aacada4c | |
| 20 | 20 | manual/qpdf.1.in 436ecc85d45c4c9e2dbd1725fb7f0177fb627179469f114561adf3cb6cbb677b | ... | ... |
libqpdf/Pl_DCT.cc
| 1 | 1 | #include <qpdf/Pl_DCT.hh> |
| 2 | 2 | |
| 3 | +#include "qpdf/QPDFLogger.hh" | |
| 3 | 4 | #include <qpdf/QIntC.hh> |
| 4 | 5 | #include <qpdf/QTC.hh> |
| 5 | 6 | |
| ... | ... | @@ -31,16 +32,21 @@ error_handler(j_common_ptr cinfo) |
| 31 | 32 | longjmp(jerr->jmpbuf, 1); |
| 32 | 33 | } |
| 33 | 34 | |
| 35 | +Pl_DCT::Members::Members(size_t corrupt_data_limit) : | |
| 36 | + action(a_decompress), | |
| 37 | + buf("DCT compressed image"), | |
| 38 | + corrupt_data_limit(corrupt_data_limit) | |
| 39 | +{ | |
| 40 | +} | |
| 41 | + | |
| 34 | 42 | Pl_DCT::Members::Members( |
| 35 | - action_e action, | |
| 36 | - char const* buf_description, | |
| 37 | 43 | JDIMENSION image_width, |
| 38 | 44 | JDIMENSION image_height, |
| 39 | 45 | int components, |
| 40 | 46 | J_COLOR_SPACE color_space, |
| 41 | 47 | CompressConfig* config_callback) : |
| 42 | - action(action), | |
| 43 | - buf(buf_description), | |
| 48 | + action(a_compress), | |
| 49 | + buf("DCT uncompressed image"), | |
| 44 | 50 | image_width(image_width), |
| 45 | 51 | image_height(image_height), |
| 46 | 52 | components(components), |
| ... | ... | @@ -50,8 +56,13 @@ Pl_DCT::Members::Members( |
| 50 | 56 | } |
| 51 | 57 | |
| 52 | 58 | Pl_DCT::Pl_DCT(char const* identifier, Pipeline* next) : |
| 59 | + Pl_DCT(identifier, next, 0) | |
| 60 | +{ | |
| 61 | +} | |
| 62 | + | |
| 63 | +Pl_DCT::Pl_DCT(char const* identifier, Pipeline* next, size_t corrupt_data_limit) : | |
| 53 | 64 | Pipeline(identifier, next), |
| 54 | - m(new Members(a_decompress, "DCT compressed image")) | |
| 65 | + m(new Members(corrupt_data_limit)) | |
| 55 | 66 | { |
| 56 | 67 | } |
| 57 | 68 | |
| ... | ... | @@ -64,14 +75,7 @@ Pl_DCT::Pl_DCT( |
| 64 | 75 | J_COLOR_SPACE color_space, |
| 65 | 76 | CompressConfig* config_callback) : |
| 66 | 77 | Pipeline(identifier, next), |
| 67 | - m(new Members( | |
| 68 | - a_compress, | |
| 69 | - "DCT uncompressed image", | |
| 70 | - image_width, | |
| 71 | - image_height, | |
| 72 | - components, | |
| 73 | - color_space, | |
| 74 | - config_callback)) | |
| 78 | + m(new Members(image_width, image_height, components, color_space, config_callback)) | |
| 75 | 79 | { |
| 76 | 80 | } |
| 77 | 81 | |
| ... | ... | @@ -311,16 +315,22 @@ Pl_DCT::decompress(void* cinfo_p, Buffer* b) |
| 311 | 315 | |
| 312 | 316 | (void)jpeg_read_header(cinfo, TRUE); |
| 313 | 317 | (void)jpeg_calc_output_dimensions(cinfo); |
| 314 | - | |
| 315 | 318 | unsigned int width = cinfo->output_width * QIntC::to_uint(cinfo->output_components); |
| 316 | - JSAMPARRAY buffer = | |
| 317 | - (*cinfo->mem->alloc_sarray)(reinterpret_cast<j_common_ptr>(cinfo), JPOOL_IMAGE, width, 1); | |
| 318 | - | |
| 319 | - (void)jpeg_start_decompress(cinfo); | |
| 320 | - while (cinfo->output_scanline < cinfo->output_height) { | |
| 321 | - (void)jpeg_read_scanlines(cinfo, buffer, 1); | |
| 322 | - this->getNext()->write(buffer[0], width * sizeof(buffer[0][0])); | |
| 319 | + if (cinfo->err->num_warnings == 0 || m->corrupt_data_limit == 0 || | |
| 320 | + (width * QIntC::to_uint(cinfo->output_height)) < m->corrupt_data_limit) { | |
| 321 | + // err->num_warnings is the number of corrupt data warnings emitted. | |
| 322 | + // err->msg_code could also be the code of an informational message. | |
| 323 | + JSAMPARRAY buffer = (*cinfo->mem->alloc_sarray)( | |
| 324 | + reinterpret_cast<j_common_ptr>(cinfo), JPOOL_IMAGE, width, 1); | |
| 325 | + | |
| 326 | + (void)jpeg_start_decompress(cinfo); | |
| 327 | + while (cinfo->output_scanline < cinfo->output_height) { | |
| 328 | + (void)jpeg_read_scanlines(cinfo, buffer, 1); | |
| 329 | + getNext()->write(buffer[0], width * sizeof(buffer[0][0])); | |
| 330 | + } | |
| 331 | + (void)jpeg_finish_decompress(cinfo); | |
| 332 | + } else { | |
| 333 | + *QPDFLogger::defaultLogger()->getError() << "corrupt JPEG data ignored" << "\n"; | |
| 323 | 334 | } |
| 324 | - (void)jpeg_finish_decompress(cinfo); | |
| 325 | - this->getNext()->finish(); | |
| 335 | + getNext()->finish(); | |
| 326 | 336 | } | ... | ... |
manual/qpdf.1
| ... | ... | @@ -3,7 +3,7 @@ |
| 3 | 3 | .\" Edits will be automatically overwritten if the build is |
| 4 | 4 | .\" run in maintainer mode. |
| 5 | 5 | .\" |
| 6 | -.TH QPDF "1" "" "qpdf version 11.9.2" "User Commands" | |
| 6 | +.TH QPDF "1" "" "qpdf version 11.10.0" "User Commands" | |
| 7 | 7 | .SH NAME |
| 8 | 8 | qpdf \- PDF transformation software |
| 9 | 9 | .SH SYNOPSIS | ... | ... |