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
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_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
RandomGen(const IfaceSpec & iface_spec,size_t num_calls)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
Mutate(const IfaceSpec & iface_spec,ExecSpec * exec_spec)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
RandomGen(const FuncSpec & func_spec)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
Mutate(const FuncSpec & func_spec)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
Transform(const VariableSpecificationMessage & var_spec,unordered_map<VariableType,VarTransformFn> & transform_fns)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
RandomGen(const VarSpec & var_spec)155 VarInstance ProtoFuzzerMutator::RandomGen(const VarSpec &var_spec) {
156 return Transform(var_spec, random_gen_fns_);
157 }
158
Mutate(const VarInstance & var_instance)159 VarInstance ProtoFuzzerMutator::Mutate(const VarInstance &var_instance) {
160 return Transform(var_instance, mutate_fns_);
161 }
162
FindPredefinedType(string name)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