summaryrefslogtreecommitdiff
path: root/native/graphics/jni/fuzz/fuzz_imagedecoder.cpp
blob: 838bf3f30a119ab2fdc72e8142edb0dacecfdae9 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
/*
 * 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;
}