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. 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 exit(1); 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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> 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 293 bool ProtoFuzzerMutator::RandomGen(bool value) { 294 return static_cast<bool>(rand_(2)); 295 } 296 297 template <typename T> 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 304 bool ProtoFuzzerMutator::Mutate(bool value) { return RandomGen(value); } 305 306 float ProtoFuzzerMutator::Mutate(float value) { 307 uint32_t copy; 308 memcpy(©, &value, sizeof(float)); 309 uint32_t mask = static_cast<uint32_t>(1) << rand_(32); 310 copy ^= mask; 311 memcpy(&value, ©, sizeof(float)); 312 return value; 313 } 314 315 double ProtoFuzzerMutator::Mutate(double value) { 316 uint64_t copy; 317 memcpy(©, &value, sizeof(double)); 318 uint64_t mask = static_cast<uint64_t>(1) << rand_(64); 319 copy ^= mask; 320 memcpy(&value, ©, sizeof(double)); 321 return value; 322 } 323 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