1 1.1 kamil //===- FuzzerMutate.cpp - Mutate a test input -----------------------------===// 2 1.1 kamil // 3 1.1 kamil // The LLVM Compiler Infrastructure 4 1.1 kamil // 5 1.1 kamil // This file is distributed under the University of Illinois Open Source 6 1.1 kamil // License. See LICENSE.TXT for details. 7 1.1 kamil // 8 1.1 kamil //===----------------------------------------------------------------------===// 9 1.1 kamil // Mutate a test input. 10 1.1 kamil //===----------------------------------------------------------------------===// 11 1.1 kamil 12 1.1 kamil #include "FuzzerMutate.h" 13 1.1 kamil #include "FuzzerCorpus.h" 14 1.1 kamil #include "FuzzerDefs.h" 15 1.1 kamil #include "FuzzerExtFunctions.h" 16 1.1 kamil #include "FuzzerIO.h" 17 1.1 kamil #include "FuzzerOptions.h" 18 1.1 kamil 19 1.1 kamil namespace fuzzer { 20 1.1 kamil 21 1.1 kamil const size_t Dictionary::kMaxDictSize; 22 1.1 kamil 23 1.1 kamil static void PrintASCII(const Word &W, const char *PrintAfter) { 24 1.1 kamil PrintASCII(W.data(), W.size(), PrintAfter); 25 1.1 kamil } 26 1.1 kamil 27 1.1 kamil MutationDispatcher::MutationDispatcher(Random &Rand, 28 1.1 kamil const FuzzingOptions &Options) 29 1.1 kamil : Rand(Rand), Options(Options) { 30 1.1 kamil DefaultMutators.insert( 31 1.1 kamil DefaultMutators.begin(), 32 1.1 kamil { 33 1.1 kamil {&MutationDispatcher::Mutate_EraseBytes, "EraseBytes"}, 34 1.1 kamil {&MutationDispatcher::Mutate_InsertByte, "InsertByte"}, 35 1.1 kamil {&MutationDispatcher::Mutate_InsertRepeatedBytes, 36 1.1 kamil "InsertRepeatedBytes"}, 37 1.1 kamil {&MutationDispatcher::Mutate_ChangeByte, "ChangeByte"}, 38 1.1 kamil {&MutationDispatcher::Mutate_ChangeBit, "ChangeBit"}, 39 1.1 kamil {&MutationDispatcher::Mutate_ShuffleBytes, "ShuffleBytes"}, 40 1.1 kamil {&MutationDispatcher::Mutate_ChangeASCIIInteger, "ChangeASCIIInt"}, 41 1.1 kamil {&MutationDispatcher::Mutate_ChangeBinaryInteger, "ChangeBinInt"}, 42 1.1 kamil {&MutationDispatcher::Mutate_CopyPart, "CopyPart"}, 43 1.1 kamil {&MutationDispatcher::Mutate_CrossOver, "CrossOver"}, 44 1.1 kamil {&MutationDispatcher::Mutate_AddWordFromManualDictionary, 45 1.1 kamil "ManualDict"}, 46 1.1 kamil {&MutationDispatcher::Mutate_AddWordFromPersistentAutoDictionary, 47 1.1 kamil "PersAutoDict"}, 48 1.1 kamil }); 49 1.1 kamil if(Options.UseCmp) 50 1.1 kamil DefaultMutators.push_back( 51 1.1 kamil {&MutationDispatcher::Mutate_AddWordFromTORC, "CMP"}); 52 1.1 kamil 53 1.1 kamil if (EF->LLVMFuzzerCustomMutator) 54 1.1 kamil Mutators.push_back({&MutationDispatcher::Mutate_Custom, "Custom"}); 55 1.1 kamil else 56 1.1 kamil Mutators = DefaultMutators; 57 1.1 kamil 58 1.1 kamil if (EF->LLVMFuzzerCustomCrossOver) 59 1.1 kamil Mutators.push_back( 60 1.1 kamil {&MutationDispatcher::Mutate_CustomCrossOver, "CustomCrossOver"}); 61 1.1 kamil } 62 1.1 kamil 63 1.1 kamil static char RandCh(Random &Rand) { 64 1.1 kamil if (Rand.RandBool()) return Rand(256); 65 1.1 kamil const char Special[] = "!*'();:@&=+$,/?%#[]012Az-`~.\xff\x00"; 66 1.1 kamil return Special[Rand(sizeof(Special) - 1)]; 67 1.1 kamil } 68 1.1 kamil 69 1.1 kamil size_t MutationDispatcher::Mutate_Custom(uint8_t *Data, size_t Size, 70 1.1 kamil size_t MaxSize) { 71 1.1 kamil return EF->LLVMFuzzerCustomMutator(Data, Size, MaxSize, Rand.Rand()); 72 1.1 kamil } 73 1.1 kamil 74 1.1 kamil size_t MutationDispatcher::Mutate_CustomCrossOver(uint8_t *Data, size_t Size, 75 1.1 kamil size_t MaxSize) { 76 1.1 kamil if (!Corpus || Corpus->size() < 2 || Size == 0) 77 1.1 kamil return 0; 78 1.1 kamil size_t Idx = Rand(Corpus->size()); 79 1.1 kamil const Unit &Other = (*Corpus)[Idx]; 80 1.1 kamil if (Other.empty()) 81 1.1 kamil return 0; 82 1.1 kamil CustomCrossOverInPlaceHere.resize(MaxSize); 83 1.1 kamil auto &U = CustomCrossOverInPlaceHere; 84 1.1 kamil size_t NewSize = EF->LLVMFuzzerCustomCrossOver( 85 1.1 kamil Data, Size, Other.data(), Other.size(), U.data(), U.size(), Rand.Rand()); 86 1.1 kamil if (!NewSize) 87 1.1 kamil return 0; 88 1.1 kamil assert(NewSize <= MaxSize && "CustomCrossOver returned overisized unit"); 89 1.1 kamil memcpy(Data, U.data(), NewSize); 90 1.1 kamil return NewSize; 91 1.1 kamil } 92 1.1 kamil 93 1.1 kamil size_t MutationDispatcher::Mutate_ShuffleBytes(uint8_t *Data, size_t Size, 94 1.1 kamil size_t MaxSize) { 95 1.1 kamil if (Size > MaxSize || Size == 0) return 0; 96 1.1 kamil size_t ShuffleAmount = 97 1.1 kamil Rand(std::min(Size, (size_t)8)) + 1; // [1,8] and <= Size. 98 1.1 kamil size_t ShuffleStart = Rand(Size - ShuffleAmount); 99 1.1 kamil assert(ShuffleStart + ShuffleAmount <= Size); 100 1.1 kamil std::shuffle(Data + ShuffleStart, Data + ShuffleStart + ShuffleAmount, Rand); 101 1.1 kamil return Size; 102 1.1 kamil } 103 1.1 kamil 104 1.1 kamil size_t MutationDispatcher::Mutate_EraseBytes(uint8_t *Data, size_t Size, 105 1.1 kamil size_t MaxSize) { 106 1.1 kamil if (Size <= 1) return 0; 107 1.1 kamil size_t N = Rand(Size / 2) + 1; 108 1.1 kamil assert(N < Size); 109 1.1 kamil size_t Idx = Rand(Size - N + 1); 110 1.1 kamil // Erase Data[Idx:Idx+N]. 111 1.1 kamil memmove(Data + Idx, Data + Idx + N, Size - Idx - N); 112 1.1 kamil // Printf("Erase: %zd %zd => %zd; Idx %zd\n", N, Size, Size - N, Idx); 113 1.1 kamil return Size - N; 114 1.1 kamil } 115 1.1 kamil 116 1.1 kamil size_t MutationDispatcher::Mutate_InsertByte(uint8_t *Data, size_t Size, 117 1.1 kamil size_t MaxSize) { 118 1.1 kamil if (Size >= MaxSize) return 0; 119 1.1 kamil size_t Idx = Rand(Size + 1); 120 1.1 kamil // Insert new value at Data[Idx]. 121 1.1 kamil memmove(Data + Idx + 1, Data + Idx, Size - Idx); 122 1.1 kamil Data[Idx] = RandCh(Rand); 123 1.1 kamil return Size + 1; 124 1.1 kamil } 125 1.1 kamil 126 1.1 kamil size_t MutationDispatcher::Mutate_InsertRepeatedBytes(uint8_t *Data, 127 1.1 kamil size_t Size, 128 1.1 kamil size_t MaxSize) { 129 1.1 kamil const size_t kMinBytesToInsert = 3; 130 1.1 kamil if (Size + kMinBytesToInsert >= MaxSize) return 0; 131 1.1 kamil size_t MaxBytesToInsert = std::min(MaxSize - Size, (size_t)128); 132 1.1 kamil size_t N = Rand(MaxBytesToInsert - kMinBytesToInsert + 1) + kMinBytesToInsert; 133 1.1 kamil assert(Size + N <= MaxSize && N); 134 1.1 kamil size_t Idx = Rand(Size + 1); 135 1.1 kamil // Insert new values at Data[Idx]. 136 1.1 kamil memmove(Data + Idx + N, Data + Idx, Size - Idx); 137 1.1 kamil // Give preference to 0x00 and 0xff. 138 1.1 kamil uint8_t Byte = Rand.RandBool() ? Rand(256) : (Rand.RandBool() ? 0 : 255); 139 1.1 kamil for (size_t i = 0; i < N; i++) 140 1.1 kamil Data[Idx + i] = Byte; 141 1.1 kamil return Size + N; 142 1.1 kamil } 143 1.1 kamil 144 1.1 kamil size_t MutationDispatcher::Mutate_ChangeByte(uint8_t *Data, size_t Size, 145 1.1 kamil size_t MaxSize) { 146 1.1 kamil if (Size > MaxSize) return 0; 147 1.1 kamil size_t Idx = Rand(Size); 148 1.1 kamil Data[Idx] = RandCh(Rand); 149 1.1 kamil return Size; 150 1.1 kamil } 151 1.1 kamil 152 1.1 kamil size_t MutationDispatcher::Mutate_ChangeBit(uint8_t *Data, size_t Size, 153 1.1 kamil size_t MaxSize) { 154 1.1 kamil if (Size > MaxSize) return 0; 155 1.1 kamil size_t Idx = Rand(Size); 156 1.1 kamil Data[Idx] ^= 1 << Rand(8); 157 1.1 kamil return Size; 158 1.1 kamil } 159 1.1 kamil 160 1.1 kamil size_t MutationDispatcher::Mutate_AddWordFromManualDictionary(uint8_t *Data, 161 1.1 kamil size_t Size, 162 1.1 kamil size_t MaxSize) { 163 1.1 kamil return AddWordFromDictionary(ManualDictionary, Data, Size, MaxSize); 164 1.1 kamil } 165 1.1 kamil 166 1.1 kamil size_t MutationDispatcher::ApplyDictionaryEntry(uint8_t *Data, size_t Size, 167 1.1 kamil size_t MaxSize, 168 1.1 kamil DictionaryEntry &DE) { 169 1.1 kamil const Word &W = DE.GetW(); 170 1.1 kamil bool UsePositionHint = DE.HasPositionHint() && 171 1.1 kamil DE.GetPositionHint() + W.size() < Size && 172 1.1 kamil Rand.RandBool(); 173 1.1 kamil if (Rand.RandBool()) { // Insert W. 174 1.1 kamil if (Size + W.size() > MaxSize) return 0; 175 1.1 kamil size_t Idx = UsePositionHint ? DE.GetPositionHint() : Rand(Size + 1); 176 1.1 kamil memmove(Data + Idx + W.size(), Data + Idx, Size - Idx); 177 1.1 kamil memcpy(Data + Idx, W.data(), W.size()); 178 1.1 kamil Size += W.size(); 179 1.1 kamil } else { // Overwrite some bytes with W. 180 1.1 kamil if (W.size() > Size) return 0; 181 1.1 kamil size_t Idx = UsePositionHint ? DE.GetPositionHint() : Rand(Size - W.size()); 182 1.1 kamil memcpy(Data + Idx, W.data(), W.size()); 183 1.1 kamil } 184 1.1 kamil return Size; 185 1.1 kamil } 186 1.1 kamil 187 1.1 kamil // Somewhere in the past we have observed a comparison instructions 188 1.1 kamil // with arguments Arg1 Arg2. This function tries to guess a dictionary 189 1.1 kamil // entry that will satisfy that comparison. 190 1.1 kamil // It first tries to find one of the arguments (possibly swapped) in the 191 1.1 kamil // input and if it succeeds it creates a DE with a position hint. 192 1.1 kamil // Otherwise it creates a DE with one of the arguments w/o a position hint. 193 1.1 kamil DictionaryEntry MutationDispatcher::MakeDictionaryEntryFromCMP( 194 1.1 kamil const void *Arg1, const void *Arg2, 195 1.1 kamil const void *Arg1Mutation, const void *Arg2Mutation, 196 1.1 kamil size_t ArgSize, const uint8_t *Data, 197 1.1 kamil size_t Size) { 198 1.1 kamil bool HandleFirst = Rand.RandBool(); 199 1.1 kamil const void *ExistingBytes, *DesiredBytes; 200 1.1 kamil Word W; 201 1.1 kamil const uint8_t *End = Data + Size; 202 1.1 kamil for (int Arg = 0; Arg < 2; Arg++) { 203 1.1 kamil ExistingBytes = HandleFirst ? Arg1 : Arg2; 204 1.1 kamil DesiredBytes = HandleFirst ? Arg2Mutation : Arg1Mutation; 205 1.1 kamil HandleFirst = !HandleFirst; 206 1.1 kamil W.Set(reinterpret_cast<const uint8_t*>(DesiredBytes), ArgSize); 207 1.1 kamil const size_t kMaxNumPositions = 8; 208 1.1 kamil size_t Positions[kMaxNumPositions]; 209 1.1 kamil size_t NumPositions = 0; 210 1.1 kamil for (const uint8_t *Cur = Data; 211 1.1 kamil Cur < End && NumPositions < kMaxNumPositions; Cur++) { 212 1.1 kamil Cur = 213 1.1 kamil (const uint8_t *)SearchMemory(Cur, End - Cur, ExistingBytes, ArgSize); 214 1.1 kamil if (!Cur) break; 215 1.1 kamil Positions[NumPositions++] = Cur - Data; 216 1.1 kamil } 217 1.1 kamil if (!NumPositions) continue; 218 1.1 kamil return DictionaryEntry(W, Positions[Rand(NumPositions)]); 219 1.1 kamil } 220 1.1 kamil DictionaryEntry DE(W); 221 1.1 kamil return DE; 222 1.1 kamil } 223 1.1 kamil 224 1.1 kamil 225 1.1 kamil template <class T> 226 1.1 kamil DictionaryEntry MutationDispatcher::MakeDictionaryEntryFromCMP( 227 1.1 kamil T Arg1, T Arg2, const uint8_t *Data, size_t Size) { 228 1.1 kamil if (Rand.RandBool()) Arg1 = Bswap(Arg1); 229 1.1 kamil if (Rand.RandBool()) Arg2 = Bswap(Arg2); 230 1.1 kamil T Arg1Mutation = Arg1 + Rand(-1, 1); 231 1.1 kamil T Arg2Mutation = Arg2 + Rand(-1, 1); 232 1.1 kamil return MakeDictionaryEntryFromCMP(&Arg1, &Arg2, &Arg1Mutation, &Arg2Mutation, 233 1.1 kamil sizeof(Arg1), Data, Size); 234 1.1 kamil } 235 1.1 kamil 236 1.1 kamil DictionaryEntry MutationDispatcher::MakeDictionaryEntryFromCMP( 237 1.1 kamil const Word &Arg1, const Word &Arg2, const uint8_t *Data, size_t Size) { 238 1.1 kamil return MakeDictionaryEntryFromCMP(Arg1.data(), Arg2.data(), Arg1.data(), 239 1.1 kamil Arg2.data(), Arg1.size(), Data, Size); 240 1.1 kamil } 241 1.1 kamil 242 1.1 kamil size_t MutationDispatcher::Mutate_AddWordFromTORC( 243 1.1 kamil uint8_t *Data, size_t Size, size_t MaxSize) { 244 1.1 kamil Word W; 245 1.1 kamil DictionaryEntry DE; 246 1.1 kamil switch (Rand(4)) { 247 1.1 kamil case 0: { 248 1.1 kamil auto X = TPC.TORC8.Get(Rand.Rand()); 249 1.1 kamil DE = MakeDictionaryEntryFromCMP(X.A, X.B, Data, Size); 250 1.1 kamil } break; 251 1.1 kamil case 1: { 252 1.1 kamil auto X = TPC.TORC4.Get(Rand.Rand()); 253 1.1 kamil if ((X.A >> 16) == 0 && (X.B >> 16) == 0 && Rand.RandBool()) 254 1.1 kamil DE = MakeDictionaryEntryFromCMP((uint16_t)X.A, (uint16_t)X.B, Data, Size); 255 1.1 kamil else 256 1.1 kamil DE = MakeDictionaryEntryFromCMP(X.A, X.B, Data, Size); 257 1.1 kamil } break; 258 1.1 kamil case 2: { 259 1.1 kamil auto X = TPC.TORCW.Get(Rand.Rand()); 260 1.1 kamil DE = MakeDictionaryEntryFromCMP(X.A, X.B, Data, Size); 261 1.1 kamil } break; 262 1.1 kamil case 3: if (Options.UseMemmem) { 263 1.1 kamil auto X = TPC.MMT.Get(Rand.Rand()); 264 1.1 kamil DE = DictionaryEntry(X); 265 1.1 kamil } break; 266 1.1 kamil default: 267 1.1 kamil assert(0); 268 1.1 kamil } 269 1.1 kamil if (!DE.GetW().size()) return 0; 270 1.1 kamil Size = ApplyDictionaryEntry(Data, Size, MaxSize, DE); 271 1.1 kamil if (!Size) return 0; 272 1.1 kamil DictionaryEntry &DERef = 273 1.1 kamil CmpDictionaryEntriesDeque[CmpDictionaryEntriesDequeIdx++ % 274 1.1 kamil kCmpDictionaryEntriesDequeSize]; 275 1.1 kamil DERef = DE; 276 1.1 kamil CurrentDictionaryEntrySequence.push_back(&DERef); 277 1.1 kamil return Size; 278 1.1 kamil } 279 1.1 kamil 280 1.1 kamil size_t MutationDispatcher::Mutate_AddWordFromPersistentAutoDictionary( 281 1.1 kamil uint8_t *Data, size_t Size, size_t MaxSize) { 282 1.1 kamil return AddWordFromDictionary(PersistentAutoDictionary, Data, Size, MaxSize); 283 1.1 kamil } 284 1.1 kamil 285 1.1 kamil size_t MutationDispatcher::AddWordFromDictionary(Dictionary &D, uint8_t *Data, 286 1.1 kamil size_t Size, size_t MaxSize) { 287 1.1 kamil if (Size > MaxSize) return 0; 288 1.1 kamil if (D.empty()) return 0; 289 1.1 kamil DictionaryEntry &DE = D[Rand(D.size())]; 290 1.1 kamil Size = ApplyDictionaryEntry(Data, Size, MaxSize, DE); 291 1.1 kamil if (!Size) return 0; 292 1.1 kamil DE.IncUseCount(); 293 1.1 kamil CurrentDictionaryEntrySequence.push_back(&DE); 294 1.1 kamil return Size; 295 1.1 kamil } 296 1.1 kamil 297 1.1 kamil // Overwrites part of To[0,ToSize) with a part of From[0,FromSize). 298 1.1 kamil // Returns ToSize. 299 1.1 kamil size_t MutationDispatcher::CopyPartOf(const uint8_t *From, size_t FromSize, 300 1.1 kamil uint8_t *To, size_t ToSize) { 301 1.1 kamil // Copy From[FromBeg, FromBeg + CopySize) into To[ToBeg, ToBeg + CopySize). 302 1.1 kamil size_t ToBeg = Rand(ToSize); 303 1.1 kamil size_t CopySize = Rand(ToSize - ToBeg) + 1; 304 1.1 kamil assert(ToBeg + CopySize <= ToSize); 305 1.1 kamil CopySize = std::min(CopySize, FromSize); 306 1.1 kamil size_t FromBeg = Rand(FromSize - CopySize + 1); 307 1.1 kamil assert(FromBeg + CopySize <= FromSize); 308 1.1 kamil memmove(To + ToBeg, From + FromBeg, CopySize); 309 1.1 kamil return ToSize; 310 1.1 kamil } 311 1.1 kamil 312 1.1 kamil // Inserts part of From[0,ToSize) into To. 313 1.1 kamil // Returns new size of To on success or 0 on failure. 314 1.1 kamil size_t MutationDispatcher::InsertPartOf(const uint8_t *From, size_t FromSize, 315 1.1 kamil uint8_t *To, size_t ToSize, 316 1.1 kamil size_t MaxToSize) { 317 1.1 kamil if (ToSize >= MaxToSize) return 0; 318 1.1 kamil size_t AvailableSpace = MaxToSize - ToSize; 319 1.1 kamil size_t MaxCopySize = std::min(AvailableSpace, FromSize); 320 1.1 kamil size_t CopySize = Rand(MaxCopySize) + 1; 321 1.1 kamil size_t FromBeg = Rand(FromSize - CopySize + 1); 322 1.1 kamil assert(FromBeg + CopySize <= FromSize); 323 1.1 kamil size_t ToInsertPos = Rand(ToSize + 1); 324 1.1 kamil assert(ToInsertPos + CopySize <= MaxToSize); 325 1.1 kamil size_t TailSize = ToSize - ToInsertPos; 326 1.1 kamil if (To == From) { 327 1.1 kamil MutateInPlaceHere.resize(MaxToSize); 328 1.1 kamil memcpy(MutateInPlaceHere.data(), From + FromBeg, CopySize); 329 1.1 kamil memmove(To + ToInsertPos + CopySize, To + ToInsertPos, TailSize); 330 1.1 kamil memmove(To + ToInsertPos, MutateInPlaceHere.data(), CopySize); 331 1.1 kamil } else { 332 1.1 kamil memmove(To + ToInsertPos + CopySize, To + ToInsertPos, TailSize); 333 1.1 kamil memmove(To + ToInsertPos, From + FromBeg, CopySize); 334 1.1 kamil } 335 1.1 kamil return ToSize + CopySize; 336 1.1 kamil } 337 1.1 kamil 338 1.1 kamil size_t MutationDispatcher::Mutate_CopyPart(uint8_t *Data, size_t Size, 339 1.1 kamil size_t MaxSize) { 340 1.1 kamil if (Size > MaxSize || Size == 0) return 0; 341 1.1 kamil // If Size == MaxSize, `InsertPartOf(...)` will 342 1.1 kamil // fail so there's no point using it in this case. 343 1.1 kamil if (Size == MaxSize || Rand.RandBool()) 344 1.1 kamil return CopyPartOf(Data, Size, Data, Size); 345 1.1 kamil else 346 1.1 kamil return InsertPartOf(Data, Size, Data, Size, MaxSize); 347 1.1 kamil } 348 1.1 kamil 349 1.1 kamil size_t MutationDispatcher::Mutate_ChangeASCIIInteger(uint8_t *Data, size_t Size, 350 1.1 kamil size_t MaxSize) { 351 1.1 kamil if (Size > MaxSize) return 0; 352 1.1 kamil size_t B = Rand(Size); 353 1.1 kamil while (B < Size && !isdigit(Data[B])) B++; 354 1.1 kamil if (B == Size) return 0; 355 1.1 kamil size_t E = B; 356 1.1 kamil while (E < Size && isdigit(Data[E])) E++; 357 1.1 kamil assert(B < E); 358 1.1 kamil // now we have digits in [B, E). 359 1.1 kamil // strtol and friends don't accept non-zero-teminated data, parse it manually. 360 1.1 kamil uint64_t Val = Data[B] - '0'; 361 1.1 kamil for (size_t i = B + 1; i < E; i++) 362 1.1 kamil Val = Val * 10 + Data[i] - '0'; 363 1.1 kamil 364 1.1 kamil // Mutate the integer value. 365 1.1 kamil switch(Rand(5)) { 366 1.1 kamil case 0: Val++; break; 367 1.1 kamil case 1: Val--; break; 368 1.1 kamil case 2: Val /= 2; break; 369 1.1 kamil case 3: Val *= 2; break; 370 1.1 kamil case 4: Val = Rand(Val * Val); break; 371 1.1 kamil default: assert(0); 372 1.1 kamil } 373 1.1 kamil // Just replace the bytes with the new ones, don't bother moving bytes. 374 1.1 kamil for (size_t i = B; i < E; i++) { 375 1.1 kamil size_t Idx = E + B - i - 1; 376 1.1 kamil assert(Idx >= B && Idx < E); 377 1.1 kamil Data[Idx] = (Val % 10) + '0'; 378 1.1 kamil Val /= 10; 379 1.1 kamil } 380 1.1 kamil return Size; 381 1.1 kamil } 382 1.1 kamil 383 1.1 kamil template<class T> 384 1.1 kamil size_t ChangeBinaryInteger(uint8_t *Data, size_t Size, Random &Rand) { 385 1.1 kamil if (Size < sizeof(T)) return 0; 386 1.1 kamil size_t Off = Rand(Size - sizeof(T) + 1); 387 1.1 kamil assert(Off + sizeof(T) <= Size); 388 1.1 kamil T Val; 389 1.1 kamil if (Off < 64 && !Rand(4)) { 390 1.1 kamil Val = Size; 391 1.1 kamil if (Rand.RandBool()) 392 1.1 kamil Val = Bswap(Val); 393 1.1 kamil } else { 394 1.1 kamil memcpy(&Val, Data + Off, sizeof(Val)); 395 1.1 kamil T Add = Rand(21); 396 1.1 kamil Add -= 10; 397 1.1 kamil if (Rand.RandBool()) 398 1.1 kamil Val = Bswap(T(Bswap(Val) + Add)); // Add assuming different endiannes. 399 1.1 kamil else 400 1.1 kamil Val = Val + Add; // Add assuming current endiannes. 401 1.1 kamil if (Add == 0 || Rand.RandBool()) // Maybe negate. 402 1.1 kamil Val = -Val; 403 1.1 kamil } 404 1.1 kamil memcpy(Data + Off, &Val, sizeof(Val)); 405 1.1 kamil return Size; 406 1.1 kamil } 407 1.1 kamil 408 1.1 kamil size_t MutationDispatcher::Mutate_ChangeBinaryInteger(uint8_t *Data, 409 1.1 kamil size_t Size, 410 1.1 kamil size_t MaxSize) { 411 1.1 kamil if (Size > MaxSize) return 0; 412 1.1 kamil switch (Rand(4)) { 413 1.1 kamil case 3: return ChangeBinaryInteger<uint64_t>(Data, Size, Rand); 414 1.1 kamil case 2: return ChangeBinaryInteger<uint32_t>(Data, Size, Rand); 415 1.1 kamil case 1: return ChangeBinaryInteger<uint16_t>(Data, Size, Rand); 416 1.1 kamil case 0: return ChangeBinaryInteger<uint8_t>(Data, Size, Rand); 417 1.1 kamil default: assert(0); 418 1.1 kamil } 419 1.1 kamil return 0; 420 1.1 kamil } 421 1.1 kamil 422 1.1 kamil size_t MutationDispatcher::Mutate_CrossOver(uint8_t *Data, size_t Size, 423 1.1 kamil size_t MaxSize) { 424 1.1 kamil if (Size > MaxSize) return 0; 425 1.1 kamil if (!Corpus || Corpus->size() < 2 || Size == 0) return 0; 426 1.1 kamil size_t Idx = Rand(Corpus->size()); 427 1.1 kamil const Unit &O = (*Corpus)[Idx]; 428 1.1 kamil if (O.empty()) return 0; 429 1.1 kamil MutateInPlaceHere.resize(MaxSize); 430 1.1 kamil auto &U = MutateInPlaceHere; 431 1.1 kamil size_t NewSize = 0; 432 1.1 kamil switch(Rand(3)) { 433 1.1 kamil case 0: 434 1.1 kamil NewSize = CrossOver(Data, Size, O.data(), O.size(), U.data(), U.size()); 435 1.1 kamil break; 436 1.1 kamil case 1: 437 1.1 kamil NewSize = InsertPartOf(O.data(), O.size(), U.data(), U.size(), MaxSize); 438 1.1 kamil if (!NewSize) 439 1.1 kamil NewSize = CopyPartOf(O.data(), O.size(), U.data(), U.size()); 440 1.1 kamil break; 441 1.1 kamil case 2: 442 1.1 kamil NewSize = CopyPartOf(O.data(), O.size(), U.data(), U.size()); 443 1.1 kamil break; 444 1.1 kamil default: assert(0); 445 1.1 kamil } 446 1.1 kamil assert(NewSize > 0 && "CrossOver returned empty unit"); 447 1.1 kamil assert(NewSize <= MaxSize && "CrossOver returned overisized unit"); 448 1.1 kamil memcpy(Data, U.data(), NewSize); 449 1.1 kamil return NewSize; 450 1.1 kamil } 451 1.1 kamil 452 1.1 kamil void MutationDispatcher::StartMutationSequence() { 453 1.1 kamil CurrentMutatorSequence.clear(); 454 1.1 kamil CurrentDictionaryEntrySequence.clear(); 455 1.1 kamil } 456 1.1 kamil 457 1.1 kamil // Copy successful dictionary entries to PersistentAutoDictionary. 458 1.1 kamil void MutationDispatcher::RecordSuccessfulMutationSequence() { 459 1.1 kamil for (auto DE : CurrentDictionaryEntrySequence) { 460 1.1 kamil // PersistentAutoDictionary.AddWithSuccessCountOne(DE); 461 1.1 kamil DE->IncSuccessCount(); 462 1.1 kamil assert(DE->GetW().size()); 463 1.1 kamil // Linear search is fine here as this happens seldom. 464 1.1 kamil if (!PersistentAutoDictionary.ContainsWord(DE->GetW())) 465 1.1 kamil PersistentAutoDictionary.push_back({DE->GetW(), 1}); 466 1.1 kamil } 467 1.1 kamil } 468 1.1 kamil 469 1.1 kamil void MutationDispatcher::PrintRecommendedDictionary() { 470 1.1 kamil Vector<DictionaryEntry> V; 471 1.1 kamil for (auto &DE : PersistentAutoDictionary) 472 1.1 kamil if (!ManualDictionary.ContainsWord(DE.GetW())) 473 1.1 kamil V.push_back(DE); 474 1.1 kamil if (V.empty()) return; 475 1.1 kamil Printf("###### Recommended dictionary. ######\n"); 476 1.1 kamil for (auto &DE: V) { 477 1.1 kamil assert(DE.GetW().size()); 478 1.1 kamil Printf("\""); 479 1.1 kamil PrintASCII(DE.GetW(), "\""); 480 1.1 kamil Printf(" # Uses: %zd\n", DE.GetUseCount()); 481 1.1 kamil } 482 1.1 kamil Printf("###### End of recommended dictionary. ######\n"); 483 1.1 kamil } 484 1.1 kamil 485 1.1 kamil void MutationDispatcher::PrintMutationSequence() { 486 1.1 kamil Printf("MS: %zd ", CurrentMutatorSequence.size()); 487 1.1 kamil for (auto M : CurrentMutatorSequence) 488 1.1 kamil Printf("%s-", M.Name); 489 1.1 kamil if (!CurrentDictionaryEntrySequence.empty()) { 490 1.1 kamil Printf(" DE: "); 491 1.1 kamil for (auto DE : CurrentDictionaryEntrySequence) { 492 1.1 kamil Printf("\""); 493 1.1 kamil PrintASCII(DE->GetW(), "\"-"); 494 1.1 kamil } 495 1.1 kamil } 496 1.1 kamil } 497 1.1 kamil 498 1.1 kamil size_t MutationDispatcher::Mutate(uint8_t *Data, size_t Size, size_t MaxSize) { 499 1.1 kamil return MutateImpl(Data, Size, MaxSize, Mutators); 500 1.1 kamil } 501 1.1 kamil 502 1.1 kamil size_t MutationDispatcher::DefaultMutate(uint8_t *Data, size_t Size, 503 1.1 kamil size_t MaxSize) { 504 1.1 kamil return MutateImpl(Data, Size, MaxSize, DefaultMutators); 505 1.1 kamil } 506 1.1 kamil 507 1.1 kamil // Mutates Data in place, returns new size. 508 1.1 kamil size_t MutationDispatcher::MutateImpl(uint8_t *Data, size_t Size, 509 1.1 kamil size_t MaxSize, 510 1.1 kamil Vector<Mutator> &Mutators) { 511 1.1 kamil assert(MaxSize > 0); 512 1.1 kamil // Some mutations may fail (e.g. can't insert more bytes if Size == MaxSize), 513 1.1 kamil // in which case they will return 0. 514 1.1 kamil // Try several times before returning un-mutated data. 515 1.1 kamil for (int Iter = 0; Iter < 100; Iter++) { 516 1.1 kamil auto M = Mutators[Rand(Mutators.size())]; 517 1.1 kamil size_t NewSize = (this->*(M.Fn))(Data, Size, MaxSize); 518 1.1 kamil if (NewSize && NewSize <= MaxSize) { 519 1.1 kamil if (Options.OnlyASCII) 520 1.1 kamil ToASCII(Data, NewSize); 521 1.1 kamil CurrentMutatorSequence.push_back(M); 522 1.1 kamil return NewSize; 523 1.1 kamil } 524 1.1 kamil } 525 1.1 kamil *Data = ' '; 526 1.1 kamil return 1; // Fallback, should not happen frequently. 527 1.1 kamil } 528 1.1 kamil 529 1.1 kamil // Mask represents the set of Data bytes that are worth mutating. 530 1.1 kamil size_t MutationDispatcher::MutateWithMask(uint8_t *Data, size_t Size, 531 1.1 kamil size_t MaxSize, 532 1.1 kamil const Vector<uint8_t> &Mask) { 533 1.1 kamil assert(Size <= Mask.size()); 534 1.1 kamil // * Copy the worthy bytes into a temporary array T 535 1.1 kamil // * Mutate T 536 1.1 kamil // * Copy T back. 537 1.1 kamil // This is totally unoptimized. 538 1.1 kamil auto &T = MutateWithMaskTemp; 539 1.1 kamil if (T.size() < Size) 540 1.1 kamil T.resize(Size); 541 1.1 kamil size_t OneBits = 0; 542 1.1 kamil for (size_t I = 0; I < Size; I++) 543 1.1 kamil if (Mask[I]) 544 1.1 kamil T[OneBits++] = Data[I]; 545 1.1 kamil 546 1.1 kamil assert(!T.empty()); 547 1.1 kamil size_t NewSize = Mutate(T.data(), OneBits, OneBits); 548 1.1 kamil assert(NewSize <= OneBits); 549 1.1 kamil (void)NewSize; 550 1.1 kamil // Even if NewSize < OneBits we still use all OneBits bytes. 551 1.1 kamil for (size_t I = 0, J = 0; I < Size; I++) 552 1.1 kamil if (Mask[I]) 553 1.1 kamil Data[I] = T[J++]; 554 1.1 kamil return Size; 555 1.1 kamil } 556 1.1 kamil 557 1.1 kamil void MutationDispatcher::AddWordToManualDictionary(const Word &W) { 558 1.1 kamil ManualDictionary.push_back( 559 1.1 kamil {W, std::numeric_limits<size_t>::max()}); 560 1.1 kamil } 561 1.1 kamil 562 1.1 kamil } // namespace fuzzer 563