diff options
| author | 2024-06-11 08:46:03 +0000 | |
|---|---|---|
| committer | 2024-06-11 08:46:03 +0000 | |
| commit | 3ce4fb8f972d000c433b51bbf0d0057cfdb66d2b (patch) | |
| tree | a801a3c0fc2c24e8ac1021a09e0bd28dc19c464b | |
| parent | 7b155a8ac15ba7d254c96659a0b42c46131eb382 (diff) | |
| parent | 85c8496ade8c44fc9a9a5692344e8f4c8463ba78 (diff) | |
Merge "Refactor imagedecoder_fuzzer" into main
| -rw-r--r-- | native/graphics/jni/Android.bp | 1 | ||||
| -rw-r--r-- | native/graphics/jni/fuzz/fuzz_imagedecoder.cpp | 141 | ||||
| -rw-r--r-- | native/graphics/jni/fuzz/imagedecoder_fuzzer.dict | 7 |
3 files changed, 99 insertions, 50 deletions
diff --git a/native/graphics/jni/Android.bp b/native/graphics/jni/Android.bp index 8ea46329af58..746c280edc70 100644 --- a/native/graphics/jni/Android.bp +++ b/native/graphics/jni/Android.bp @@ -111,6 +111,7 @@ cc_defaults { "allocator_may_return_null = 1", ], }, + dictionary: "fuzz/imagedecoder_fuzzer.dict", host_supported: true, } diff --git a/native/graphics/jni/fuzz/fuzz_imagedecoder.cpp b/native/graphics/jni/fuzz/fuzz_imagedecoder.cpp index 838bf3f30a11..886f3075df72 100644 --- a/native/graphics/jni/fuzz/fuzz_imagedecoder.cpp +++ b/native/graphics/jni/fuzz/fuzz_imagedecoder.cpp @@ -15,32 +15,15 @@ */ #include <android/imagedecoder.h> - #include <binder/IPCThreadState.h> -#include <stddef.h> -#include <stdint.h> -#include <cstdlib> -#include <memory> +#include <fuzzer/FuzzedDataProvider.h> #ifdef PNG_MUTATOR_DEFINE_LIBFUZZER_CUSTOM_MUTATOR #include <fuzz/png_mutator.h> #endif -struct DecoderDeleter { - void operator()(AImageDecoder* decoder) const { AImageDecoder_delete(decoder); } -}; - -using DecoderPointer = std::unique_ptr<AImageDecoder, DecoderDeleter>; - -static DecoderPointer makeDecoder(const uint8_t* data, size_t size) { - AImageDecoder* decoder = nullptr; - int result = AImageDecoder_createFromBuffer(data, size, &decoder); - if (result != ANDROID_IMAGE_DECODER_SUCCESS) { - // This was not a valid image. - return nullptr; - } - return DecoderPointer(decoder); -} +constexpr int32_t kMaxDimension = 5000; +constexpr int32_t kMinDimension = 0; struct PixelFreer { void operator()(void* pixels) const { std::free(pixels); } @@ -49,40 +32,98 @@ struct PixelFreer { using PixelPointer = std::unique_ptr<void, PixelFreer>; extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { - // Without this call, decoding HEIF may time out on binder IPC calls. - android::ProcessState::self()->startThreadPool(); - - DecoderPointer decoder = makeDecoder(data, size); + FuzzedDataProvider dataProvider = FuzzedDataProvider(data, size); + /** + * Use maximum of 80% of buffer for creating decoder and save at least + * 20% buffer for fuzzing other APIs + */ + const int32_t dataSize = dataProvider.ConsumeIntegralInRange<int32_t>(0, (size * 80) / 100); + std::vector<uint8_t> inputBuffer = dataProvider.ConsumeBytes<uint8_t>(dataSize); + AImageDecoder* decoder = nullptr; + AImageDecoder_createFromBuffer(inputBuffer.data(), inputBuffer.size(), &decoder); if (!decoder) { return 0; } - - const AImageDecoderHeaderInfo* info = AImageDecoder_getHeaderInfo(decoder.get()); - int32_t width = AImageDecoderHeaderInfo_getWidth(info); - int32_t height = AImageDecoderHeaderInfo_getHeight(info); - - // Set an arbitrary limit on the size of an image. The fuzzer runs with a - // limited amount of memory, and keeping this allocation small allows the - // fuzzer to continue running to try to find more serious problems. This - // size is large enough to hold a photo taken by a current gen phone. - constexpr int32_t kMaxDimension = 5000; - if (width > kMaxDimension || height > kMaxDimension) { - return 0; - } - - size_t stride = AImageDecoder_getMinimumStride(decoder.get()); - size_t pixelSize = height * stride; - auto pixels = PixelPointer(std::malloc(pixelSize)); - if (!pixels.get()) { - return 0; + const AImageDecoderHeaderInfo* headerInfo = AImageDecoder_getHeaderInfo(decoder); + AImageDecoderFrameInfo* frameInfo = AImageDecoderFrameInfo_create(); + int32_t height = AImageDecoderHeaderInfo_getHeight(headerInfo); + int32_t width = AImageDecoderHeaderInfo_getWidth(headerInfo); + while (dataProvider.remaining_bytes()) { + auto invokeImageApi = dataProvider.PickValueInArray<const std::function<void()>>({ + [&]() { + int32_t testHeight = + dataProvider.ConsumeIntegralInRange<int32_t>(kMinDimension, + kMaxDimension); + int32_t testWidth = dataProvider.ConsumeIntegralInRange<int32_t>(kMinDimension, + kMaxDimension); + int32_t result = AImageDecoder_setTargetSize(decoder, testHeight, testWidth); + if (result == ANDROID_IMAGE_DECODER_SUCCESS) { + height = testHeight; + width = testWidth; + } + }, + [&]() { + const bool required = dataProvider.ConsumeBool(); + AImageDecoder_setUnpremultipliedRequired(decoder, required); + }, + [&]() { + AImageDecoder_setAndroidBitmapFormat( + decoder, + dataProvider.ConsumeIntegralInRange< + int32_t>(ANDROID_BITMAP_FORMAT_NONE, + ANDROID_BITMAP_FORMAT_RGBA_1010102) /* format */); + }, + [&]() { + AImageDecoder_setDataSpace(decoder, + dataProvider + .ConsumeIntegral<int32_t>() /* dataspace */); + }, + [&]() { + ARect rect{dataProvider.ConsumeIntegral<int32_t>() /* left */, + dataProvider.ConsumeIntegral<int32_t>() /* top */, + dataProvider.ConsumeIntegral<int32_t>() /* right */, + dataProvider.ConsumeIntegral<int32_t>() /* bottom */}; + AImageDecoder_setCrop(decoder, rect); + }, + [&]() { AImageDecoderHeaderInfo_getWidth(headerInfo); }, + [&]() { AImageDecoderHeaderInfo_getMimeType(headerInfo); }, + [&]() { AImageDecoderHeaderInfo_getAlphaFlags(headerInfo); }, + [&]() { AImageDecoderHeaderInfo_getAndroidBitmapFormat(headerInfo); }, + [&]() { + int32_t tempHeight; + int32_t tempWidth; + AImageDecoder_computeSampledSize(decoder, + dataProvider.ConsumeIntegral< + int>() /* sampleSize */, + &tempWidth, &tempHeight); + }, + [&]() { AImageDecoderHeaderInfo_getDataSpace(headerInfo); }, + [&]() { AImageDecoder_getRepeatCount(decoder); }, + [&]() { AImageDecoder_getFrameInfo(decoder, frameInfo); }, + [&]() { AImageDecoderFrameInfo_getDuration(frameInfo); }, + [&]() { AImageDecoderFrameInfo_hasAlphaWithinBounds(frameInfo); }, + [&]() { AImageDecoderFrameInfo_getDisposeOp(frameInfo); }, + [&]() { AImageDecoderFrameInfo_getBlendOp(frameInfo); }, + [&]() { + AImageDecoder_setInternallyHandleDisposePrevious( + decoder, dataProvider.ConsumeBool() /* handle */); + }, + [&]() { AImageDecoder_rewind(decoder); }, + [&]() { AImageDecoder_advanceFrame(decoder); }, + [&]() { + size_t stride = AImageDecoder_getMinimumStride(decoder); + size_t pixelSize = height * stride; + auto pixels = PixelPointer(std::malloc(pixelSize)); + if (!pixels.get()) { + return; + } + AImageDecoder_decodeImage(decoder, pixels.get(), stride, pixelSize); + }, + }); + invokeImageApi(); } - while (true) { - int result = AImageDecoder_decodeImage(decoder.get(), pixels.get(), stride, pixelSize); - if (result != ANDROID_IMAGE_DECODER_SUCCESS) break; - - result = AImageDecoder_advanceFrame(decoder.get()); - if (result != ANDROID_IMAGE_DECODER_SUCCESS) break; - } + AImageDecoderFrameInfo_delete(frameInfo); + AImageDecoder_delete(decoder); return 0; } diff --git a/native/graphics/jni/fuzz/imagedecoder_fuzzer.dict b/native/graphics/jni/fuzz/imagedecoder_fuzzer.dict new file mode 100644 index 000000000000..5b54a0ed115e --- /dev/null +++ b/native/graphics/jni/fuzz/imagedecoder_fuzzer.dict @@ -0,0 +1,7 @@ +kw1="\x89\x50\x4E\x47" +kw2="\xff\xD8\xFF" +kw4="\x52\x49\x46\x46" +kw5="\x00\x00\x01\x00" +kw6="\x47\x49\x46\x08" +kw7="ftyp" +kw8="\x04\x00\x00\x00" |