| /* |
| * Copyright 2020 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. |
| */ |
| |
| #include <android/imagedecoder.h> |
| |
| #include <binder/IPCThreadState.h> |
| #include <stddef.h> |
| #include <stdint.h> |
| #include <cstdlib> |
| #include <memory> |
| |
| #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); |
| } |
| |
| struct PixelFreer { |
| void operator()(void* pixels) const { std::free(pixels); } |
| }; |
| |
| 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); |
| 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; |
| } |
| |
| 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; |
| } |
| return 0; |
| } |