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

Commit cbfdfe0d authored by Hamzeh Zawawy's avatar Hamzeh Zawawy Committed by Gerrit Code Review
Browse files

Merge "Adds fuzzer for MediaWriter and FrameDecoder"

parents 4e1eeb30 96f2c26a
Loading
Loading
Loading
Loading
+31 −2
Original line number Diff line number Diff line
@@ -9,6 +9,8 @@ cc_defaults {
    shared_libs: [
        "libstagefright",
        "libstagefright_codecbase",
        "libbase",
        "libcutils",
        "libutils",
        "libstagefright_foundation",
        "libmedia",
@@ -16,7 +18,10 @@ cc_defaults {
        "libmedia_omx",
        "libgui",
        "libbinder",
        "libcutils",
        "liblog",
    ],
    include_dirs: [
        "frameworks/av/media/libstagefright",
    ],
}

@@ -51,3 +56,27 @@ cc_fuzz {
    ],
    defaults: ["libstagefright_fuzzer_defaults"],
}

cc_fuzz {
    name: "libstagefright_frameDecoder_fuzzer",
    srcs: [
        "FrameDecoderFuzzer.cpp",
    ],
    defaults: ["libstagefright_fuzzer_defaults"],
}

cc_fuzz {
    name: "libstagefright_writer_fuzzer",
    srcs: [
        "FuzzerMediaUtility.cpp",
        "WriterFuzzer.cpp",
    ],
    dictionary: "dictionaries/formats.dict",
    defaults: ["libstagefright_fuzzer_defaults"],
    static_libs: [
        "libstagefright_webm",
        "libdatasource",
        "libstagefright_esds",
        "libogg",
    ],
}
+83 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 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 "include/FrameDecoder.h"
#include <fuzzer/FuzzedDataProvider.h>
#include <media/IMediaSource.h>
#include <media/stagefright/MetaData.h>
#include <media/stagefright/foundation/AString.h>
#include "FrameDecoderHelpers.h"
#include "IMediaSourceFuzzImpl.h"

namespace android {

#define MAX_MEDIA_BUFFER_SIZE 2048

// Fuzzer entry point.
extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
    // Init our wrapper
    FuzzedDataProvider fdp(data, size);

    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);
    } else {
        decoder = new ImageDecoder(componentName, trackMeta, source);
    }

    while (fdp.remaining_bytes()) {
        switch (fdp.ConsumeIntegralInRange<uint8_t>(0, 3)) {
            case 0:
                decoder->init(/*frameTimeUs*/ fdp.ConsumeIntegral<int64_t>(),
                              /*option*/ fdp.ConsumeIntegral<int>(),
                              /*colorFormat*/ fdp.ConsumeIntegral<int>());
                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>();
                decoder->extractFrame(&rect);
                break;
            }
            case 3: {
                sp<MetaData> trackMeta = generateMetaData(&fdp);
                decoder->getMetadataOnly(trackMeta,
                                         /*colorFormat*/ fdp.ConsumeIntegral<int>(),
                                         /*thumbnail*/ fdp.ConsumeBool());
                break;
            }
        }
    }

    generated_mime_types.clear();

    return 0;
}

}  // namespace android
+90 −0
Original line number Diff line number Diff line

/*
 * Copyright (C) 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.
 */

#pragma once

#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;

sp<MetaData> generateMetaData(FuzzedDataProvider *fdp) {
    sp<MetaData> newMeta = new MetaData();

    // random MIME Type
    const char *mime_type;
    size_t index = fdp->ConsumeIntegralInRange<size_t>(0, kMimeTypes.size());
    // Let there be a chance of a true random string
    if (index == kMimeTypes.size()) {
        std::string mime_str = fdp->ConsumeRandomLengthString(64);
        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();
    } else {
        mime_type = kMimeTypes[index];
    }
    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;
}

}  // namespace android
+124 −0
Original line number Diff line number Diff line
/*
 * 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 "FuzzerMediaUtility.h"

#include <media/stagefright/AACWriter.h>
#include <media/stagefright/AMRWriter.h>
#include <media/stagefright/MPEG2TSWriter.h>
#include <media/stagefright/MPEG4Writer.h>
#include <media/stagefright/OggWriter.h>

#include "MediaMimeTypes.h"
#include "webm/WebmWriter.h"

namespace android {
std::string genMimeType(FuzzedDataProvider *dataProvider) {
    uint8_t idx = dataProvider->ConsumeIntegralInRange<uint8_t>(0, kMimeTypes.size() - 1);
    return std::string(kMimeTypes[idx]);
}

sp<IMediaExtractor> genMediaExtractor(FuzzedDataProvider *dataProvider, std::string mimeType,
                                      uint16_t maxDataAmount) {
    uint32_t dataBlobSize = dataProvider->ConsumeIntegralInRange<uint16_t>(0, maxDataAmount);
    std::vector<uint8_t> data = dataProvider->ConsumeBytes<uint8_t>(dataBlobSize);
    // data:[<mediatype>][;base64],<data>
    std::string uri("data:");
    uri += mimeType;
    // Currently libstagefright only accepts base64 uris
    uri += ";base64,";
    android::AString out;
    android::encodeBase64(data.data(), data.size(), &out);
    uri += out.c_str();

    sp<DataSource> source =
        DataSourceFactory::getInstance()->CreateFromURI(NULL /* httpService */, uri.c_str());

    if (source == NULL) {
        return NULL;
    }

    return MediaExtractorFactory::Create(source);
}

sp<MediaSource> genMediaSource(FuzzedDataProvider *dataProvider, uint16_t maxMediaBlobSize) {
    std::string mime = genMimeType(dataProvider);
    sp<IMediaExtractor> extractor = genMediaExtractor(dataProvider, mime, maxMediaBlobSize);

    if (extractor == NULL) {
        return NULL;
    }

    for (size_t i = 0; i < extractor->countTracks(); ++i) {
        sp<MetaData> meta = extractor->getTrackMetaData(i);

        const char *trackMime;
        if (!strcasecmp(mime.c_str(), trackMime)) {
            sp<IMediaSource> track = extractor->getTrack(i);
            if (track == NULL) {
                return NULL;
            }
            return new CallbackMediaSource(track);
        }
    }

    return NULL;
}

sp<MediaWriter> createWriter(int fd, StandardWriters writerType, sp<MetaData> fileMeta) {
    sp<MediaWriter> writer;
    switch (writerType) {
        case OGG:
            writer = new OggWriter(fd);
            fileMeta->setInt32(kKeyFileType, output_format::OUTPUT_FORMAT_OGG);
            break;
        case AAC:
            writer = new AACWriter(fd);
            fileMeta->setInt32(kKeyFileType, output_format::OUTPUT_FORMAT_AAC_ADIF);
            break;
        case AAC_ADTS:
            writer = new AACWriter(fd);
            fileMeta->setInt32(kKeyFileType, output_format::OUTPUT_FORMAT_AAC_ADTS);
            break;
        case WEBM:
            writer = new WebmWriter(fd);
            fileMeta->setInt32(kKeyFileType, output_format::OUTPUT_FORMAT_WEBM);
            break;
        case MPEG4:
            writer = new MPEG4Writer(fd);
            fileMeta->setInt32(kKeyFileType, output_format::OUTPUT_FORMAT_MPEG_4);
            break;
        case AMR_NB:
            writer = new AMRWriter(fd);
            fileMeta->setInt32(kKeyFileType, output_format::OUTPUT_FORMAT_AMR_NB);
            break;
        case AMR_WB:
            writer = new AMRWriter(fd);
            fileMeta->setInt32(kKeyFileType, output_format::OUTPUT_FORMAT_AMR_WB);
            break;
        case MPEG2TS:
            writer = new MPEG2TSWriter(fd);
            fileMeta->setInt32(kKeyFileType, output_format::OUTPUT_FORMAT_MPEG2TS);
            break;
        default:
            return nullptr;
    }
    if (writer != nullptr) {
        fileMeta->setInt32(kKeyRealTimeRecording, false);
    }
    return writer;
}
}  // namespace android
 No newline at end of file
+50 −0
Original line number Diff line number Diff line
/*
 * 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.
 */

#pragma once
#include <datasource/DataSourceFactory.h>
#include <fuzzer/FuzzedDataProvider.h>
#include <android/IMediaExtractor.h>
#include <media/IMediaHTTPService.h>
#include <media/mediarecorder.h>
#include <media/stagefright/CallbackMediaSource.h>
#include <media/stagefright/MediaDefs.h>
#include <media/stagefright/MediaExtractorFactory.h>
#include <media/stagefright/MediaWriter.h>
#include <media/stagefright/MetaData.h>
#include <media/stagefright/foundation/base64.h>
#include <utils/StrongPointer.h>

namespace android {
enum StandardWriters {
    OGG,
    AAC,
    AAC_ADTS,
    WEBM,
    MPEG4,
    AMR_NB,
    AMR_WB,
    MPEG2TS,
    // Allows FuzzedDataProvider to find the end of this enum.
    kMaxValue = MPEG2TS,
};

std::string genMimeType(FuzzedDataProvider *dataProvider);
sp<IMediaExtractor> genMediaExtractor(FuzzedDataProvider *dataProvider, uint16_t dataAmount);
sp<MediaSource> genMediaSource(FuzzedDataProvider *dataProvider, uint16_t maxMediaBlobSize);

sp<MediaWriter> createWriter(int32_t fd, StandardWriters writerType, sp<MetaData> fileMeta);
}  // namespace android
Loading