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

Commit 3df11ed5 authored by Hamzeh Zawawy's avatar Hamzeh Zawawy Committed by Automerger Merge Worker
Browse files

Merge "Adds fuzzer for MediaWriter and FrameDecoder" am: cbfdfe0d

Original change: https://android-review.googlesource.com/c/platform/frameworks/av/+/1363817

MUST ONLY BE SUBMITTED BY AUTOMERGER

Change-Id: Ifcb1ff8a2f811e7cf6303e5fcf1eaf566a51dccf
parents f7a2c50f cbfdfe0d
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