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

Commit 18b6f5a3 authored by Aditya Wazir's avatar Aditya Wazir Committed by Ayushi Khopkar
Browse files

Added ndk_mediamuxer_fuzzer

Test: ./ndk_mediamuxer_fuzzer
Bug: 231667886

Change-Id: I95f920ef852f3420fd33b49c14b5217988b5f280
(cherry picked from commit 57605912985a45fc336f8753a582714810b2888a)
parent e9eca479
Loading
Loading
Loading
Loading
+7 −0
Original line number Diff line number Diff line
@@ -90,3 +90,10 @@ cc_fuzz {
    srcs: ["ndk_drm_fuzzer.cpp"],
    defaults: ["libmediandk_fuzzer_defaults",],
}

cc_fuzz {
    name: "ndk_mediamuxer_fuzzer",
    srcs: ["ndk_mediamuxer_fuzzer.cpp"],
    defaults: ["libmediandk_fuzzer_defaults"],
    shared_libs: ["libbinder_ndk",],
}
+24 −0
Original line number Diff line number Diff line
@@ -6,6 +6,7 @@
+ [ndk_extractor_fuzzer](#NdkExtractor)
+ [ndk_mediaformat_fuzzer](#NdkMediaFormat)
+ [ndk_drm_fuzzer](#NdkDrm)
+ [ndk_mediamuxer_fuzzer](#NdkMediaMuxer)

# <a name="NdkCrypto"></a> Fuzzer for NdkCrypto

@@ -75,6 +76,7 @@ NdkExtractor supports the following parameters:
  $ adb shell /data/fuzz/arm64/ndk_extractor_fuzzer/ndk_extractor_fuzzer /data/fuzz/${TARGET_ARCH}/ndk_extractor_fuzzer/corpus
```


# <a name="NdkMediaFormat"></a>Fuzzer for NdkMediaFormat

NdkMediaFormat supports the following parameters:
@@ -118,3 +120,25 @@ NdkDrm supports the following parameters:
  $ adb sync data
  $ adb shell /data/fuzz/arm64/ndk_drm_fuzzer/ndk_drm_fuzzer
```

# <a name="NdkMediaMuxer"></a>Fuzzer for NdkMediaMuxer

NdkMediaMuxer supports the following parameters:
1. OutputFormat (parameter name: "outputFormat")
2. AppendMode (parameter name: "appendMode")

| Parameter| Valid Values |Configured Value|
|-------------|----------|----- |
|`outputFormat`|0.`AMEDIAMUXER_OUTPUT_FORMAT_MPEG_4`,<br/>1.`AMEDIAMUXER_OUTPUT_FORMAT_WEBM`,<br/>2.`AMEDIAMUXER_OUTPUT_FORMAT_THREE_GPP`| Value obtained from FuzzedDataProvider|
|`appendMode`|0.`AMEDIAMUXER_APPEND_IGNORE_LAST_VIDEO_GOP`,<br/>1.`AMEDIAMUXER_APPEND_TO_EXISTING_DATA`| Value obtained from FuzzedDataProvider|

#### Steps to run
1. Build the fuzzer
```
  $ mm -j$(nproc) ndk_mediamuxer_fuzzer
```
2. Run on device
```
  $ adb sync data
  $ adb shell /data/fuzz/arm64/ndk_mediamuxer_fuzzer/ndk_mediamuxer_fuzzer
```
+158 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2022 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/binder_process.h>
#include <fcntl.h>
#include <fuzzer/FuzzedDataProvider.h>
#include <media/NdkMediaMuxer.h>
#include <sys/mman.h>
#include <unistd.h>

const std::string kMuxerFile = "mediaMuxer";
const std::string kAppendFile = "mediaAppend";
constexpr size_t kMinBytes = 0;
constexpr size_t kMaxBytes = 1000;
constexpr size_t kMinChoice = 0;
constexpr size_t kMaxChoice = 7;
constexpr size_t kMaxStringLength = 20;
constexpr size_t kOffset = 0;

constexpr OutputFormat kOutputFormat[] = {AMEDIAMUXER_OUTPUT_FORMAT_MPEG_4,
                                          AMEDIAMUXER_OUTPUT_FORMAT_WEBM,
                                          AMEDIAMUXER_OUTPUT_FORMAT_THREE_GPP};
constexpr AppendMode kAppendMode[] = {AMEDIAMUXER_APPEND_IGNORE_LAST_VIDEO_GOP,
                                      AMEDIAMUXER_APPEND_TO_EXISTING_DATA};

const std::string kAudioMimeType[] = {"audio/3gpp", "audio/amr-wb", "audio/mp4a-latm",
                                      "audio/flac", "audio/vorbis", "audio/opus"};

const std::string kVideoMimeType[] = {"video/x-vnd.on2.vp8", "video/x-vnd.on2.vp9", "video/av01",
                                      "video/avc",           "video/hevc",          "video/mp4v-es",
                                      "video/3gpp"};

void getSampleAudioFormat(FuzzedDataProvider& fdp, AMediaFormat* format) {
    std::string mimeType = fdp.ConsumeBool() ? fdp.ConsumeRandomLengthString(kMaxStringLength)
                                             : fdp.PickValueInArray(kAudioMimeType);
    AMediaFormat_setString(format, AMEDIAFORMAT_KEY_MIME, mimeType.c_str());
    AMediaFormat_setInt32(format, AMEDIAFORMAT_KEY_BIT_RATE, fdp.ConsumeIntegral<int32_t>());
    AMediaFormat_setInt32(format, AMEDIAFORMAT_KEY_SAMPLE_RATE, fdp.ConsumeIntegral<int32_t>());
    AMediaFormat_setInt32(format, AMEDIAFORMAT_KEY_CHANNEL_COUNT, fdp.ConsumeIntegral<int32_t>());
    AMediaFormat_setInt64(format, AMEDIAFORMAT_KEY_DURATION, fdp.ConsumeIntegral<int64_t>());
}

void getSampleVideoFormat(FuzzedDataProvider& fdp, AMediaFormat* format) {
    std::string mimeType = fdp.ConsumeBool() ? fdp.ConsumeRandomLengthString(kMaxStringLength)
                                             : fdp.PickValueInArray(kAudioMimeType);
    AMediaFormat_setString(format, AMEDIAFORMAT_KEY_MIME, mimeType.c_str());
    AMediaFormat_setInt32(format, AMEDIAFORMAT_KEY_BIT_RATE, fdp.ConsumeIntegral<int32_t>());
    AMediaFormat_setInt32(format, AMEDIAFORMAT_KEY_WIDTH, fdp.ConsumeIntegral<int32_t>());
    AMediaFormat_setInt32(format, AMEDIAFORMAT_KEY_HEIGHT, fdp.ConsumeIntegral<int32_t>());
    AMediaFormat_setInt32(format, AMEDIAFORMAT_KEY_FRAME_RATE, fdp.ConsumeIntegral<int32_t>());
    AMediaFormat_setFloat(format, AMEDIAFORMAT_KEY_I_FRAME_INTERVAL,
                          fdp.ConsumeFloatingPoint<float>());
    AMediaFormat_setFloat(format, AMEDIAFORMAT_KEY_CAPTURE_RATE, fdp.ConsumeFloatingPoint<float>());
    AMediaFormat_setInt32(format, AMEDIAFORMAT_KEY_COLOR_FORMAT, fdp.ConsumeIntegral<int32_t>());
}

extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
    /**
     * Create a threadpool for incoming binder transactions,
     * without this muxer results in a DoS after few instances.
     */
    ABinderProcess_startThreadPool();
    FuzzedDataProvider fdp(data, size);
    /**
     * memfd_create() creates an anonymous file and returns a file
     * descriptor that refers to it. MFD_ALLOW_SEALING allow sealing
     * operations on this file.
     */
    int32_t fd = -1;
    AMediaMuxer* muxer = nullptr;
    if (fdp.ConsumeBool()) {
        fd = memfd_create(kMuxerFile.c_str(), MFD_ALLOW_SEALING);
        muxer = AMediaMuxer_new(fd, fdp.ConsumeBool()
                                            ? fdp.PickValueInArray(kOutputFormat)
                                            : (OutputFormat)fdp.ConsumeIntegral<int32_t>());
    } else {
        fd = memfd_create(kAppendFile.c_str(), MFD_ALLOW_SEALING);
        std::vector<uint8_t> appendData =
                fdp.ConsumeBytes<uint8_t>(fdp.ConsumeIntegralInRange<size_t>(kMinBytes, kMaxBytes));
        write(fd, appendData.data(), appendData.size());
        muxer = AMediaMuxer_append(fd, fdp.PickValueInArray(kAppendMode) /* mode */);
    }
    if (!muxer) {
        close(fd);
        return 0;
    }
    AMediaFormat* mediaFormat = nullptr;
    ssize_t trackIdx = 0;
    while (fdp.remaining_bytes()) {
        int32_t kSwitchChoice = fdp.ConsumeIntegralInRange<int32_t>(kMinChoice, kMaxChoice);
        switch (kSwitchChoice) {
            case 0: {
                AMediaMuxer_setLocation(muxer, fdp.ConsumeFloatingPoint<float>() /* latitude */,
                                        fdp.ConsumeFloatingPoint<float>() /* longitude */);
                break;
            }
            case 1: {
                AMediaMuxer_setOrientationHint(muxer, fdp.ConsumeIntegral<int32_t>() /* degrees */);
                break;
            }
            case 2: {
                AMediaMuxer_start(muxer);
                break;
            }
            case 3: {
                AMediaMuxer_stop(muxer);
                break;
            }
            case 4: {
                AMediaMuxer_getTrackCount(muxer);
                break;
            }
            case 5: {
                AMediaFormat* getFormat =
                        AMediaMuxer_getTrackFormat(muxer, fdp.ConsumeIntegral<size_t>() /* idx */);
                AMediaFormat_delete(getFormat);
                break;
            }
            case 6: {
                mediaFormat = AMediaFormat_new();
                fdp.ConsumeBool() ? getSampleAudioFormat(fdp, mediaFormat)
                                  : getSampleVideoFormat(fdp, mediaFormat);
                trackIdx = AMediaMuxer_addTrack(muxer, mediaFormat);
                AMediaFormat_delete(mediaFormat);
                break;
            }
            default: {
                std::vector<uint8_t> sampleData = fdp.ConsumeBytes<uint8_t>(
                        fdp.ConsumeIntegralInRange<size_t>(kMinBytes, kMaxBytes));
                AMediaCodecBufferInfo codecBuffer;
                codecBuffer.size = sampleData.size();
                codecBuffer.offset = kOffset;
                codecBuffer.presentationTimeUs = fdp.ConsumeIntegral<int64_t>();
                codecBuffer.flags = fdp.ConsumeIntegral<uint32_t>();
                AMediaMuxer_writeSampleData(
                        muxer,
                        fdp.ConsumeBool() ? trackIdx : fdp.ConsumeIntegral<size_t>() /* trackIdx */,
                        sampleData.data(), &codecBuffer);
                break;
            }
        }
    }
    AMediaMuxer_delete(muxer);
    close(fd);
    return 0;
}