Improve JPX fuzzer
This CL splits initialization into two parts so that the fuzzer can
check for enormous sizes in headers before calling the opj decoding
code.
Bug: chromium:903724
Change-Id: I1dc7095d65b55319cb748d8a24206d72dd66390d
Reviewed-on: https://pdfium-review.googlesource.com/c/45732
Reviewed-by: Tom Sepez <tsepez@chromium.org>
Commit-Queue: Nicolás Peña Moreno <npm@chromium.org>
diff --git a/core/fpdfapi/render/cpdf_dibbase.cpp b/core/fpdfapi/render/cpdf_dibbase.cpp
index 5e48c68..1f1ec21 100644
--- a/core/fpdfapi/render/cpdf_dibbase.cpp
+++ b/core/fpdfapi/render/cpdf_dibbase.cpp
@@ -592,6 +592,9 @@
if (!context->decoder())
return nullptr;
+ if (!context->decoder()->StartDecode())
+ return nullptr;
+
uint32_t width = 0;
uint32_t height = 0;
uint32_t components = 0;
diff --git a/core/fxcodec/codec/ccodec_jpxmodule.cpp b/core/fxcodec/codec/ccodec_jpxmodule.cpp
index aaaaf81..fb197de 100644
--- a/core/fxcodec/codec/ccodec_jpxmodule.cpp
+++ b/core/fxcodec/codec/ccodec_jpxmodule.cpp
@@ -517,7 +517,10 @@
m_Image = pTempImage;
m_Image->pdfium_use_colorspace = !!m_ColorSpace;
+ return true;
+}
+bool CJPX_Decoder::StartDecode() {
if (!m_Parameters.nb_tile_to_decode) {
if (!opj_set_decode_area(m_Codec.Get(), m_Image.Get(), m_Parameters.DA_x0,
m_Parameters.DA_y0, m_Parameters.DA_x1,
@@ -554,7 +557,6 @@
m_Image->icc_profile_buf = nullptr;
m_Image->icc_profile_len = 0;
}
-
return true;
}
diff --git a/core/fxcodec/codec/cjpx_decoder.h b/core/fxcodec/codec/cjpx_decoder.h
index 5be4b87..940efd8 100644
--- a/core/fxcodec/codec/cjpx_decoder.h
+++ b/core/fxcodec/codec/cjpx_decoder.h
@@ -24,6 +24,7 @@
bool Init(pdfium::span<const uint8_t> src_data);
void GetInfo(uint32_t* width, uint32_t* height, uint32_t* components);
+ bool StartDecode();
bool Decode(uint8_t* dest_buf,
uint32_t pitch,
const std::vector<uint8_t>& offsets);
diff --git a/testing/fuzzers/pdf_jpx_fuzzer.cc b/testing/fuzzers/pdf_jpx_fuzzer.cc
index 011b171..51601f6 100644
--- a/testing/fuzzers/pdf_jpx_fuzzer.cc
+++ b/testing/fuzzers/pdf_jpx_fuzzer.cc
@@ -16,6 +16,14 @@
namespace {
const uint32_t kMaxJPXFuzzSize = 100 * 1024 * 1024; // 100 MB
+
+bool CheckImageSize(uint32_t width, uint32_t height, uint32_t components) {
+ static constexpr uint32_t kMemLimitBytes = 1024 * 1024 * 1024; // 1 GB.
+ FX_SAFE_UINT32 mem = width;
+ mem *= height;
+ mem *= components;
+ return mem.IsValid() && mem.ValueOrDie() <= kMemLimitBytes;
+}
} // namespace
extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
@@ -24,16 +32,21 @@
if (!decoder)
return 0;
+ // A call to StartDecode could be too expensive if image size is very big, so
+ // check size before calling StartDecode().
uint32_t width;
uint32_t height;
uint32_t components;
g_module.GetImageInfo(decoder.get(), &width, &height, &components);
+ if (!CheckImageSize(width, height, components))
+ return 0;
- static constexpr uint32_t kMemLimit = 1024 * 1024 * 1024; // 1 GB.
- FX_SAFE_UINT32 mem = width;
- mem *= height;
- mem *= components;
- if (!mem.IsValid() || mem.ValueOrDie() > kMemLimit)
+ if (!decoder->StartDecode())
+ return 0;
+
+ // StartDecode() could change image size, so check again.
+ g_module.GetImageInfo(decoder.get(), &width, &height, &components);
+ if (!CheckImageSize(width, height, components))
return 0;
FXDIB_Format format;