Add strict_mode parameter to CJPX_Decoder::Create()

Allow pdf_jpx_fuzzer to exercise the JPEG2000 decoding code, without
enabling the new code paths exposed by calling
opj_decoder_set_strict_mode() by default.

Bug: 42270564, 347071498, 348129258
Change-Id: Iabb7be6e098b322a7c7c916e01fca4a8f55d9633
Reviewed-on: https://pdfium-review.googlesource.com/c/pdfium/+/120930
Reviewed-by: Thomas Sepez <tsepez@google.com>
Reviewed-by: Tom Sepez <tsepez@chromium.org>
Commit-Queue: Lei Zhang <thestig@chromium.org>
diff --git a/core/fpdfapi/page/cpdf_dib.cpp b/core/fpdfapi/page/cpdf_dib.cpp
index 22733de..421af3f 100644
--- a/core/fpdfapi/page/cpdf_dib.cpp
+++ b/core/fpdfapi/page/cpdf_dib.cpp
@@ -661,7 +661,7 @@
   std::unique_ptr<CJPX_Decoder> decoder =
       CJPX_Decoder::Create(m_pStreamAcc->GetSpan(),
                            ColorSpaceOptionFromColorSpace(m_pColorSpace.Get()),
-                           resolution_levels_to_skip);
+                           resolution_levels_to_skip, /*strict_mode=*/true);
   if (!decoder)
     return nullptr;
 
diff --git a/core/fxcodec/jpx/cjpx_decoder.cpp b/core/fxcodec/jpx/cjpx_decoder.cpp
index 33157b5..8a53dd9 100644
--- a/core/fxcodec/jpx/cjpx_decoder.cpp
+++ b/core/fxcodec/jpx/cjpx_decoder.cpp
@@ -413,11 +413,13 @@
 std::unique_ptr<CJPX_Decoder> CJPX_Decoder::Create(
     pdfium::span<const uint8_t> src_span,
     CJPX_Decoder::ColorSpaceOption option,
-    uint8_t resolution_levels_to_skip) {
+    uint8_t resolution_levels_to_skip,
+    bool strict_mode) {
   // Private ctor.
   auto decoder = pdfium::WrapUnique(new CJPX_Decoder(option));
-  if (!decoder->Init(src_span, resolution_levels_to_skip))
+  if (!decoder->Init(src_span, resolution_levels_to_skip, strict_mode)) {
     return nullptr;
+  }
   return decoder;
 }
 
@@ -432,7 +434,8 @@
 CJPX_Decoder::~CJPX_Decoder() = default;
 
 bool CJPX_Decoder::Init(pdfium::span<const uint8_t> src_data,
-                        uint8_t resolution_levels_to_skip) {
+                        uint8_t resolution_levels_to_skip,
+                        bool strict_mode) {
   static constexpr uint8_t kJP2Header[] = {0x00, 0x00, 0x00, 0x0c, 0x6a, 0x50,
                                            0x20, 0x20, 0x0d, 0x0a, 0x87, 0x0a};
   if (src_data.size() < sizeof(kJP2Header) ||
@@ -470,6 +473,11 @@
     return false;
   }
 
+  // For https://crbug.com/42270564
+  if (!strict_mode) {
+    CHECK(opj_decoder_set_strict_mode(m_Codec.get(), false));
+  }
+
   opj_image_t* pTempImage = nullptr;
   if (!opj_read_header(m_Stream.get(), m_Codec.get(), &pTempImage)) {
     return false;
diff --git a/core/fxcodec/jpx/cjpx_decoder.h b/core/fxcodec/jpx/cjpx_decoder.h
index fb1efd4..a693413 100644
--- a/core/fxcodec/jpx/cjpx_decoder.h
+++ b/core/fxcodec/jpx/cjpx_decoder.h
@@ -46,7 +46,8 @@
   static std::unique_ptr<CJPX_Decoder> Create(
       pdfium::span<const uint8_t> src_span,
       CJPX_Decoder::ColorSpaceOption option,
-      uint8_t resolution_levels_to_skip);
+      uint8_t resolution_levels_to_skip,
+      bool strict_mode);
 
   static void Sycc420ToRgbForTesting(opj_image_t* img);
 
@@ -87,8 +88,11 @@
   // Use Create() to instantiate.
   explicit CJPX_Decoder(ColorSpaceOption option);
 
+  // TODO(crbug.com/42270564): Remove `strict_mode` once all the bugs have been
+  // worked out in OpenJPEG.
   bool Init(pdfium::span<const uint8_t> src_data,
-            uint8_t resolution_levels_to_skip);
+            uint8_t resolution_levels_to_skip,
+            bool strict_mode);
 
   const ColorSpaceOption m_ColorSpaceOption;
   pdfium::raw_span<const uint8_t> m_SrcData;
diff --git a/testing/fuzzers/pdf_jpx_fuzzer.cc b/testing/fuzzers/pdf_jpx_fuzzer.cc
index 5306f4d..3fc45ef 100644
--- a/testing/fuzzers/pdf_jpx_fuzzer.cc
+++ b/testing/fuzzers/pdf_jpx_fuzzer.cc
@@ -26,15 +26,21 @@
 }  // namespace
 
 extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
-  if (size < 2)
+  if (size < 3) {
     return 0;
+  }
 
   // SAFETY: trusted arguments from fuzzer.
   auto span = UNSAFE_BUFFERS(pdfium::make_span(data, size));
 
-  std::unique_ptr<CJPX_Decoder> decoder = CJPX_Decoder::Create(
-      span.subspan(2u),
-      static_cast<CJPX_Decoder::ColorSpaceOption>(data[0] % 3), data[1]);
+  auto color_space_option =
+      static_cast<CJPX_Decoder::ColorSpaceOption>(data[0] % 3);
+  uint8_t resolution_levels_to_skip = data[1];
+  bool strict_mode = !!data[2];
+
+  std::unique_ptr<CJPX_Decoder> decoder =
+      CJPX_Decoder::Create(span.subspan(3u), color_space_option,
+                           resolution_levels_to_skip, strict_mode);
   if (!decoder)
     return 0;