1 /* 2 * Copyright 2016 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #include "ProtoFuzzerMutator.h" 18 #include <iostream> 19 20 using std::endl; 21 using std::cerr; 22 using std::cout; 23 using std::make_unique; 24 using std::unordered_map; 25 using namespace std::placeholders; 26 27 namespace android { 28 namespace vts { 29 namespace fuzzer { 30 31 ProtoFuzzerMutator::ProtoFuzzerMutator( 32 Random &rand, unordered_map<string, TypeSpec> predefined_types, 33 ProtoFuzzerMutatorConfig mutator_config) 34 : rand_(rand), 35 predefined_types_(predefined_types), 36 mutator_config_(mutator_config) { 37 // Default function used for mutation/random generation. Used for types for 38 // which the notion of mutation/random generation is not defined, e.g. 39 // TYPE_HANDLE, TYPE_HIDL_CALLBACK. 40 VarTransformFn default_transform = 41 [](const VariableSpecificationMessage &var_spec) { 42 return VariableSpecificationMessage{var_spec}; 43 }; 44 45 // Initialize random_gen_fns_ and mutate_fns_ tables. 46 random_gen_fns_[TYPE_ARRAY] = 47 std::bind(&ProtoFuzzerMutator::ArrayRandomGen, this, _1); 48 mutate_fns_[TYPE_ARRAY] = 49 std::bind(&ProtoFuzzerMutator::ArrayMutate, this, _1); 50 51 random_gen_fns_[TYPE_ENUM] = 52 std::bind(&ProtoFuzzerMutator::EnumRandomGen, this, _1); 53 mutate_fns_[TYPE_ENUM] = std::bind(&ProtoFuzzerMutator::EnumMutate, this, _1); 54 55 random_gen_fns_[TYPE_HANDLE] = default_transform; 56 mutate_fns_[TYPE_HANDLE] = default_transform; 57 58 random_gen_fns_[TYPE_HIDL_CALLBACK] = default_transform; 59 mutate_fns_[TYPE_HIDL_CALLBACK] = default_transform; 60 61 random_gen_fns_[TYPE_SCALAR] = 62 std::bind(&ProtoFuzzerMutator::ScalarRandomGen, this, _1); 63 mutate_fns_[TYPE_SCALAR] = 64 std::bind(&ProtoFuzzerMutator::ScalarMutate, this, _1); 65 66 random_gen_fns_[TYPE_STRUCT] = 67 std::bind(&ProtoFuzzerMutator::StructRandomGen, this, _1); 68 mutate_fns_[TYPE_STRUCT] = 69 std::bind(&ProtoFuzzerMutator::StructMutate, this, _1); 70 71 random_gen_fns_[TYPE_UNION] = 72 std::bind(&ProtoFuzzerMutator::UnionRandomGen, this, _1); 73 mutate_fns_[TYPE_UNION] = 74 std::bind(&ProtoFuzzerMutator::UnionMutate, this, _1); 75 76 random_gen_fns_[TYPE_VECTOR] = 77 std::bind(&ProtoFuzzerMutator::VectorRandomGen, this, _1); 78 mutate_fns_[TYPE_VECTOR] = 79 std::bind(&ProtoFuzzerMutator::VectorMutate, this, _1); 80 } 81 82 ExecSpec ProtoFuzzerMutator::RandomGen(const IfaceSpec &iface_spec, 83 size_t num_calls) { 84 ExecSpec result{}; 85 86 for (size_t i = 0; i < num_calls; ++i) { 87 size_t num_apis = iface_spec.api_size(); 88 size_t rand_api_idx = rand_(num_apis); 89 FuncSpec rand_api = RandomGen(iface_spec.api(rand_api_idx)); 90 result.add_api()->Swap(&rand_api); 91 } 92 93 return result; 94 } 95 96 void ProtoFuzzerMutator::Mutate(const IfaceSpec &iface_spec, 97 ExecSpec *exec_spec) { 98 // Mutate a randomly chosen function call with probability 99 // odds_for/(odds_for + odds_against). 100 uint64_t odds_for = mutator_config_.func_mutated_.first; 101 uint64_t odds_against = mutator_config_.func_mutated_.second; 102 uint64_t rand_num = rand_(odds_for + odds_against); 103 104 if (rand_num < odds_for) { 105 // Mutate a random function in execution. 106 size_t idx = rand_(exec_spec->api_size()); 107 const FuncSpec &rand_api = exec_spec->api(idx); 108 (*exec_spec->mutable_api(idx)) = Mutate(rand_api); 109 } else { 110 // Generate a random function call in place of randomly chosen function in 111 // execution. 112 size_t func_idx = rand_(exec_spec->api_size()); 113 size_t blueprint_idx = rand_(iface_spec.api_size()); 114 *(exec_spec->mutable_api(func_idx)) = 115 RandomGen(iface_spec.api(blueprint_idx)); 116 } 117 } 118 119 FuncSpec ProtoFuzzerMutator::RandomGen(const FuncSpec &func_spec) { 120 FuncSpec result{func_spec}; 121 // We'll repopulate arg field. 122 result.clear_arg(); 123 result.clear_return_type_hidl(); 124 for (const auto &var_spec : func_spec.arg()) { 125 VarInstance rand_var_spec = RandomGen(var_spec); 126 auto *new_var = result.add_arg(); 127 new_var->Swap(&rand_var_spec); 128 } 129 return result; 130 } 131 132 FuncSpec ProtoFuzzerMutator::Mutate(const FuncSpec &func_spec) { 133 FuncSpec result{func_spec}; 134 size_t num_args = result.arg_size(); 135 if (num_args > 0) { 136 size_t rand_arg_idx = rand_(num_args); 137 VarInstance rand_arg = Mutate(result.arg(rand_arg_idx)); 138 result.mutable_arg(rand_arg_idx)->Swap(&rand_arg); 139 } 140 return result; 141 } 142 143 static VariableSpecificationMessage Transform( 144 const VariableSpecificationMessage &var_spec, 145 unordered_map<VariableType, VarTransformFn> &transform_fns) { 146 auto type = var_spec.type(); 147 auto transform_fn = transform_fns.find(type); 148 if (transform_fn == transform_fns.end()) { 149 cerr << "Transformation function not found for type: " << type << endl; 150 exit(1); 151 } 152 return transform_fn->second(var_spec); 153 } 154 155 VarInstance ProtoFuzzerMutator::RandomGen(const VarSpec &var_spec) { 156 return Transform(var_spec, random_gen_fns_); 157 } 158 159 VarInstance ProtoFuzzerMutator::Mutate(const VarInstance &var_instance) { 160 return Transform(var_instance, mutate_fns_); 161 } 162 163 const TypeSpec &ProtoFuzzerMutator::FindPredefinedType(string name) { 164 auto type_spec = predefined_types_.find(name); 165 if (type_spec == predefined_types_.end()) { 166 cerr << "Predefined type not found: " << name << endl; 167 exit(1); 168 } 169 return type_spec->second; 170 } 171 172 } // namespace fuzzer 173 } // namespace vts 174 } // namespace android 175