1 /*
2  * Copyright 2017 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 
19 using std::cerr;
20 using std::endl;
21 
22 namespace android {
23 namespace vts {
24 namespace fuzzer {
25 
26 // Creates an inital stub of mutation/random generation result.
VarInstanceStubFromSpec(const VarSpec & var_spec)27 static VarInstance VarInstanceStubFromSpec(const VarSpec &var_spec) {
28   VarInstance result{};
29   if (var_spec.has_type()) {
30     result.set_type(var_spec.type());
31   } else {
32     cerr << "VarInstance with no type field: " << var_spec.DebugString();
33     std::abort();
34   }
35   if (var_spec.has_name()) {
36     result.set_name(var_spec.name());
37   }
38   if (var_spec.has_predefined_type()) {
39     result.set_predefined_type(var_spec.predefined_type());
40   }
41   return result;
42 }
43 
ArrayRandomGen(const VarSpec & var_spec)44 VarInstance ProtoFuzzerMutator::ArrayRandomGen(const VarSpec &var_spec) {
45   VarInstance result{VarInstanceStubFromSpec(var_spec)};
46   size_t vector_size = var_spec.vector_size();
47   result.set_vector_size(vector_size);
48   for (size_t i = 0; i < vector_size; ++i) {
49     *result.add_vector_value() = this->RandomGen(var_spec.vector_value(0));
50   }
51   return result;
52 }
53 
ArrayMutate(const VarInstance & var_instance)54 VarInstance ProtoFuzzerMutator::ArrayMutate(const VarInstance &var_instance) {
55   VarInstance result{var_instance};
56   size_t vector_size = result.vector_size();
57   size_t idx = rand_(vector_size);
58   *result.mutable_vector_value(idx) = this->Mutate(result.vector_value(idx));
59   return result;
60 }
61 
EnumRandomGen(const VarSpec & var_spec)62 VarInstance ProtoFuzzerMutator::EnumRandomGen(const VarSpec &var_spec) {
63   VarInstance result{VarInstanceStubFromSpec(var_spec)};
64   const EnumData &blueprint =
65       FindPredefinedType(result.predefined_type()).enum_value();
66 
67   size_t size = blueprint.enumerator_size();
68   size_t idx = rand_(size);
69 
70   ScalarData scalar_value = blueprint.scalar_value(idx);
71   string scalar_type = blueprint.scalar_type();
72 
73   // Mutate this enum like a scalar with probability
74   // odds_for/(odds_for + odds_against).
75   uint64_t odds_for = (this->mutator_config_).enum_bias_.first;
76   uint64_t odds_against = (this->mutator_config_).enum_bias_.second;
77   uint64_t rand_num = rand_(odds_for + odds_against);
78   if (rand_num < odds_for) {
79     scalar_value = Mutate(scalar_value, scalar_type);
80   }
81 
82   *(result.mutable_scalar_value()) = scalar_value;
83   result.set_scalar_type(scalar_type);
84   return result;
85 }
86 
EnumMutate(const VarInstance & var_instance)87 VarInstance ProtoFuzzerMutator::EnumMutate(const VarInstance &var_instance) {
88   // For TYPE_ENUM, VarInstance contains superset info of VarSpec.
89   return RandomGen(var_instance);
90 }
91 
ScalarRandomGen(const VarSpec & var_spec)92 VarInstance ProtoFuzzerMutator::ScalarRandomGen(const VarSpec &var_spec) {
93   VarInstance result{VarInstanceStubFromSpec(var_spec)};
94   result.set_scalar_type(var_spec.scalar_type());
95   (*result.mutable_scalar_value()) =
96       RandomGen(result.scalar_value(), result.scalar_type());
97   return result;
98 }
99 
ScalarMutate(const VarInstance & var_instance)100 VarInstance ProtoFuzzerMutator::ScalarMutate(const VarInstance &var_instance) {
101   VarInstance result{var_instance};
102   (*result.mutable_scalar_value()) =
103       Mutate(result.scalar_value(), result.scalar_type());
104   return result;
105 }
106 
StringRandomGen(const VarSpec & var_spec)107 VarInstance ProtoFuzzerMutator::StringRandomGen(const VarSpec &var_spec) {
108   VarInstance result{VarInstanceStubFromSpec(var_spec)};
109 
110   size_t str_size = mutator_config_.default_string_size_;
111   string str(str_size, 0);
112   auto rand_char = std::bind(&ProtoFuzzerMutator::RandomAsciiChar, this);
113   std::generate_n(str.begin(), str_size, rand_char);
114 
115   StringDataValueMessage string_data;
116   string_data.set_message(str.c_str());
117   string_data.set_length(str_size);
118 
119   *result.mutable_string_value() = string_data;
120   return result;
121 }
122 
StringMutate(const VarInstance & var_instance)123 VarInstance ProtoFuzzerMutator::StringMutate(const VarInstance &var_instance) {
124   VarInstance result{var_instance};
125   string str = result.string_value().message();
126   size_t str_size = result.string_value().length();
127 
128   // Three things can happen when mutating a string:
129   // 1. A random char is inserted into a random position.
130   // 2. A randomly selected char is removed from the string.
131   // 3. A randomly selected char in the string is replaced by a random char.
132   size_t dice_roll = str.empty() ? 0 : rand_(3);
133   size_t idx = rand_(str_size);
134   switch (dice_roll) {
135     case 0:
136       // Insert a random char.
137       str.insert(str.begin() + idx, RandomAsciiChar());
138       ++str_size;
139       break;
140     case 1:
141       // Remove a randomly selected char.
142       str.erase(str.begin() + idx);
143       --str_size;
144       break;
145     case 2:
146       // Replace a randomly selected char.
147       str[idx] = RandomAsciiChar();
148       break;
149     default:
150       // Do nothing.
151       break;
152   }
153 
154   result.mutable_string_value()->set_message(str);
155   result.mutable_string_value()->set_length(str_size);
156   return result;
157 }
158 
StructRandomGen(const VarSpec & var_spec)159 VarInstance ProtoFuzzerMutator::StructRandomGen(const VarSpec &var_spec) {
160   VarInstance result{VarInstanceStubFromSpec(var_spec)};
161   const TypeSpec &blueprint = FindPredefinedType(result.predefined_type());
162   for (const VarSpec &struct_value : blueprint.struct_value()) {
163     *result.add_struct_value() = this->RandomGen(struct_value);
164   }
165   return result;
166 }
167 
StructMutate(const VarInstance & var_instance)168 VarInstance ProtoFuzzerMutator::StructMutate(const VarInstance &var_instance) {
169   VarInstance result{var_instance};
170   size_t size = result.struct_value_size();
171   size_t idx = rand_(size);
172   *result.mutable_struct_value(idx) = this->Mutate(result.struct_value(idx));
173   return result;
174 }
175 
UnionRandomGen(const VarSpec & var_spec)176 VarInstance ProtoFuzzerMutator::UnionRandomGen(const VarSpec &var_spec) {
177   VarInstance result{VarInstanceStubFromSpec(var_spec)};
178   const TypeSpec &blueprint = FindPredefinedType(result.predefined_type());
179   size_t size = blueprint.union_value_size();
180   for (size_t i = 0; i < size; ++i) {
181     result.add_union_value();
182   }
183   size_t idx = rand_(size);
184   *result.mutable_union_value(idx) =
185       this->RandomGen(blueprint.union_value(idx));
186   return result;
187 }
188 
UnionMutate(const VarInstance & var_instance)189 VarInstance ProtoFuzzerMutator::UnionMutate(const VarInstance &var_instance) {
190   VarInstance result{var_instance};
191   size_t size = result.union_value_size();
192   for (size_t i = 0; i < size; ++i) {
193     if (result.union_value(i).has_name()) {
194       *result.mutable_union_value(i) = this->Mutate(result.union_value(i));
195     }
196   }
197   return result;
198 }
199 
VectorRandomGen(const VarSpec & var_spec)200 VarInstance ProtoFuzzerMutator::VectorRandomGen(const VarSpec &var_spec) {
201   VarInstance result{VarInstanceStubFromSpec(var_spec)};
202   size_t size = mutator_config_.default_vector_size_;
203   for (size_t i = 0; i < size; ++i) {
204     *result.add_vector_value() = this->RandomGen(var_spec.vector_value(0));
205   }
206   return result;
207 }
208 
VectorMutate(const VarInstance & var_instance)209 VarInstance ProtoFuzzerMutator::VectorMutate(const VarInstance &var_instance) {
210   VarInstance result{var_instance};
211   size_t size = result.vector_size();
212   size_t idx = rand_(size);
213   *result.mutable_vector_value(idx) = this->Mutate(result.vector_value(idx));
214   return result;
215 }
216 
RandomGen(const ScalarData & scalar_value,const string & scalar_type)217 ScalarData ProtoFuzzerMutator::RandomGen(const ScalarData &scalar_value,
218                                          const string &scalar_type) {
219   ScalarData result{};
220 
221   if (scalar_type == "bool_t") {
222     result.set_bool_t(RandomGen(static_cast<bool>(scalar_value.bool_t())));
223   } else if (scalar_type == "int8_t") {
224     result.set_int8_t(RandomGen(scalar_value.int8_t()));
225   } else if (scalar_type == "uint8_t") {
226     result.set_uint8_t(RandomGen(scalar_value.uint8_t()));
227   } else if (scalar_type == "int16_t") {
228     result.set_int16_t(RandomGen(scalar_value.int16_t()));
229   } else if (scalar_type == "uint16_t") {
230     result.set_uint16_t(RandomGen(scalar_value.uint16_t()));
231   } else if (scalar_type == "int32_t") {
232     result.set_int32_t(RandomGen(scalar_value.int32_t()));
233   } else if (scalar_type == "uint32_t") {
234     result.set_uint32_t(RandomGen(scalar_value.uint32_t()));
235   } else if (scalar_type == "int64_t") {
236     result.set_int64_t(RandomGen(scalar_value.int64_t()));
237   } else if (scalar_type == "uint64_t") {
238     result.set_uint64_t(RandomGen(scalar_value.uint64_t()));
239   } else if (scalar_type == "float_t") {
240     result.set_float_t(RandomGen(scalar_value.float_t()));
241   } else if (scalar_type == "double_t") {
242     result.set_double_t(RandomGen(scalar_value.double_t()));
243   } else {
244     cout << scalar_type << " not supported.\n";
245   }
246 
247   return result;
248 }
249 
Mutate(const ScalarData & scalar_value,const string & scalar_type)250 ScalarData ProtoFuzzerMutator::Mutate(const ScalarData &scalar_value,
251                                       const string &scalar_type) {
252   ScalarData result{};
253 
254   if (scalar_type == "bool_t") {
255     result.set_bool_t(Mutate(static_cast<bool>(scalar_value.bool_t())));
256   } else if (scalar_type == "int8_t") {
257     result.set_int8_t(Mutate(scalar_value.int8_t()));
258   } else if (scalar_type == "uint8_t") {
259     result.set_uint8_t(Mutate(scalar_value.uint8_t()));
260   } else if (scalar_type == "int16_t") {
261     result.set_int16_t(Mutate(scalar_value.int16_t()));
262   } else if (scalar_type == "uint16_t") {
263     result.set_uint16_t(Mutate(scalar_value.uint16_t()));
264   } else if (scalar_type == "int32_t") {
265     result.set_int32_t(Mutate(scalar_value.int32_t()));
266   } else if (scalar_type == "uint32_t") {
267     result.set_uint32_t(Mutate(scalar_value.uint32_t()));
268   } else if (scalar_type == "int64_t") {
269     result.set_int64_t(Mutate(scalar_value.int64_t()));
270   } else if (scalar_type == "uint64_t") {
271     result.set_uint64_t(Mutate(scalar_value.uint64_t()));
272   } else if (scalar_type == "float_t") {
273     result.set_float_t(Mutate(scalar_value.float_t()));
274   } else if (scalar_type == "double_t") {
275     result.set_double_t(Mutate(scalar_value.double_t()));
276   } else {
277     cout << scalar_type << " not supported.\n";
278   }
279 
280   return result;
281 }
282 
283 template <typename T>
RandomGen(T value)284 T ProtoFuzzerMutator::RandomGen(T value) {
285   // Generate a biased random scalar.
286   uint64_t rand_int = mutator_config_.scalar_bias_(rand_);
287 
288   T result;
289   memcpy(&result, &rand_int, sizeof(T));
290   return result;
291 }
292 
RandomGen(bool value)293 bool ProtoFuzzerMutator::RandomGen(bool value) {
294   return static_cast<bool>(rand_(2));
295 }
296 
297 template <typename T>
Mutate(T value)298 T ProtoFuzzerMutator::Mutate(T value) {
299   size_t num_bits = 8 * sizeof(T);
300   T mask = static_cast<T>(1) << rand_(num_bits);
301   return value ^ mask;
302 }
303 
Mutate(bool value)304 bool ProtoFuzzerMutator::Mutate(bool value) { return RandomGen(value); }
305 
Mutate(float value)306 float ProtoFuzzerMutator::Mutate(float value) {
307   uint32_t copy;
308   memcpy(&copy, &value, sizeof(float));
309   uint32_t mask = static_cast<uint32_t>(1) << rand_(32);
310   copy ^= mask;
311   memcpy(&value, &copy, sizeof(float));
312   return value;
313 }
314 
Mutate(double value)315 double ProtoFuzzerMutator::Mutate(double value) {
316   uint64_t copy;
317   memcpy(&copy, &value, sizeof(double));
318   uint64_t mask = static_cast<uint64_t>(1) << rand_(64);
319   copy ^= mask;
320   memcpy(&value, &copy, sizeof(double));
321   return value;
322 }
323 
RandomAsciiChar()324 char ProtoFuzzerMutator::RandomAsciiChar() {
325   const char char_set[] =
326       "0123456789"
327       "`~!@#$%^&*()-_=+[{]};:',<.>/? "
328       "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
329       "abcdefghijklmnopqrstuvwxyz";
330   size_t num_chars = sizeof(char_set) - 1;
331   return char_set[rand_(num_chars)];
332 }
333 
334 }  // namespace fuzzer
335 }  // namespace vts
336 }  // namespace android
337