C++程序  |  202行  |  6.55 KB

/*
 * Copyright 2016 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 "FuzzerInternal.h"
#include "ProtoFuzzerMutator.h"

#include "test/vts/proto/ComponentSpecificationMessage.pb.h"

#include <signal.h>
#include <unistd.h>

#include <cstdlib>
#include <iostream>
#include <memory>
#include <string>
#include <vector>

using std::cout;
using std::endl;
using std::make_unique;
using std::string;
using std::unique_ptr;
using std::vector;

// Executed when fuzzer raises SIGABRT signal. This function calls
// the signal handler from the libfuzzer library.
extern "C" void sig_handler(int signo) {
  if (signo == SIGABRT) {
    cerr << "SIGABRT noticed, please refer to device logcat for the root cause."
         << endl;
    fuzzer::Fuzzer::StaticCrashSignalCallback();
    exit(1);
  }
}

namespace android {
namespace vts {
namespace fuzzer {

// 64-bit random number generator.
static unique_ptr<Random> random;
// Parameters that were passed in to fuzzer.
static ProtoFuzzerParams params;
// Used to mutate inputs to hal driver.
static unique_ptr<ProtoFuzzerMutator> mutator;
// Used to exercise HIDL HAL's API.
static unique_ptr<ProtoFuzzerRunner> runner;

static ProtoFuzzerMutatorConfig mutator_config{
    // Heuristic: values close to 0 are likely to be meaningful scalar input
    // values.
    [](Random &rand) {
      size_t dice_roll = rand(10);
      if (dice_roll < 3) {
        // With probability of 30% return an integer in range [0, 10).
        return rand(10);
      } else if (dice_roll >= 3 && dice_roll < 6) {
        // With probability of 30% return an integer in range [0, 100).
        return rand(100);
      } else if (dice_roll >= 6 && dice_roll < 9) {
        // With probability of 30% return an integer in range [0, 100).
        return rand(1000);
      }
      if (rand(10) == 0) {
        // With probability of 1% return 0xffffffffffffffff.
        return 0xffffffffffffffff;
      }
      // With probability 9% result is uniformly random.
      return rand.Rand();
    },
    // Odds of an enum being treated like a scalar are 1:1000.
    {1, 1000}};

// Executed when fuzzer process exits. We use this to print out useful
// information about the state of the fuzzer.
static void AtExit() {
  // Print currently opened interfaces.
  cerr << "Currently opened interfaces: " << endl;
  for (const auto &iface_desc : runner->GetOpenedIfaces()) {
    cerr << iface_desc.first << endl;
  }
  cerr << endl;
  cerr << runner->GetStats().StatsString();
}

extern "C" int LLVMFuzzerInitialize(int *argc, char ***argv) {
  params = ExtractProtoFuzzerParams(*argc, *argv);
  cerr << params.DebugString() << endl;

  random = make_unique<Random>(params.seed_);
  mutator = make_unique<ProtoFuzzerMutator>(
      *random.get(), ExtractPredefinedTypes(params.comp_specs_),
      mutator_config);
  runner = make_unique<ProtoFuzzerRunner>(params.comp_specs_);

  runner->Init(params.target_iface_, params.binder_mode_);
  // Register atexit handler after all static objects' initialization.
  std::atexit(AtExit);
  // Register signal handler for SIGABRT.
  signal(SIGABRT, sig_handler);

  return 0;
}

extern "C" size_t LLVMFuzzerCustomMutator(uint8_t *data, size_t size,
                                          size_t max_size, unsigned int seed) {
  ExecSpec exec_spec{};
  // An Execution is randomly generated if:
  // 1. It can't be serialized from the given buffer OR
  // 2. The runner has opened interfaces that have not been touched.
  // Otherwise, the Execution is mutated.
  if (!FromArray(data, size, &exec_spec) || runner->UntouchedIfaces()) {
    exec_spec =
        mutator->RandomGen(runner->GetOpenedIfaces(), params.exec_size_);
  } else {
    mutator->Mutate(runner->GetOpenedIfaces(), &exec_spec);
  }

  if (static_cast<size_t>(exec_spec.ByteSize()) > max_size) {
    cerr << "execution specification message exceeded maximum size." << endl;
    cerr << max_size << endl;
    cerr << static_cast<size_t>(exec_spec.ByteSize()) << endl;
    std::abort();
  }
  return ToArray(data, max_size, &exec_spec);
}

extern "C" size_t LLVMFuzzerCustomCrossOver(const uint8_t *data1, size_t size1,
                                            const uint8_t *data2, size_t size2,
                                            uint8_t *out, size_t max_out_size,
                                            unsigned int seed) {
  ExecSpec exec_spec1{};
  FromArray(data1, size1, &exec_spec1);
  int function_call_size1 = exec_spec1.function_call_size();

  ExecSpec exec_spec2{};
  FromArray(data2, size2, &exec_spec2);
  int function_call_size2 = exec_spec2.function_call_size();

  if (function_call_size1 != static_cast<int>(params.exec_size_)) {
    if (function_call_size2 != static_cast<int>(params.exec_size_)) {
      cerr << "Both messages were invalid, aborting." << endl;
      std::abort();
    } else {
      cerr << "Message 1 was invalid, copying message 2." << endl;
      memcpy(out, data2, size2);
      return size2;
    }
  } else if (function_call_size2 != static_cast<int>(params.exec_size_)) {
    cerr << "Message 2 was invalid, copying message 1." << endl;
    memcpy(out, data1, size1);
    return size1;
  }

  ExecSpec exec_spec_out{};
  for (int i = 0; i < static_cast<int>(params.exec_size_); i++) {
    FuncCall temp;
    int dice = rand() % 2;
    if (dice == 0) {
      temp = exec_spec1.function_call(i);
    } else {
      temp = exec_spec2.function_call(i);
    }
    exec_spec_out.add_function_call()->CopyFrom(temp);
  }

  if (static_cast<size_t>(exec_spec_out.ByteSize()) > max_out_size) {
    cerr << "execution specification message exceeded maximum size." << endl;
    cerr << max_out_size << endl;
    cerr << static_cast<size_t>(exec_spec_out.ByteSize()) << endl;
    std::abort();
  }
  return ToArray(out, max_out_size, &exec_spec_out);
}

extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
  ExecSpec exec_spec{};
  if (!FromArray(data, size, &exec_spec)) {
    cerr << "Failed to deserialize an ExecSpec." << endl;
    return 0;
  }
  runner->Execute(exec_spec);
  return 0;
}

}  // namespace fuzzer
}  // namespace vts
}  // namespace android