/* * 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 #include #include #include #include #include #include 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 { #ifdef STATIC_TARGET_FQ_NAME // Returns parameters used for static fuzzer executables. extern ProtoFuzzerParams ExtractProtoFuzzerStaticParams(int argc, char **argv); #endif // 64-bit random number generator. static unique_ptr random; // Parameters that were passed in to fuzzer. static ProtoFuzzerParams params; // Used to mutate inputs to hal driver. static unique_ptr mutator; // Used to exercise HIDL HAL's API. static unique_ptr 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) { #ifdef STATIC_TARGET_FQ_NAME params = ExtractProtoFuzzerStaticParams(*argc, *argv); #else params = ExtractProtoFuzzerParams(*argc, *argv); #endif cerr << params.DebugString() << endl; random = make_unique(params.seed_); mutator = make_unique( *random.get(), ExtractPredefinedTypes(params.comp_specs_), mutator_config); runner = make_unique(params.comp_specs_, params.target_fq_name_.version()); runner->Init(params.target_fq_name_.name(), 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(exec_spec.ByteSize()) > max_size) { cerr << "execution specification message exceeded maximum size." << endl; cerr << max_size << endl; cerr << static_cast(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{}; if (!FromArray(data1, size1, &exec_spec1)) { cerr << "Message 1 was invalid." << endl; exec_spec1 = mutator->RandomGen(runner->GetOpenedIfaces(), params.exec_size_); } ExecSpec exec_spec2{}; if (!FromArray(data2, size2, &exec_spec2)) { cerr << "Message 2 was invalid." << endl; exec_spec2 = mutator->RandomGen(runner->GetOpenedIfaces(), params.exec_size_); } ExecSpec exec_spec_out{}; for (int i = 0; i < static_cast(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(exec_spec_out.ByteSize()) > max_out_size) { cerr << "execution specification message exceeded maximum size." << endl; cerr << max_out_size << endl; cerr << static_cast(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; // Don't generate an ExecSpec here so that libFuzzer knows that the provided // buffer doesn't provide any coverage. return 0; } runner->Execute(exec_spec); return 0; } } // namespace fuzzer } // namespace vts } // namespace android