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

Commit 601b8c31 authored by Treehugger Robot's avatar Treehugger Robot Committed by Gerrit Code Review
Browse files

Merge "Refactored libstagefright_mediamuxer_fuzzer" into main

parents 8b634267 c51da1b0
Loading
Loading
Loading
Loading
+9 −0
Original line number Diff line number Diff line
@@ -32,6 +32,15 @@ cc_defaults {
        "liblog",
        "media_permission-aidl-cpp",
    ],
    fuzz_config: {
        componentid: 42195,
        hotlists: ["4593311"],
        description: "The fuzzer targets the APIs of libstagefright",
        vector: "local_no_privileges_required",
        service_privilege: "constrained",
        users: "multi_user",
        fuzzed_code_usage: "shipped",
    },
}

cc_fuzz {
+199 −72
Original line number Diff line number Diff line
@@ -13,93 +13,220 @@
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
// Authors: corbin.souffrant@leviathansecurity.com
//          dylan.katz@leviathansecurity.com

#include <MediaMuxerFuzzer.h>
#include <cutils/ashmem.h>
#include <fuzzer/FuzzedDataProvider.h>
#include <media/stagefright/MediaMuxer.h>
#include <media/stagefright/foundation/ABuffer.h>
#include <media/stagefright/foundation/AMessage.h>
#include <media/stagefright/foundation/MediaDefs.h>

namespace android {
const uint8_t kMinSize = 0;
const uint8_t kMinTrackCount = 0;

// Can't seem to get setBuffer or setString working. It always segfaults on a
// null pointer read or memleaks. So that functionality is missing.
void createMessage(AMessage *msg, FuzzedDataProvider *fdp) {
  size_t count = fdp->ConsumeIntegralInRange<size_t>(0, 32);
  while (fdp->remaining_bytes() > 0 && count > 0) {
    uint8_t function_id =
        fdp->ConsumeIntegralInRange<uint8_t>(0, amessage_setvals.size() - 1);
    amessage_setvals[function_id](msg, fdp);
    count--;
enum kBufferFlags { BUFFER_FLAG_SYNCFRAME = 1, BUFFER_FLAG_CODECCONFIG = 2, BUFFER_FLAG_EOS = 4 };

constexpr char kMuxerFile[] = "MediaMuxer";

const std::string kAudioMimeTypes[] = {
        MEDIA_MIMETYPE_AUDIO_AMR_NB,
        MEDIA_MIMETYPE_AUDIO_AMR_WB,
        MEDIA_MIMETYPE_AUDIO_MPEG,
        MEDIA_MIMETYPE_AUDIO_MPEG_LAYER_I,
        MEDIA_MIMETYPE_AUDIO_MPEG_LAYER_II,
        MEDIA_MIMETYPE_AUDIO_MIDI,
        MEDIA_MIMETYPE_AUDIO_AAC,
        MEDIA_MIMETYPE_AUDIO_QCELP,
        MEDIA_MIMETYPE_AUDIO_VORBIS,
        MEDIA_MIMETYPE_AUDIO_OPUS,
        MEDIA_MIMETYPE_AUDIO_G711_ALAW,
        MEDIA_MIMETYPE_AUDIO_G711_MLAW,
        MEDIA_MIMETYPE_AUDIO_RAW,
        MEDIA_MIMETYPE_AUDIO_FLAC,
        MEDIA_MIMETYPE_AUDIO_AAC_ADTS,
        MEDIA_MIMETYPE_AUDIO_MSGSM,
        MEDIA_MIMETYPE_AUDIO_AC3,
        MEDIA_MIMETYPE_AUDIO_EAC3,
        MEDIA_MIMETYPE_AUDIO_EAC3_JOC,
        MEDIA_MIMETYPE_AUDIO_AC4,
        MEDIA_MIMETYPE_AUDIO_MPEGH_MHA1,
        MEDIA_MIMETYPE_AUDIO_MPEGH_MHM1,
        MEDIA_MIMETYPE_AUDIO_MPEGH_BL_L3,
        MEDIA_MIMETYPE_AUDIO_MPEGH_BL_L4,
        MEDIA_MIMETYPE_AUDIO_MPEGH_LC_L3,
        MEDIA_MIMETYPE_AUDIO_MPEGH_LC_L4,
        MEDIA_MIMETYPE_AUDIO_SCRAMBLED,
        MEDIA_MIMETYPE_AUDIO_ALAC,
        MEDIA_MIMETYPE_AUDIO_WMA,
        MEDIA_MIMETYPE_AUDIO_MS_ADPCM,
        MEDIA_MIMETYPE_AUDIO_DVI_IMA_ADPCM,
        MEDIA_MIMETYPE_AUDIO_DTS,
        MEDIA_MIMETYPE_AUDIO_DTS_HD,
        MEDIA_MIMETYPE_AUDIO_DTS_HD_MA,
        MEDIA_MIMETYPE_AUDIO_DTS_UHD,
        MEDIA_MIMETYPE_AUDIO_DTS_UHD_P1,
        MEDIA_MIMETYPE_AUDIO_DTS_UHD_P2,
        MEDIA_MIMETYPE_AUDIO_EVRC,
        MEDIA_MIMETYPE_AUDIO_EVRCB,
        MEDIA_MIMETYPE_AUDIO_EVRCWB,
        MEDIA_MIMETYPE_AUDIO_EVRCNW,
        MEDIA_MIMETYPE_AUDIO_AMR_WB_PLUS,
        MEDIA_MIMETYPE_AUDIO_APTX,
        MEDIA_MIMETYPE_AUDIO_DRA,
        MEDIA_MIMETYPE_AUDIO_DOLBY_MAT,
        MEDIA_MIMETYPE_AUDIO_DOLBY_MAT_1_0,
        MEDIA_MIMETYPE_AUDIO_DOLBY_MAT_2_0,
        MEDIA_MIMETYPE_AUDIO_DOLBY_MAT_2_1,
        MEDIA_MIMETYPE_AUDIO_DOLBY_TRUEHD,
        MEDIA_MIMETYPE_AUDIO_AAC_MP4,
        MEDIA_MIMETYPE_AUDIO_AAC_MAIN,
        MEDIA_MIMETYPE_AUDIO_AAC_LC,
        MEDIA_MIMETYPE_AUDIO_AAC_SSR,
        MEDIA_MIMETYPE_AUDIO_AAC_LTP,
        MEDIA_MIMETYPE_AUDIO_AAC_HE_V1,
        MEDIA_MIMETYPE_AUDIO_AAC_SCALABLE,
        MEDIA_MIMETYPE_AUDIO_AAC_ERLC,
        MEDIA_MIMETYPE_AUDIO_AAC_LD,
        MEDIA_MIMETYPE_AUDIO_AAC_HE_V2,
        MEDIA_MIMETYPE_AUDIO_AAC_ELD,
        MEDIA_MIMETYPE_AUDIO_AAC_XHE,
        MEDIA_MIMETYPE_AUDIO_AAC_ADIF,
        MEDIA_MIMETYPE_AUDIO_AAC_ADTS_MAIN,
        MEDIA_MIMETYPE_AUDIO_AAC_ADTS_LC,
        MEDIA_MIMETYPE_AUDIO_AAC_ADTS_SSR,
        MEDIA_MIMETYPE_AUDIO_AAC_ADTS_LTP,
        MEDIA_MIMETYPE_AUDIO_AAC_ADTS_HE_V1,
        MEDIA_MIMETYPE_AUDIO_AAC_ADTS_SCALABLE,
        MEDIA_MIMETYPE_AUDIO_AAC_ADTS_ERLC,
        MEDIA_MIMETYPE_AUDIO_AAC_ADTS_LD,
        MEDIA_MIMETYPE_AUDIO_AAC_ADTS_HE_V2,
        MEDIA_MIMETYPE_AUDIO_AAC_ADTS_ELD,
        MEDIA_MIMETYPE_AUDIO_AAC_ADTS_XHE,
        MEDIA_MIMETYPE_AUDIO_AAC_LATM_LC,
        MEDIA_MIMETYPE_AUDIO_AAC_LATM_HE_V1,
        MEDIA_MIMETYPE_AUDIO_AAC_LATM_HE_V2,
        MEDIA_MIMETYPE_AUDIO_IEC61937,
        MEDIA_MIMETYPE_AUDIO_IEC60958,
};

const std::string kVideoMimeTypes[] = {
        MEDIA_MIMETYPE_VIDEO_VP8,       MEDIA_MIMETYPE_VIDEO_VP9,
        MEDIA_MIMETYPE_VIDEO_AV1,       MEDIA_MIMETYPE_VIDEO_AVC,
        MEDIA_MIMETYPE_VIDEO_HEVC,      MEDIA_MIMETYPE_VIDEO_MPEG4,
        MEDIA_MIMETYPE_VIDEO_H263,      MEDIA_MIMETYPE_VIDEO_MPEG2,
        MEDIA_MIMETYPE_VIDEO_RAW,       MEDIA_MIMETYPE_VIDEO_DOLBY_VISION,
        MEDIA_MIMETYPE_VIDEO_SCRAMBLED, MEDIA_MIMETYPE_VIDEO_DIVX,
        MEDIA_MIMETYPE_VIDEO_DIVX3,     MEDIA_MIMETYPE_VIDEO_XVID,
        MEDIA_MIMETYPE_VIDEO_MJPEG,
};

void getSampleAudioFormat(FuzzedDataProvider& fdp, AMessage* format) {
    std::string mimeType = fdp.PickValueInArray(kAudioMimeTypes);
    format->setString("mime", mimeType.c_str(), mimeType.length());
    format->setInt32("sample-rate", fdp.ConsumeIntegral<int32_t>());
    format->setInt32("channel-count", fdp.ConsumeIntegral<int32_t>());
}

void getSampleVideoFormat(FuzzedDataProvider& fdp, AMessage* format) {
    std::string mimeType = fdp.PickValueInArray(kVideoMimeTypes);
    format->setString("mime", mimeType.c_str(), mimeType.length());
    format->setInt32("height", fdp.ConsumeIntegral<int32_t>());
    format->setInt32("width", fdp.ConsumeIntegral<int32_t>());
    format->setInt32("time-lapse-fps", fdp.ConsumeIntegral<int32_t>());
}

extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
  FuzzedDataProvider fdp = FuzzedDataProvider(data, size);
    FuzzedDataProvider fdp(data, size);

  size_t data_size = fdp.ConsumeIntegralInRange<size_t>(0, size);
  int fd = ashmem_create_region("mediamuxer_fuzz_region", data_size);
  if (fd < 0)
    // memfd_create() creates an anonymous file and returns a file
    // descriptor that refers to it. MFD_ALLOW_SEALING allows sealing
    // operations on this file.
    int32_t fd = memfd_create(kMuxerFile, MFD_ALLOW_SEALING);
    if (fd == -1) {
        ALOGE("memfd_create failed: %s", strerror(errno));
        return 0;
    }

  uint8_t *sh_data = static_cast<uint8_t *>(
      mmap(NULL, data_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0));
  if (sh_data == MAP_FAILED)
    return 0;
    auto outputFormat = (MediaMuxer::OutputFormat)fdp.ConsumeIntegralInRange<int32_t>(
            MediaMuxer::OutputFormat::OUTPUT_FORMAT_MPEG_4,
            MediaMuxer::OutputFormat::OUTPUT_FORMAT_LIST_END);

  MediaMuxer::OutputFormat format =
      (MediaMuxer::OutputFormat)fdp.ConsumeIntegralInRange<int32_t>(0, 4);
  sp<MediaMuxer> mMuxer = MediaMuxer::create(fd, format);
    sp<MediaMuxer> mMuxer = MediaMuxer::create(fd, outputFormat);
    if (mMuxer == nullptr) {
        close(fd);
        return 0;
    }

  while (fdp.remaining_bytes() > 1) {
    switch (fdp.ConsumeIntegralInRange<uint8_t>(0, 4)) {
    case 0: {
      // For some reason it only likes mp4s here...
      if (format == 1 || format == 4)
        break;

      sp<AMessage> a_format(new AMessage);
      createMessage(a_format.get(), &fdp);
      mMuxer->addTrack(a_format);
      break;
    // Used to consume a maximum of 80% of the data to send buffer data to writeSampleData().
    // This ensures that we don't completely exhaust data and use the rest 20% for fuzzing
    // of APIs.
    const size_t kMaxSize = (size * 80) / 100;
    while (fdp.remaining_bytes()) {
        auto invokeMediaMuxerAPI = fdp.PickValueInArray<const std::function<void()>>({
                [&]() {
                    // Using 'return' here due to a timeout bug present in OGGWriter.cpp
                    // (b/310316183).
                    if (outputFormat == MediaMuxer::OutputFormat::OUTPUT_FORMAT_OGG) {
                        return;
                    }
    case 1: {
      mMuxer->start();
      break;

                    sp<AMessage> format = sp<AMessage>::make();
                    fdp.ConsumeBool() ? getSampleAudioFormat(fdp, format.get())
                                      : getSampleVideoFormat(fdp, format.get());

                    mMuxer->addTrack(fdp.ConsumeBool() ? format : nullptr);
                },
                [&]() {
                    mMuxer->setLocation(fdp.ConsumeIntegral<int32_t>() /* latitude */,
                                        fdp.ConsumeIntegral<int32_t>() /* longitude */);
                },
                [&]() { mMuxer->setOrientationHint(fdp.ConsumeIntegral<int32_t>() /* degrees */); },
                [&]() { mMuxer->start(); },
                [&]() {
                    std::vector<uint8_t> sample = fdp.ConsumeBytes<uint8_t>(
                            fdp.ConsumeIntegralInRange<size_t>(kMinSize, kMaxSize));
                    sp<ABuffer> buffer = sp<ABuffer>::make(sample.data(), sample.size());

                    size_t offset = fdp.ConsumeIntegralInRange<size_t>(kMinSize, sample.size());
                    size_t length =
                            fdp.ConsumeIntegralInRange<size_t>(kMinSize, buffer->size() - offset);
                    buffer->setRange(offset, length);

                    sp<AMessage> meta = buffer->meta();
                    meta->setInt64("sample-file-offset", fdp.ConsumeIntegral<int64_t>());
                    meta->setInt64("last-sample-index-in-chunk", fdp.ConsumeIntegral<int64_t>());

                    uint32_t flags = 0;
                    if (fdp.ConsumeBool()) {
                        flags |= kBufferFlags::BUFFER_FLAG_SYNCFRAME;
                    }
    case 2: {
      int degrees = fdp.ConsumeIntegral<int>();
      mMuxer->setOrientationHint(degrees);
      break;
                    if (fdp.ConsumeBool()) {
                        flags |= kBufferFlags::BUFFER_FLAG_CODECCONFIG;
                    }
    case 3: {
      int latitude = fdp.ConsumeIntegral<int>();
      int longitude = fdp.ConsumeIntegral<int>();
      mMuxer->setLocation(latitude, longitude);
      break;
                    if (fdp.ConsumeBool()) {
                        flags |= kBufferFlags::BUFFER_FLAG_EOS;
                    }
    case 4: {
      size_t buf_size = fdp.ConsumeIntegralInRange<size_t>(0, data_size);
      sp<ABuffer> a_buffer(new ABuffer(buf_size));

      size_t trackIndex = fdp.ConsumeIntegral<size_t>();
                    size_t trackIndex = fdp.ConsumeBool()
                                                ? fdp.ConsumeIntegralInRange<size_t>(
                                                          kMinTrackCount, mMuxer->getTrackCount())
                                                : fdp.ConsumeIntegral<size_t>();
                    int64_t timeUs = fdp.ConsumeIntegral<int64_t>();
      uint32_t flags = fdp.ConsumeIntegral<uint32_t>();
      mMuxer->writeSampleData(a_buffer, trackIndex, timeUs, flags);
    }
    }
  }
                    mMuxer->writeSampleData(fdp.ConsumeBool() ? buffer : nullptr, trackIndex,
                                            timeUs, flags);
                },
                [&]() {
                    mMuxer->getTrackFormat(
                            fdp.ConsumeBool() ? fdp.ConsumeIntegralInRange<size_t>(
                                                        kMinTrackCount, mMuxer->getTrackCount())
                                              : fdp.ConsumeIntegral<size_t>() /* idx */);
                },
                [&]() { mMuxer->stop(); },
        });

  if (fdp.ConsumeBool())
    mMuxer->stop();
        invokeMediaMuxerAPI();
    }

  munmap(sh_data, data_size);
    close(fd);
    return 0;
}
+0 −109
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.
 */
// Authors: corbin.souffrant@leviathansecurity.com
//          dylan.katz@leviathansecurity.com

#pragma once

#include <fuzzer/FuzzedDataProvider.h>
#include <media/stagefright/foundation/AMessage.h>

namespace android {

// Mappings vectors are the list of attributes that the MediaMuxer
// class looks for in the message.
static std::vector<const char *> floatMappings{
    "capture-rate",
    "time-lapse-fps",
    "frame-rate",
};

static std::vector<const char *> int64Mappings{
    "exif-offset",    "exif-size", "target-time",
    "thumbnail-time", "timeUs",    "durationUs",
};

static std::vector<const char *> int32Mappings{"loop",
                                               "time-scale",
                                               "crypto-mode",
                                               "crypto-default-iv-size",
                                               "crypto-encrypted-byte-block",
                                               "crypto-skip-byte-block",
                                               "frame-count",
                                               "max-bitrate",
                                               "pcm-big-endian",
                                               "temporal-layer-count",
                                               "temporal-layer-id",
                                               "thumbnail-width",
                                               "thumbnail-height",
                                               "track-id",
                                               "valid-samples",
                                               "color-format",
                                               "ca-system-id",
                                               "is-sync-frame",
                                               "bitrate",
                                               "max-bitrate",
                                               "width",
                                               "height",
                                               "sar-width",
                                               "sar-height",
                                               "display-width",
                                               "display-height",
                                               "is-default",
                                               "tile-width",
                                               "tile-height",
                                               "grid-rows",
                                               "grid-cols",
                                               "rotation-degrees",
                                               "channel-count",
                                               "sample-rate",
                                               "bits-per-sample",
                                               "channel-mask",
                                               "encoder-delay",
                                               "encoder-padding",
                                               "is-adts",
                                               "frame-rate",
                                               "max-height",
                                               "max-width",
                                               "max-input-size",
                                               "haptic-channel-count",
                                               "pcm-encoding",
                                               "aac-profile"};

static const std::vector<std::function<void(AMessage *, FuzzedDataProvider *)>>
    amessage_setvals = {
        [](AMessage *msg, FuzzedDataProvider *fdp) -> void {
          msg->setRect("crop", fdp->ConsumeIntegral<int32_t>(),
                       fdp->ConsumeIntegral<int32_t>(),
                       fdp->ConsumeIntegral<int32_t>(),
                       fdp->ConsumeIntegral<int32_t>());
        },
        [](AMessage *msg, FuzzedDataProvider *fdp) -> void {
          msg->setFloat(floatMappings[fdp->ConsumeIntegralInRange<size_t>(
                            0, floatMappings.size() - 1)],
                        fdp->ConsumeFloatingPoint<float>());
        },
        [](AMessage *msg, FuzzedDataProvider *fdp) -> void {
          msg->setInt64(int64Mappings[fdp->ConsumeIntegralInRange<size_t>(
                            0, int64Mappings.size() - 1)],
                        fdp->ConsumeIntegral<int64_t>());
        },
        [](AMessage *msg, FuzzedDataProvider *fdp) -> void {
          msg->setInt32(int32Mappings[fdp->ConsumeIntegralInRange<size_t>(
                            0, int32Mappings.size() - 1)],
                        fdp->ConsumeIntegral<int32_t>());
        }};
} // namespace android