1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141
|
#include <qpdf/Buffer.hh>
#include <qpdf/BufferInputSource.hh>
#include <qpdf/Pl_DCT.hh>
#include <qpdf/Pl_Discard.hh>
#include <qpdf/Pl_Flate.hh>
#include <qpdf/Pl_PNGFilter.hh>
#include <qpdf/Pl_RunLength.hh>
#include <qpdf/Pl_TIFFPredictor.hh>
#include <qpdf/QPDF.hh>
#include <qpdf/QPDFPageObjectHelper.hh>
#include <qpdf/QPDFWriter.hh>
#include <qpdf/QUtil.hh>
#include <cstdlib>
class FuzzHelper
{
public:
FuzzHelper(unsigned char const* data, size_t size);
void run();
private:
std::shared_ptr<QPDF> getQpdf();
std::shared_ptr<QPDFWriter> getWriter(std::shared_ptr<QPDF>);
void doWrite(std::shared_ptr<QPDFWriter> w);
void testWrite();
void doChecks();
Buffer input_buffer;
Pl_Discard discard;
};
FuzzHelper::FuzzHelper(unsigned char const* data, size_t size) :
// We do not modify data, so it is safe to remove the const for Buffer
input_buffer(const_cast<unsigned char*>(data), size)
{
}
std::shared_ptr<QPDF>
FuzzHelper::getQpdf()
{
auto is =
std::shared_ptr<InputSource>(new BufferInputSource("fuzz input", &this->input_buffer));
auto qpdf = QPDF::create();
qpdf->setMaxWarnings(200);
qpdf->processInputSource(is);
return qpdf;
}
std::shared_ptr<QPDFWriter>
FuzzHelper::getWriter(std::shared_ptr<QPDF> qpdf)
{
auto w = std::make_shared<QPDFWriter>(*qpdf);
w->setOutputPipeline(&this->discard);
w->setDecodeLevel(qpdf_dl_all);
return w;
}
void
FuzzHelper::doWrite(std::shared_ptr<QPDFWriter> w)
{
try {
w->write();
} catch (QPDFExc const& e) {
std::cerr << e.what() << '\n';
} catch (std::runtime_error const& e) {
std::cerr << e.what() << '\n';
}
}
void
FuzzHelper::testWrite()
{
// Write in various ways to exercise QPDFWriter
std::shared_ptr<QPDF> q;
std::shared_ptr<QPDFWriter> w;
q = getQpdf();
w = getWriter(q);
w->setStaticID(true);
w->setLinearization(true);
w->setR6EncryptionParameters("u", "o", true, true, true, true, true, true, qpdf_r3p_full, true);
doWrite(w);
}
void
FuzzHelper::doChecks()
{
// Limit the memory used to decompress JPEG files during fuzzing. Excessive memory use during
// 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
// occur legitimately and therefore must be allowed during normal operations.
Pl_DCT::setMemoryLimit(100'000'000);
Pl_DCT::setScanLimit(50);
Pl_PNGFilter::setMemoryLimit(1'000'000);
Pl_RunLength::setMemoryLimit(1'000'000);
Pl_TIFFPredictor::setMemoryLimit(1'000'000);
Pl_Flate::memory_limit(200'000);
// Do not decompress corrupt data. This may cause extended runtime within jpeglib without
// exercising additional code paths in qpdf, and potentially causing counterproductive timeouts.
Pl_DCT::setThrowOnCorruptData(true);
// Get as much coverage as possible in parts of the library that
// might benefit from fuzzing.
std::cerr << "\ninfo: starting testWrite\n";
testWrite();
}
void
FuzzHelper::run()
{
// The goal here is that you should be able to throw anything at
// libqpdf and it will respond without any memory errors and never
// do anything worse than throwing a QPDFExc or
// std::runtime_error. Throwing any other kind of exception,
// segfaulting, or having a memory error (when built with
// appropriate sanitizers) will all cause abnormal exit.
try {
doChecks();
} catch (QPDFExc const& e) {
std::cerr << "QPDFExc: " << e.what() << '\n';
} catch (std::runtime_error const& e) {
std::cerr << "runtime_error: " << e.what() << '\n';
}
}
extern "C" int
LLVMFuzzerTestOneInput(unsigned char const* data, size_t size)
{
#ifndef _WIN32
// Used by jpeg library to work around false positives in memory
// sanitizer.
setenv("JSIMD_FORCENONE", "1", 1);
#endif
FuzzHelper f(data, size);
f.run();
return 0;
}
|