| #include "fuzz_cmn.h" |
| |
| std::string BytesToHex(const uint8_t* data, size_t size) { |
| std::string result = "{"; |
| if (data && size) { |
| StringAppendF(&result, "0x%02X", data[0]); |
| for (auto i = 1; i < size; i++) { |
| StringAppendF(&result, ", 0x%02X", data[i]); |
| } |
| } |
| result += "}"; |
| |
| return result; |
| } |
| |
| std::string BytesToHex(const bytes_t& data) { |
| return BytesToHex(&data[0], data.size()); |
| } |
| |
| static std::vector<bytes_t> UnpackPackets(const uint8_t* Data, size_t Size) { |
| std::vector<bytes_t> result; |
| while (Size > 0) { |
| auto s = *Data++; |
| Size--; |
| |
| if (s > Size) { |
| s = Size; |
| } |
| |
| if (s > 0) { |
| result.push_back(bytes_t(Data, Data + s)); |
| } |
| |
| Size -= s; |
| Data += s; |
| } |
| |
| return result; |
| } |
| |
| static size_t PackPackets(const std::vector<bytes_t>& Packets, uint8_t* Data, |
| size_t MaxSize) { |
| size_t TotalSize = 0; |
| |
| for (auto it = Packets.cbegin(); MaxSize > 0 && it != Packets.cend(); ++it) { |
| auto s = it->size(); |
| if (s == 0) { |
| // skip empty packets |
| continue; |
| } |
| |
| if (s > MaxSize - 1) { |
| s = MaxSize - 1; |
| } |
| *Data++ = (uint8_t)s; |
| MaxSize--; |
| |
| memcpy(Data, it->data(), s); |
| MaxSize -= s; |
| Data += s; |
| |
| TotalSize += (s + 1); |
| } |
| |
| return TotalSize; |
| } |
| |
| extern "C" size_t LLVMFuzzerCustomMutator(uint8_t* Data, size_t Size, |
| size_t MaxSize, uint Seed) { |
| const uint MAX_PACKET_SIZE = 255; |
| auto Packets = UnpackPackets(Data, Size); |
| auto odd = Seed % 100; |
| if (odd < 10 || Packets.size() == 0) { |
| // ~10% chance to insert a new packet |
| auto len = (Seed >> 8) % MAX_PACKET_SIZE; |
| if (Packets.size() > 0) { |
| auto pos = (Seed >> 16) % Packets.size(); |
| Packets.insert(Packets.begin() + pos, bytes_t(len)); |
| } else { |
| Packets.push_back(bytes_t(len)); |
| } |
| } else if (odd < 20 && Packets.size() > 1) { |
| // ~10% chance to drop a packet |
| auto pos = (Seed >> 16) % Packets.size(); |
| Packets.erase(Packets.begin() + pos); |
| } else if (Packets.size() > 0) { |
| // ~80% chance to mutate a packet, maximium length 255 |
| auto pos = (Seed >> 16) % Packets.size(); |
| auto& p = Packets[pos]; |
| |
| auto size = p.size(); |
| p.resize(MAX_PACKET_SIZE); |
| size = LLVMFuzzerMutate(p.data(), size, MAX_PACKET_SIZE); |
| p.resize(size); |
| } |
| |
| Fuzz_FixPackets(Packets, Seed); |
| |
| Size = PackPackets(Packets, Data, MaxSize); |
| FUZZLOG("Packet size:%zu, data=%s", Packets.size(), |
| BytesToHex(Data, Size).c_str()); |
| return Size; |
| } |
| |
| extern "C" int LLVMFuzzerTestOneInput(const uint8_t* Data, size_t Size) { |
| android::base::SetDefaultTag(fuzzer_name); |
| |
| if (Size > 0) { |
| auto Packets = UnpackPackets(Data, Size); |
| Fuzz_RunPackets(Packets); |
| } |
| |
| if (__gcov_flush) { |
| __gcov_flush(); |
| } |
| |
| return 0; |
| } |
| |
| extern "C" int LLVMFuzzerInitialize(int* /*argc*/, char*** /*argv*/) { |
| android::base::SetMinimumLogSeverity(android::base::DEBUG); |
| FUZZLOG("Debugging output enabled"); |
| |
| return 0; |
| } |