ultrahdr: Add fuzz application for decode api

Bug: 282640328
Test: ./ultrahdr_dec_fuzzer

Change-Id: I9bd2a314d05122fd3010889b661455a6cba364e6
diff --git a/libs/ultrahdr/fuzzer/Android.bp b/libs/ultrahdr/fuzzer/Android.bp
index 27b38c3..6c0a2f5 100644
--- a/libs/ultrahdr/fuzzer/Android.bp
+++ b/libs/ultrahdr/fuzzer/Android.bp
@@ -24,7 +24,17 @@
 cc_defaults {
     name: "ultrahdr_fuzzer_defaults",
     host_supported: true,
-    static_libs: ["liblog"],
+    shared_libs: [
+        "libimage_io",
+        "libjpeg",
+    ],
+    static_libs: [
+        "libjpegdecoder",
+        "libjpegencoder",
+        "libultrahdr",
+        "libutils",
+        "liblog",
+    ],
     target: {
         darwin: {
             enabled: false,
@@ -37,6 +47,8 @@
         description: "The fuzzers target the APIs of jpeg hdr",
         service_privilege: "constrained",
         users: "multi_user",
+        fuzzed_code_usage: "future_version",
+        vector: "local_no_privileges_required",
     },
 }
 
@@ -46,20 +58,12 @@
     srcs: [
         "ultrahdr_enc_fuzzer.cpp",
     ],
-    shared_libs: [
-        "libimage_io",
-        "libjpeg",
-        "liblog",
-    ],
-    static_libs: [
-        "libjpegdecoder",
-        "libjpegencoder",
-        "libultrahdr",
-        "libutils",
-    ],
-    fuzz_config: {
-        fuzzed_code_usage: "future_version",
-        vector: "local_no_privileges_required",
-    },
 }
 
+cc_fuzz {
+    name: "ultrahdr_dec_fuzzer",
+    defaults: ["ultrahdr_fuzzer_defaults"],
+    srcs: [
+        "ultrahdr_dec_fuzzer.cpp",
+    ],
+}
diff --git a/libs/ultrahdr/fuzzer/ultrahdr_dec_fuzzer.cpp b/libs/ultrahdr/fuzzer/ultrahdr_dec_fuzzer.cpp
new file mode 100644
index 0000000..ad1d57a
--- /dev/null
+++ b/libs/ultrahdr/fuzzer/ultrahdr_dec_fuzzer.cpp
@@ -0,0 +1,73 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// System include files
+#include <fuzzer/FuzzedDataProvider.h>
+#include <iostream>
+#include <vector>
+
+// User include files
+#include "ultrahdr/jpegr.h"
+
+using namespace android::ultrahdr;
+
+// Transfer functions for image data, sync with ultrahdr.h
+const int kOfMin = ULTRAHDR_OUTPUT_UNSPECIFIED + 1;
+const int kOfMax = ULTRAHDR_OUTPUT_MAX;
+
+class UltraHdrDecFuzzer {
+public:
+    UltraHdrDecFuzzer(const uint8_t* data, size_t size) : mFdp(data, size){};
+    void process();
+
+private:
+    FuzzedDataProvider mFdp;
+};
+
+void UltraHdrDecFuzzer::process() {
+    // hdr_of
+    auto of = static_cast<ultrahdr_output_format>(mFdp.ConsumeIntegralInRange<int>(kOfMin, kOfMax));
+    auto buffer = mFdp.ConsumeRemainingBytes<uint8_t>();
+    jpegr_compressed_struct jpegImgR{buffer.data(), (int)buffer.size(), (int)buffer.size(),
+                                     ULTRAHDR_COLORGAMUT_UNSPECIFIED};
+
+    std::vector<uint8_t> iccData(0);
+    std::vector<uint8_t> exifData(0);
+    jpegr_info_struct info{0, 0, &iccData, &exifData};
+    JpegR jpegHdr;
+    (void)jpegHdr.getJPEGRInfo(&jpegImgR, &info);
+//#define DUMP_PARAM
+#ifdef DUMP_PARAM
+    std::cout << "input buffer size " << jpegImgR.length << std::endl;
+    std::cout << "image dimensions " << info.width << " x " << info.width << std::endl;
+#endif
+    size_t outSize = info.width * info.height * ((of == ULTRAHDR_OUTPUT_SDR) ? 4 : 8);
+    jpegr_uncompressed_struct decodedJpegR;
+    auto decodedRaw = std::make_unique<uint8_t[]>(outSize);
+    decodedJpegR.data = decodedRaw.get();
+    ultrahdr_metadata_struct metadata;
+    jpegr_uncompressed_struct decodedGainMap{};
+    (void)jpegHdr.decodeJPEGR(&jpegImgR, &decodedJpegR,
+                              mFdp.ConsumeFloatingPointInRange<float>(1.0, FLT_MAX), nullptr, of,
+                              &decodedGainMap, &metadata);
+    if (decodedGainMap.data) free(decodedGainMap.data);
+}
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
+    UltraHdrDecFuzzer fuzzHandle(data, size);
+    fuzzHandle.process();
+    return 0;
+}
diff --git a/libs/ultrahdr/fuzzer/ultrahdr_enc_fuzzer.cpp b/libs/ultrahdr/fuzzer/ultrahdr_enc_fuzzer.cpp
index 7faa157..dca0c15 100644
--- a/libs/ultrahdr/fuzzer/ultrahdr_enc_fuzzer.cpp
+++ b/libs/ultrahdr/fuzzer/ultrahdr_enc_fuzzer.cpp
@@ -55,12 +55,9 @@
 const int kQfMin = 0;
 const int kQfMax = 100;
 
-// seed
-const unsigned kSeed = 0x7ab7;
-
-class JpegHDRFuzzer {
+class UltraHdrEncFuzzer {
 public:
-    JpegHDRFuzzer(const uint8_t* data, size_t size) : mFdp(data, size){};
+    UltraHdrEncFuzzer(const uint8_t* data, size_t size) : mFdp(data, size){};
     void process();
     void fillP010Buffer(uint16_t* data, int width, int height, int stride);
     void fill420Buffer(uint8_t* data, int size);
@@ -69,7 +66,7 @@
     FuzzedDataProvider mFdp;
 };
 
-void JpegHDRFuzzer::fillP010Buffer(uint16_t* data, int width, int height, int stride) {
+void UltraHdrEncFuzzer::fillP010Buffer(uint16_t* data, int width, int height, int stride) {
     uint16_t* tmp = data;
     std::vector<uint16_t> buffer(16);
     for (int i = 0; i < buffer.size(); i++) {
@@ -78,22 +75,24 @@
     for (int j = 0; j < height; j++) {
         for (int i = 0; i < width; i += buffer.size()) {
             memcpy(data + i, buffer.data(), std::min((int)buffer.size(), (width - i)));
-            std::shuffle(buffer.begin(), buffer.end(), std::default_random_engine(kSeed));
+            std::shuffle(buffer.begin(), buffer.end(),
+                         std::default_random_engine(std::random_device{}()));
         }
         tmp += stride;
     }
 }
 
-void JpegHDRFuzzer::fill420Buffer(uint8_t* data, int size) {
+void UltraHdrEncFuzzer::fill420Buffer(uint8_t* data, int size) {
     std::vector<uint8_t> buffer(16);
     mFdp.ConsumeData(buffer.data(), buffer.size());
     for (int i = 0; i < size; i += buffer.size()) {
         memcpy(data + i, buffer.data(), std::min((int)buffer.size(), (size - i)));
-        std::shuffle(buffer.begin(), buffer.end(), std::default_random_engine(kSeed));
+        std::shuffle(buffer.begin(), buffer.end(),
+                     std::default_random_engine(std::random_device{}()));
     }
 }
 
-void JpegHDRFuzzer::process() {
+void UltraHdrEncFuzzer::process() {
     while (mFdp.remaining_bytes()) {
         struct jpegr_uncompressed_struct p010Img {};
         struct jpegr_uncompressed_struct yuv420Img {};
@@ -293,7 +292,7 @@
 }
 
 extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
-    JpegHDRFuzzer fuzzHandle(data, size);
+    UltraHdrEncFuzzer fuzzHandle(data, size);
     fuzzHandle.process();
     return 0;
 }
diff --git a/libs/ultrahdr/include/ultrahdr/jpegdecoderhelper.h b/libs/ultrahdr/include/ultrahdr/jpegdecoderhelper.h
index f642bad..4f2b742 100644
--- a/libs/ultrahdr/include/ultrahdr/jpegdecoderhelper.h
+++ b/libs/ultrahdr/include/ultrahdr/jpegdecoderhelper.h
@@ -25,6 +25,10 @@
 }
 #include <utils/Errors.h>
 #include <vector>
+
+static const int kMaxWidth = 8192;
+static const int kMaxHeight = 8192;
+
 namespace android::ultrahdr {
 /*
  * Encapsulates a converter from JPEG to raw image (YUV420planer or grey-scale) format.
diff --git a/libs/ultrahdr/jpegdecoderhelper.cpp b/libs/ultrahdr/jpegdecoderhelper.cpp
index fac90c5..2a9bc9a 100644
--- a/libs/ultrahdr/jpegdecoderhelper.cpp
+++ b/libs/ultrahdr/jpegdecoderhelper.cpp
@@ -213,6 +213,12 @@
         }
     }
 
+    if (cinfo.image_width > kMaxWidth || cinfo.image_height > kMaxHeight) {
+        // constraint on max width and max height is only due to alloc constraints
+        // tune these values basing on the target device
+        return false;
+    }
+
     mWidth = cinfo.image_width;
     mHeight = cinfo.image_height;
 
diff --git a/libs/ultrahdr/jpegr.cpp b/libs/ultrahdr/jpegr.cpp
index b2bde6c..25197d6 100644
--- a/libs/ultrahdr/jpegr.cpp
+++ b/libs/ultrahdr/jpegr.cpp
@@ -119,6 +119,13 @@
     return ERROR_JPEGR_INVALID_INPUT_TYPE;
   }
 
+  if (uncompressed_p010_image->width > kMaxWidth
+          || uncompressed_p010_image->height > kMaxHeight) {
+    ALOGE("Image dimensions cannot be larger than %dx%d, image dimensions %dx%d",
+          kMaxWidth, kMaxHeight, uncompressed_p010_image->width, uncompressed_p010_image->height);
+    return ERROR_JPEGR_INVALID_INPUT_TYPE;
+  }
+
   if (uncompressed_p010_image->colorGamut <= ULTRAHDR_COLORGAMUT_UNSPECIFIED
           || uncompressed_p010_image->colorGamut > ULTRAHDR_COLORGAMUT_MAX) {
     ALOGE("Unrecognized p010 color gamut %d", uncompressed_p010_image->colorGamut);