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

Commit 057f2f5e authored by S Vasudev Prasad's avatar S Vasudev Prasad
Browse files

Added ExtractorFuzzerBase class

This class provides the interface for a generic extractor. It
creates a buffersource and also provides an api to extract
all tracks

This can be used to fuzz extractors

Test: Build using mm
Bug: 151789258

Change-Id: I5c5de9d4558d547db667d1c6ff065c961d3bdad8
parent 17bfa455
Loading
Loading
Loading
Loading
+53 −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,
}
+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);
}
+19 −0
Original line number Diff line number Diff line
# Fuzzer for extractors

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

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


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