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