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

Commit e4ce69c0 authored by Kris Alder's avatar Kris Alder Committed by Automerger Merge Worker
Browse files

Merge changes I446495dc,I5c5de9d4 am: fbb38e2c

Change-Id: Ieea1f630b719b31e5e52050dc2b253bad6d74233
parents 42a533d8 fbb38e2c
Loading
Loading
Loading
Loading
+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.
 *
 *****************************************************************************
 * Originally developed and contributed by Ittiam Systems Pvt. Ltd, Bangalore
 */

cc_library {
    name: "libextractorfuzzerbase",

    srcs: [
        "ExtractorFuzzerBase.cpp",
    ],

    local_include_dirs: [
        "include",
    ],

    export_include_dirs: [
        "include",
    ],

    static_libs: [
        "liblog",
        "libstagefright_foundation",
        "libmedia",
    ],

    shared_libs: [
        "libutils",
        "libbinder",
        "libmediandk",
    ],

    /* GETEXTRACTORDEF is not defined as extractor library is not linked in the
     * base class. It will be included when the extractor fuzzer binary is
     * generated.
     */
    allow_undefined_symbols: true,
}

cc_fuzz {
    name: "mp4_extractor_fuzzer",

    srcs: [
        "mp4_extractor_fuzzer.cpp",
    ],

    include_dirs: [
        "frameworks/av/media/extractors/mp4",
    ],

    static_libs: [
        "liblog",
        "libstagefright_foundation",
        "libmedia",
        "libextractorfuzzerbase",
        "libstagefright_id3",
        "libstagefright_esds",
        "libmp4extractor",
    ],

    shared_libs: [
        "libutils",
        "libmediandk",
        "libbinder",
    ],

    dictionary: "mp4_extractor_fuzzer.dict",
}
+118 −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.
 */

//#define LOG_NDEBUG 0
#define LOG_TAG "ExtractorFuzzerBase"
#include <utils/Log.h>

#include "ExtractorFuzzerBase.h"

using namespace android;

bool ExtractorFuzzerBase::setDataSource(const uint8_t* data, size_t size) {
  if ((!data) || (size == 0)) {
    return false;
  }
  mBufferSource = new BufferSource(data, size);
  mDataSource = reinterpret_cast<DataSource*>(mBufferSource.get());
  if (!mDataSource) {
    return false;
  }
  return true;
}

bool ExtractorFuzzerBase::getExtractorDef() {
  float confidence;
  void* meta = nullptr;
  FreeMetaFunc freeMeta = nullptr;

  ExtractorDef extractorDef = GETEXTRACTORDEF();
  if (extractorDef.def_version == EXTRACTORDEF_VERSION_NDK_V1) {
    extractorDef.u.v2.sniff(mDataSource->wrap(), &confidence, &meta, &freeMeta);
  } else if (extractorDef.def_version == EXTRACTORDEF_VERSION_NDK_V2) {
    extractorDef.u.v3.sniff(mDataSource->wrap(), &confidence, &meta, &freeMeta);
  }

  if (meta != nullptr && freeMeta != nullptr) {
    freeMeta(meta);
  }

  return true;
}

bool ExtractorFuzzerBase::extractTracks() {
  MediaBufferGroup* bufferGroup = new MediaBufferGroup();
  if (!bufferGroup) {
    return false;
  }
  for (size_t trackIndex = 0; trackIndex < mExtractor->countTracks(); ++trackIndex) {
    MediaTrackHelper* track = mExtractor->getTrack(trackIndex);
    if (!track) {
      continue;
    }
    extractTrack(track, bufferGroup);
    delete track;
  }
  delete bufferGroup;
  return true;
}

void ExtractorFuzzerBase::extractTrack(MediaTrackHelper* track, MediaBufferGroup* bufferGroup) {
  CMediaTrack* cTrack = wrap(track);
  if (!cTrack) {
    return;
  }

  media_status_t status = cTrack->start(track, bufferGroup->wrap());
  if (status != AMEDIA_OK) {
    free(cTrack);
    return;
  }

  do {
    MediaBufferHelper* buffer = nullptr;
    status = track->read(&buffer);
    if (buffer) {
      buffer->release();
    }
  } while (status == AMEDIA_OK);

  cTrack->stop(track);
  free(cTrack);
}

bool ExtractorFuzzerBase::getTracksMetadata() {
  AMediaFormat* format = AMediaFormat_new();
  uint32_t flags = MediaExtractorPluginHelper::kIncludeExtensiveMetaData;

  for (size_t trackIndex = 0; trackIndex < mExtractor->countTracks(); ++trackIndex) {
    mExtractor->getTrackMetaData(format, trackIndex, flags);
  }

  AMediaFormat_delete(format);
  return true;
}

bool ExtractorFuzzerBase::getMetadata() {
  AMediaFormat* format = AMediaFormat_new();
  mExtractor->getMetaData(format);
  AMediaFormat_delete(format);
  return true;
}

void ExtractorFuzzerBase::setDataSourceFlags(uint32_t flags) {
  mBufferSource->setFlags(flags);
}
+54 −0
Original line number Diff line number Diff line
# Fuzzer for extractors

## Table of contents
1. [libextractorfuzzerbase](#ExtractorFuzzerBase)
2. [libmp4extractor](#mp4ExtractorFuzzer)

# <a name="ExtractorFuzzerBase"></a> Fuzzer for libextractorfuzzerbase
All the extractors have a common API - creating a data source, extraction
of all the tracks, etc. These common APIs have been abstracted in a base class
called `ExtractorFuzzerBase` to ensure code is reused between fuzzer plugins.

Additionally, `ExtractorFuzzerBase` also has support for memory based buffer
`BufferSource` since the fuzzing engine feeds data using memory buffers and
usage of standard data source objects like FileSource, HTTPSource, etc. is
not feasible.

# <a name="mp4ExtractorFuzzer"></a> Fuzzer for libmp4extractor

## Plugin Design Considerations
The fuzzer plugin for MP4 extractor uses the `ExtractorFuzzerBase` class and
implements only the `createExtractor` to create the MP4 extractor class.

##### Maximize code coverage
Dict file (dictionary file) is created for MP4 to ensure that the required MP4
atoms are present in every input file that goes to the fuzzer.
This ensures that larger code gets covered as a range of MP4 atoms will be
present in the input data.


## Build

This describes steps to build mp4_extractor_fuzzer binary.

### Android

#### Steps to build
Build the fuzzer
```
  $ mm -j$(nproc) mp4_extractor_fuzzer
```

#### Steps to run
Create a directory CORPUS_DIR and copy some MP4 files to that folder
Push this directory to device.

To run on device
```
  $ adb sync data
  $ adb shell /data/fuzz/arm64/mp4_extractor_fuzzer/mp4_extractor_fuzzer CORPUS_DIR
```

## References:
 * http://llvm.org/docs/LibFuzzer.html
 * https://github.com/google/oss-fuzz
+130 −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.
 *
 *****************************************************************************
 * Originally developed and contributed by Ittiam Systems Pvt. Ltd, Bangalore
 */

#ifndef __EXTRACTOR_FUZZER_BASE_H__
#define __EXTRACTOR_FUZZER_BASE_H__

#include <media/DataSource.h>
#include <media/MediaExtractorPluginHelper.h>
#include <media/stagefright/MediaBufferGroup.h>

extern "C" {
android::ExtractorDef GETEXTRACTORDEF();
}

namespace android {

class ExtractorFuzzerBase {
 public:
  ExtractorFuzzerBase() = default;
  virtual ~ExtractorFuzzerBase() {
    if (mExtractor) {
      delete mExtractor;
      mExtractor = nullptr;
    }
    if (mBufferSource) {
      mBufferSource.clear();
      mBufferSource = nullptr;
    }
  }

  /** Function to create the media extractor component.
    * To be implemented by the derived class.
    */
  virtual bool createExtractor() = 0;

  /** Parent class functions to be reused by derived class.
    * These are common for all media extractor components.
    */
  bool setDataSource(const uint8_t* data, size_t size);

  bool getExtractorDef();

  bool extractTracks();

  bool getMetadata();

  bool getTracksMetadata();

  void setDataSourceFlags(uint32_t flags);

 protected:
  class BufferSource : public DataSource {
   public:
    BufferSource(const uint8_t* data, size_t length) : mData(data), mLength(length) {}
    virtual ~BufferSource() { mData = nullptr; }

    void setFlags(uint32_t flags) { mFlags = flags; }

    uint32_t flags() { return mFlags; }

    status_t initCheck() const { return mData != nullptr ? OK : NO_INIT; }

    ssize_t readAt(off64_t offset, void* data, size_t size) {
      if (!mData) {
        return NO_INIT;
      }

      Mutex::Autolock autoLock(mLock);
      if ((offset >= static_cast<off64_t>(mLength)) || (offset < 0)) {
        return 0;  // read beyond bounds.
      }
      size_t numAvailable = mLength - static_cast<size_t>(offset);
      if (size > numAvailable) {
        size = numAvailable;
      }
      return readAt_l(offset, data, size);
    }

    status_t getSize(off64_t* size) {
      if (!mData) {
        return NO_INIT;
      }

      Mutex::Autolock autoLock(mLock);
      *size = static_cast<off64_t>(mLength);
      return OK;
    }

   protected:
    ssize_t readAt_l(off64_t offset, void* data, size_t size) {
      void* result = memcpy(data, mData + offset, size);
      return result != nullptr ? size : 0;
    }

    const uint8_t* mData = nullptr;
    size_t mLength = 0;
    Mutex mLock;
    uint32_t mFlags = 0;

   private:
    DISALLOW_EVIL_CONSTRUCTORS(BufferSource);
  };

  sp<BufferSource> mBufferSource;
  DataSource* mDataSource = nullptr;
  MediaExtractorPluginHelper* mExtractor = nullptr;

  virtual void extractTrack(MediaTrackHelper* track, MediaBufferGroup* bufferGroup);
};

}  // namespace android

#endif  // __EXTRACTOR_FUZZER_BASE_H__
+64 −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.
 *
 *****************************************************************************
 * Originally developed and contributed by Ittiam Systems Pvt. Ltd, Bangalore
 */

#include "ExtractorFuzzerBase.h"

#include "MPEG4Extractor.h"
#include "SampleTable.h"

using namespace android;

class MP4Extractor : public ExtractorFuzzerBase {
 public:
  MP4Extractor() = default;
  ~MP4Extractor() = default;

  bool createExtractor();
};

bool MP4Extractor::createExtractor() {
  mExtractor = new MPEG4Extractor(new DataSourceHelper(mDataSource->wrap()));
  if (!mExtractor) {
    return false;
  }
  mExtractor->name();
  setDataSourceFlags(DataSourceBase::kWantsPrefetching | DataSourceBase::kIsCachingDataSource);
  return true;
}

extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
  if ((!data) || (size == 0)) {
    return 0;
  }
  MP4Extractor* extractor = new MP4Extractor();
  if (!extractor) {
    return 0;
  }
  if (extractor->setDataSource(data, size)) {
    if (extractor->createExtractor()) {
      extractor->getExtractorDef();
      extractor->getMetadata();
      extractor->extractTracks();
      extractor->getTracksMetadata();
    }
  }
  delete extractor;
  return 0;
}
Loading