Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 5421d3f1 authored by Treehugger Robot's avatar Treehugger Robot Committed by Automerger Merge Worker
Browse files

Merge "Refactored libstagefright_frameDecoder_fuzzer" into main am: dfe71bf7 am: 0ff5a740

parents 091f3b1e 0ff5a740
Loading
Loading
Loading
Loading
+51 −48
Original line number Diff line number Diff line
@@ -24,61 +24,64 @@

namespace android {

#define MAX_MEDIA_BUFFER_SIZE 2048
static const android_pixel_format_t kColorFormats[] = {
        HAL_PIXEL_FORMAT_RGBA_8888,
        HAL_PIXEL_FORMAT_RGB_565,
        HAL_PIXEL_FORMAT_BGRA_8888,
        HAL_PIXEL_FORMAT_RGBA_1010102,
        HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED, /* To cover the default case */
};

static const MediaSource::ReadOptions::SeekMode kSeekModes[] = {
        MediaSource::ReadOptions::SeekMode::SEEK_PREVIOUS_SYNC,
        MediaSource::ReadOptions::SeekMode::SEEK_NEXT_SYNC,
        MediaSource::ReadOptions::SeekMode::SEEK_CLOSEST_SYNC,
        MediaSource::ReadOptions::SeekMode::SEEK_CLOSEST,
        MediaSource::ReadOptions::SeekMode::SEEK_FRAME_INDEX,
};

static const std::string kComponentNames[] = {
        "c2.android.avc.decoder",  "c2.android.hevc.decoder", "c2.android.vp8.decoder",
        "c2.android.vp9.decoder",  "c2.android.av1.decoder",  "c2.android.mpeg4.decoder",
        "c2.android.h263.decoder",
};

// Fuzzer entry point.
extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
    // Init our wrapper
    FuzzedDataProvider fdp(data, size);
    std::string component = fdp.PickValueInArray(kComponentNames);
    AString componentName(component.c_str());
    sp<MetaData> trackMeta = generateMetaData(&fdp, component);
    sp<IMediaSource> source = sp<IMediaSourceFuzzImpl>::make(&fdp, gMaxMediaBufferSize);

    std::string name = fdp.ConsumeRandomLengthString(fdp.remaining_bytes());
    AString componentName(name.c_str());
    sp<MetaData> trackMeta = generateMetaData(&fdp);
    sp<IMediaSource> source = new IMediaSourceFuzzImpl(&fdp, MAX_MEDIA_BUFFER_SIZE);

    // Image or video Decoder?
    sp<FrameDecoder> decoder;
    bool isVideoDecoder = fdp.ConsumeBool();
    if (isVideoDecoder) {
        decoder = new VideoFrameDecoder(componentName, trackMeta, source);
    sp<FrameDecoder> decoder = nullptr;
    if (fdp.ConsumeBool()) {
        decoder = sp<MediaImageDecoder>::make(componentName, trackMeta, source);
    } else {
        decoder = new MediaImageDecoder(componentName, trackMeta, source);
        decoder = sp<VideoFrameDecoder>::make(componentName, trackMeta, source);
    }

    while (fdp.remaining_bytes()) {
        uint8_t switchCase = fdp.ConsumeIntegralInRange<uint8_t>(0, 3);
        switch (switchCase) {
            case 0: {
                int64_t frameTimeUs = fdp.ConsumeIntegral<int64_t>();
                int option = fdp.ConsumeIntegral<int>();
                int colorFormat = fdp.ConsumeIntegral<int>();
                decoder->init(frameTimeUs, option, colorFormat);
                break;
            }
            case 1:
                decoder->extractFrame();
                break;
            case 2: {
                FrameRect rect;
                rect.left = fdp.ConsumeIntegral<int32_t>();
                rect.top = fdp.ConsumeIntegral<int32_t>();
                rect.right = fdp.ConsumeIntegral<int32_t>();
                rect.bottom = fdp.ConsumeIntegral<int32_t>();
    if (decoder.get() &&
        decoder->init(fdp.ConsumeIntegral<uint64_t>() /* frameTimeUs */,
                      fdp.PickValueInArray(kSeekModes) /* option */,
                      fdp.PickValueInArray(kColorFormats) /* colorFormat */) == OK) {
        auto frameDecoderAPI = fdp.PickValueInArray<const std::function<void()>>({
                [&]() { decoder->extractFrame(); },
                [&]() {
                    FrameRect rect(fdp.ConsumeIntegral<int32_t>() /* left */,
                                   fdp.ConsumeIntegral<int32_t>() /* top */,
                                   fdp.ConsumeIntegral<int32_t>() /* right */,
                                   fdp.ConsumeIntegral<int32_t>() /* bottom */
                    );
                    decoder->extractFrame(&rect);
                break;
            }
            case 3: {
                sp<MetaData> trackMeta = generateMetaData(&fdp);
                decoder->getMetadataOnly(trackMeta,
                                         /*colorFormat*/ fdp.ConsumeIntegral<int>(),
                                         /*thumbnail*/ fdp.ConsumeBool());
                break;
                },
                [&]() {
                    FrameDecoder::getMetadataOnly(
                            trackMeta, fdp.PickValueInArray(kColorFormats) /* colorFormat */,
                            fdp.ConsumeBool() /* thumbnail */);
                },
        });
        frameDecoderAPI();
    }
        }
    }

    generated_mime_types.clear();

    return 0;
}

+89 −58
Original line number Diff line number Diff line
@@ -20,17 +20,25 @@
#include <media/stagefright/MetaData.h>
#include "MediaMimeTypes.h"

#define MAX_METADATA_BUF_SIZE 512

namespace android {

std::vector<std::shared_ptr<char>> generated_mime_types;
constexpr uint8_t kMinKeyHeight = 32;
constexpr uint8_t kMinKeyWidth = 32;
constexpr uint16_t kMaxKeyHeight = 2160;
constexpr uint16_t kMaxKeyWidth = 3840;
size_t gMaxMediaBufferSize = 0;

sp<MetaData> generateMetaData(FuzzedDataProvider *fdp) {
    sp<MetaData> newMeta = new MetaData();
sp<MetaData> generateMetaData(FuzzedDataProvider* fdp, std::string componentName = std::string()) {
    sp<MetaData> newMeta = sp<MetaData>::make();

    // random MIME Type
    const char *mime_type;
    const char* mime;
    if(!componentName.empty())
    {
        auto it = decoderToMediaType.find(componentName);
        mime = it->second;
    }
    else{
        size_t index = fdp->ConsumeIntegralInRange<size_t>(0, kMimeTypes.size());
        // Let there be a chance of a true random string
        if (index == kMimeTypes.size()) {
@@ -38,51 +46,74 @@ sp<MetaData> generateMetaData(FuzzedDataProvider *fdp) {
            std::shared_ptr<char> mime_cstr(new char[mime_str.length()+1]);
            generated_mime_types.push_back(mime_cstr);
            strncpy(mime_cstr.get(), mime_str.c_str(), mime_str.length()+1);
        mime_type = mime_cstr.get();
            mime = mime_cstr.get();
        } else {
            mime = kMimeTypes[index];
        }
    }
    newMeta->setCString(kKeyMIMEType, mime);

    auto height = fdp->ConsumeIntegralInRange<uint16_t>(kMinKeyHeight, kMaxKeyHeight);
    auto width = fdp->ConsumeIntegralInRange<uint16_t>(kMinKeyWidth, kMaxKeyWidth);
    newMeta->setInt32(kKeyHeight, height);
    newMeta->setInt32(kKeyWidth, width);

    gMaxMediaBufferSize = height * width;

    if (fdp->ConsumeBool()) {
        newMeta->setInt32(kKeyTileHeight,
                          fdp->ConsumeIntegralInRange<uint16_t>(kMinKeyHeight, height));
        newMeta->setInt32(kKeyTileWidth,
                          fdp->ConsumeIntegralInRange<uint16_t>(kMinKeyWidth, width));
        newMeta->setInt32(kKeyGridRows, fdp->ConsumeIntegral<uint8_t>());
        newMeta->setInt32(kKeyGridCols, fdp->ConsumeIntegral<uint8_t>());
    }

    if (fdp->ConsumeBool()) {
        newMeta->setInt32(kKeySARHeight, fdp->ConsumeIntegral<uint8_t>());
        newMeta->setInt32(kKeySARWidth, fdp->ConsumeIntegral<uint8_t>());
    }

    if (fdp->ConsumeBool()) {
        newMeta->setInt32(kKeyDisplayHeight,
                          fdp->ConsumeIntegralInRange<uint16_t>(height, UINT16_MAX));
        newMeta->setInt32(kKeyDisplayWidth,
                          fdp->ConsumeIntegralInRange<uint16_t>(width, UINT16_MAX));
    }

    if (fdp->ConsumeBool()) {
        newMeta->setRect(kKeyCropRect, fdp->ConsumeIntegral<int32_t>() /* left */,
                         fdp->ConsumeIntegral<int32_t>() /* top */,
                         fdp->ConsumeIntegral<int32_t>() /* right */,
                         fdp->ConsumeIntegral<int32_t>() /* bottom */);
    }

    if (fdp->ConsumeBool()) {
        newMeta->setInt32(kKeyRotation, fdp->ConsumeIntegralInRange<uint8_t>(0, 3) * 90);
    }

    if (fdp->ConsumeBool()) {
        newMeta->setInt64(kKeyThumbnailTime, fdp->ConsumeIntegral<uint64_t>());
        newMeta->setInt32(kKeyThumbnailHeight, fdp->ConsumeIntegral<uint8_t>());
        newMeta->setInt32(kKeyThumbnailWidth, fdp->ConsumeIntegral<uint8_t>());

        size_t thumbnailSize = fdp->ConsumeIntegral<size_t>();
        std::vector<uint8_t> thumbnailData = fdp->ConsumeBytes<uint8_t>(thumbnailSize);
        if (mime == MEDIA_MIMETYPE_VIDEO_AV1) {
            newMeta->setData(kKeyThumbnailAV1C, fdp->ConsumeIntegral<int32_t>() /* type */,
                             thumbnailData.data(), thumbnailData.size());
        } else {
        mime_type = kMimeTypes[index];
            newMeta->setData(kKeyThumbnailHVCC, fdp->ConsumeIntegral<int32_t>() /* type */,
                             thumbnailData.data(), thumbnailData.size());
        }
    }

    if (fdp->ConsumeBool()) {
        size_t profileSize = fdp->ConsumeIntegral<size_t>();
        std::vector<uint8_t> profileData = fdp->ConsumeBytes<uint8_t>(profileSize);
        newMeta->setData(kKeyIccProfile, fdp->ConsumeIntegral<int32_t>() /* type */,
                         profileData.data(), profileData.size());
    }
    newMeta->setCString(kKeyMIMEType, mime_type);

    // Thumbnail time
    newMeta->setInt64(kKeyThumbnailTime, fdp->ConsumeIntegral<int64_t>());

    // Values used by allocVideoFrame
    newMeta->setInt32(kKeyRotation, fdp->ConsumeIntegral<int32_t>());
    size_t profile_size =
        fdp->ConsumeIntegralInRange<size_t>(0, MAX_METADATA_BUF_SIZE);
    std::vector<uint8_t> profile_bytes =
        fdp->ConsumeBytes<uint8_t>(profile_size);
    newMeta->setData(kKeyIccProfile,
                     fdp->ConsumeIntegral<int32_t>(),
                     profile_bytes.empty() ? nullptr : profile_bytes.data(),
                     profile_bytes.size());
    newMeta->setInt32(kKeySARWidth, fdp->ConsumeIntegral<int32_t>());
    newMeta->setInt32(kKeySARHeight, fdp->ConsumeIntegral<int32_t>());
    newMeta->setInt32(kKeyDisplayWidth, fdp->ConsumeIntegral<int32_t>());
    newMeta->setInt32(kKeyDisplayHeight, fdp->ConsumeIntegral<int32_t>());

    // Values used by findThumbnailInfo
    newMeta->setInt32(kKeyThumbnailWidth, fdp->ConsumeIntegral<int32_t>());
    newMeta->setInt32(kKeyThumbnailHeight, fdp->ConsumeIntegral<int32_t>());
    size_t thumbnail_size =
        fdp->ConsumeIntegralInRange<size_t>(0, MAX_METADATA_BUF_SIZE);
    std::vector<uint8_t> thumb_bytes =
        fdp->ConsumeBytes<uint8_t>(thumbnail_size);
    newMeta->setData(kKeyThumbnailHVCC,
                     fdp->ConsumeIntegral<int32_t>(),
                     thumb_bytes.empty() ? nullptr : thumb_bytes.data(),
                     thumb_bytes.size());

    // Values used by findGridInfo
    newMeta->setInt32(kKeyTileWidth, fdp->ConsumeIntegral<int32_t>());
    newMeta->setInt32(kKeyTileHeight, fdp->ConsumeIntegral<int32_t>());
    newMeta->setInt32(kKeyGridRows, fdp->ConsumeIntegral<int32_t>());
    newMeta->setInt32(kKeyGridCols, fdp->ConsumeIntegral<int32_t>());

    // A few functions perform a CHECK() that height/width are set
    newMeta->setInt32(kKeyHeight, fdp->ConsumeIntegral<int32_t>());
    newMeta->setInt32(kKeyWidth, fdp->ConsumeIntegral<int32_t>());

    return newMeta;
}
+43 −32
Original line number Diff line number Diff line
@@ -19,18 +19,18 @@

#include <media/stagefright/MediaSource.h>

#define MAX_FRAMES 5

namespace android {

class IMediaSourceFuzzImpl : public IMediaSource {
 public:
    IMediaSourceFuzzImpl(FuzzedDataProvider *_fdp, size_t _max_buffer_size) :
        fdp(_fdp),
        max_buffer_size(_max_buffer_size) {}
   IMediaSourceFuzzImpl(FuzzedDataProvider* _fdp, size_t _max_buffer_size)
       : frames_read(0), fdp(_fdp), min_buffer_size(32 * 32), max_buffer_size(_max_buffer_size) {}
   status_t start(MetaData*) override { return 0; }
   status_t stop() override { return 0; }
   sp<MetaData> getFormat() override { return nullptr; }
    status_t read(MediaBufferBase**,
        const MediaSource::ReadOptions*) override;
   status_t read(MediaBufferBase**, const MediaSource::ReadOptions*) override;
   status_t readMultiple(Vector<MediaBufferBase*>*, uint32_t,
                         const MediaSource::ReadOptions*) override;
   bool supportReadMultiple() override { return true; }
@@ -41,9 +41,11 @@ class IMediaSourceFuzzImpl : public IMediaSource {
    IBinder* onAsBinder() { return nullptr; }

 private:
   uint8_t frames_read;
   FuzzedDataProvider* fdp;
    std::vector<std::shared_ptr<MediaBufferBase>> buffer_bases;
   const size_t min_buffer_size;
   const size_t max_buffer_size;
   std::vector<uint8_t> buf;
};

// This class is simply to expose the destructor
@@ -53,32 +55,41 @@ class MediaBufferFuzzImpl : public MediaBuffer {
    ~MediaBufferFuzzImpl() {}
};

status_t IMediaSourceFuzzImpl::read(MediaBufferBase **buffer,
        const MediaSource::ReadOptions *options) {
status_t IMediaSourceFuzzImpl::read(MediaBufferBase** buffer, const MediaSource::ReadOptions*) {
    Vector<MediaBufferBase*> buffers;
    status_t ret = readMultiple(&buffers, 1, options);
    status_t ret = readMultiple(&buffers, 1, nullptr);
    *buffer = buffers.empty() ? nullptr : buffers[0];

    return ret;
}

status_t IMediaSourceFuzzImpl::readMultiple(Vector<MediaBufferBase*>* buffers,
        uint32_t maxNumBuffers, const MediaSource::ReadOptions*) {
    uint32_t num_buffers =
        fdp->ConsumeIntegralInRange<uint32_t>(0, maxNumBuffers);
    for(uint32_t i = 0; i < num_buffers; i++) {
        std::vector<uint8_t> buf = fdp->ConsumeBytes<uint8_t>(
            fdp->ConsumeIntegralInRange<size_t>(0, max_buffer_size));
status_t IMediaSourceFuzzImpl::readMultiple(Vector<MediaBufferBase*>* buffers, uint32_t,
                                            const MediaSource::ReadOptions*) {
    if (++frames_read == MAX_FRAMES) {
        auto size = fdp->ConsumeIntegralInRange<size_t>(min_buffer_size, max_buffer_size);
        buf = fdp->ConsumeBytes<uint8_t>(size);
        if (buf.size() < size) {
            buf.resize(size, 0);
        }

        MediaBufferBase* mbb = new MediaBufferFuzzImpl(buf.data(), buf.size());
        mbb->meta_data().setInt64(kKeyTime, fdp->ConsumeIntegral<uint64_t>());
        buffers->push_back(mbb);

        std::shared_ptr<MediaBufferBase> mbb(
            new MediaBufferFuzzImpl(buf.data(), buf.size()));
        return ERROR_END_OF_STREAM;
    }

        buffer_bases.push_back(mbb);
        buffers->push_back(mbb.get());
    auto size = fdp->ConsumeIntegralInRange<size_t>(min_buffer_size, max_buffer_size);
    buf = fdp->ConsumeBytes<uint8_t>(size);
    if (buf.size() < size) {
        buf.resize(size, 0);
    }

    // STATUS_OK
    return 0;
    MediaBufferBase* mbb = new MediaBufferFuzzImpl(buf.data(), buf.size());
    mbb->meta_data().setInt64(kKeyTime, fdp->ConsumeIntegral<uint64_t>());
    buffers->push_back(mbb);

    return OK;
}

} // namespace android
+10 −0
Original line number Diff line number Diff line
@@ -18,6 +18,7 @@
#define FUZZER_MEDIAMIMETYPES_H_

#include <media/stagefright/foundation/MediaDefs.h>
#include <unordered_map>

namespace android {

@@ -80,6 +81,15 @@ static const std::vector<const char*> kMimeTypes {
    MEDIA_MIMETYPE_DATA_TIMED_ID3
};

static const std::unordered_map<std::string, const char*> decoderToMediaType = {
        {"c2.android.vp8.decoder", MEDIA_MIMETYPE_VIDEO_VP8},
        {"c2.android.vp9.decoder", MEDIA_MIMETYPE_VIDEO_VP9},
        {"c2.android.av1.decoder", MEDIA_MIMETYPE_VIDEO_AV1},
        {"c2.android.avc.decoder", MEDIA_MIMETYPE_VIDEO_AVC},
        {"c2.android.hevc.decoder", MEDIA_MIMETYPE_VIDEO_HEVC},
        {"c2.android.mpeg4.decoder", MEDIA_MIMETYPE_VIDEO_MPEG4},
        {"c2.android.h263.decoder", MEDIA_MIMETYPE_VIDEO_H263}};

}  // namespace android

#endif  // FUZZER_MEDIAMIMETYPES_H_
Loading