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_HIDL_INTERFACE] = default_transform; 62 mutate_fns_[TYPE_HIDL_INTERFACE] = default_transform; 63 64 // Interpret masks as enums. 65 random_gen_fns_[TYPE_MASK] = 66 std::bind(&ProtoFuzzerMutator::EnumRandomGen, this, _1); 67 mutate_fns_[TYPE_MASK] = std::bind(&ProtoFuzzerMutator::EnumMutate, this, _1); 68 69 random_gen_fns_[TYPE_POINTER] = default_transform; 70 mutate_fns_[TYPE_POINTER] = default_transform; 71 72 random_gen_fns_[TYPE_SCALAR] = 73 std::bind(&ProtoFuzzerMutator::ScalarRandomGen, this, _1); 74 mutate_fns_[TYPE_SCALAR] = 75 std::bind(&ProtoFuzzerMutator::ScalarMutate, this, _1); 76 77 random_gen_fns_[TYPE_STRING] = 78 std::bind(&ProtoFuzzerMutator::StringRandomGen, this, _1); 79 mutate_fns_[TYPE_STRING] = 80 std::bind(&ProtoFuzzerMutator::StringMutate, this, _1); 81 82 random_gen_fns_[TYPE_STRUCT] = 83 std::bind(&ProtoFuzzerMutator::StructRandomGen, this, _1); 84 mutate_fns_[TYPE_STRUCT] = 85 std::bind(&ProtoFuzzerMutator::StructMutate, this, _1); 86 87 random_gen_fns_[TYPE_UNION] = 88 std::bind(&ProtoFuzzerMutator::UnionRandomGen, this, _1); 89 mutate_fns_[TYPE_UNION] = 90 std::bind(&ProtoFuzzerMutator::UnionMutate, this, _1); 91 92 random_gen_fns_[TYPE_VECTOR] = 93 std::bind(&ProtoFuzzerMutator::VectorRandomGen, this, _1); 94 mutate_fns_[TYPE_VECTOR] = 95 std::bind(&ProtoFuzzerMutator::VectorMutate, this, _1); 96 } 97 98 // TODO(trong): add a mutator config option which controls how an interface is 99 // selected. 100 const CompSpec *ProtoFuzzerMutator::RandomSelectIface(const IfaceDescTbl &tbl) { 101 size_t rand_idx = rand_(tbl.size()); 102 auto it = tbl.begin(); 103 std::advance(it, rand_idx); 104 return it->second.comp_spec_; 105 } 106 107 ExecSpec ProtoFuzzerMutator::RandomGen(const IfaceDescTbl &tbl, 108 size_t num_calls) { 109 ExecSpec result{}; 110 for (size_t i = 0; i < num_calls; ++i) { 111 const CompSpec *comp_spec = RandomSelectIface(tbl); 112 string iface_name = comp_spec->component_name(); 113 const IfaceSpec &iface_spec = comp_spec->interface(); 114 115 // Generate a random interface function call. 116 FuncCall rand_call{}; 117 rand_call.set_hidl_interface_name(iface_name); 118 size_t num_apis = iface_spec.api_size(); 119 size_t rand_api_idx = rand_(num_apis); 120 FuncSpec rand_api = RandomGen(iface_spec.api(rand_api_idx)); 121 *rand_call.mutable_api() = rand_api; 122 *result.add_function_call() = rand_call; 123 } 124 return result; 125 } 126 127 void ProtoFuzzerMutator::Mutate(const IfaceDescTbl &tbl, ExecSpec *exec_spec) { 128 // Mutate a randomly chosen function call with probability 129 // odds_for/(odds_for + odds_against). 130 uint64_t odds_for = mutator_config_.func_mutated_.first; 131 uint64_t odds_against = mutator_config_.func_mutated_.second; 132 uint64_t rand_num = rand_(odds_for + odds_against); 133 134 if (rand_num < odds_for) { 135 // Mutate a random function in execution. 136 size_t idx = rand_(exec_spec->function_call_size()); 137 const FuncSpec &rand_api = exec_spec->function_call(idx).api(); 138 *exec_spec->mutable_function_call(idx)->mutable_api() = Mutate(rand_api); 139 } else { 140 // Generate a random function call in place of randomly chosen function in 141 // execution. 142 const CompSpec *comp_spec = RandomSelectIface(tbl); 143 string iface_name = comp_spec->component_name(); 144 const IfaceSpec &iface_spec = comp_spec->interface(); 145 146 size_t func_idx = rand_(exec_spec->function_call_size()); 147 size_t blueprint_idx = rand_(iface_spec.api_size()); 148 FuncCall *func_call = exec_spec->mutable_function_call(func_idx); 149 func_call->set_hidl_interface_name(iface_name); 150 *func_call->mutable_api() = RandomGen(iface_spec.api(blueprint_idx)); 151 } 152 } 153 154 FuncSpec ProtoFuzzerMutator::RandomGen(const FuncSpec &func_spec) { 155 FuncSpec result{func_spec}; 156 // We'll repopulate arg field. 157 result.clear_arg(); 158 result.clear_return_type_hidl(); 159 for (const auto &var_spec : func_spec.arg()) { 160 VarInstance rand_var_spec = RandomGen(var_spec); 161 auto *new_var = result.add_arg(); 162 new_var->Swap(&rand_var_spec); 163 } 164 return result; 165 } 166 167 FuncSpec ProtoFuzzerMutator::Mutate(const FuncSpec &func_spec) { 168 FuncSpec result{func_spec}; 169 size_t num_args = result.arg_size(); 170 if (num_args > 0) { 171 size_t rand_arg_idx = rand_(num_args); 172 VarInstance rand_arg = Mutate(result.arg(rand_arg_idx)); 173 result.mutable_arg(rand_arg_idx)->Swap(&rand_arg); 174 } 175 return result; 176 } 177 178 static VariableSpecificationMessage Transform( 179 const VariableSpecificationMessage &var_spec, 180 unordered_map<VariableType, VarTransformFn> &transform_fns) { 181 auto type = var_spec.type(); 182 auto transform_fn = transform_fns.find(type); 183 if (transform_fn == transform_fns.end()) { 184 cerr << "Transformation function not found for type: " << type << endl; 185 exit(1); 186 } 187 return transform_fn->second(var_spec); 188 } 189 190 VarInstance ProtoFuzzerMutator::RandomGen(const VarSpec &var_spec) { 191 return Transform(var_spec, random_gen_fns_); 192 } 193 194 VarInstance ProtoFuzzerMutator::Mutate(const VarInstance &var_instance) { 195 return Transform(var_instance, mutate_fns_); 196 } 197 198 const TypeSpec &ProtoFuzzerMutator::FindPredefinedType(string name) { 199 auto type_spec = predefined_types_.find(name); 200 if (type_spec == predefined_types_.end()) { 201 cerr << "Predefined type not found: " << name << endl; 202 exit(1); 203 } 204 return type_spec->second; 205 } 206 207 } // namespace fuzzer 208 } // namespace vts 209 } // namespace android 210