1 #include "fuzz_cmn.h"
2 
BytesToHex(const uint8_t * data,size_t size)3 std::string BytesToHex(const uint8_t* data, size_t size) {
4   std::string result = "{";
5   if (data && size) {
6     StringAppendF(&result, "0x%02X", data[0]);
7     for (auto i = 1; i < size; i++) {
8       StringAppendF(&result, ", 0x%02X", data[i]);
9     }
10   }
11   result += "}";
12 
13   return result;
14 }
15 
BytesToHex(const bytes_t & data)16 std::string BytesToHex(const bytes_t& data) {
17   return BytesToHex(&data[0], data.size());
18 }
19 
UnpackPackets(const uint8_t * Data,size_t Size)20 static std::vector<bytes_t> UnpackPackets(const uint8_t* Data, size_t Size) {
21   std::vector<bytes_t> result;
22   while (Size > 0) {
23     auto s = *Data++;
24     Size--;
25 
26     if (s > Size) {
27       s = Size;
28     }
29 
30     if (s > 0) {
31       result.push_back(bytes_t(Data, Data + s));
32     }
33 
34     Size -= s;
35     Data += s;
36   }
37 
38   return result;
39 }
40 
PackPackets(const std::vector<bytes_t> & Packets,uint8_t * Data,size_t MaxSize)41 static size_t PackPackets(const std::vector<bytes_t>& Packets, uint8_t* Data,
42                           size_t MaxSize) {
43   size_t TotalSize = 0;
44 
45   for (auto it = Packets.cbegin(); MaxSize > 0 && it != Packets.cend(); ++it) {
46     auto s = it->size();
47     if (s == 0) {
48       // skip empty packets
49       continue;
50     }
51 
52     if (s > MaxSize - 1) {
53       s = MaxSize - 1;
54     }
55     *Data++ = (uint8_t)s;
56     MaxSize--;
57 
58     memcpy(Data, it->data(), s);
59     MaxSize -= s;
60     Data += s;
61 
62     TotalSize += (s + 1);
63   }
64 
65   return TotalSize;
66 }
67 
LLVMFuzzerCustomMutator(uint8_t * Data,size_t Size,size_t MaxSize,uint Seed)68 extern "C" size_t LLVMFuzzerCustomMutator(uint8_t* Data, size_t Size,
69                                           size_t MaxSize, uint Seed) {
70   const uint MAX_PACKET_SIZE = 255;
71   auto Packets = UnpackPackets(Data, Size);
72   auto odd = Seed % 100;
73   if (odd < 10 || Packets.size() == 0) {
74     // ~10% chance to insert a new packet
75     auto len = (Seed >> 8) % MAX_PACKET_SIZE;
76     if (Packets.size() > 0) {
77       auto pos = (Seed >> 16) % Packets.size();
78       Packets.insert(Packets.begin() + pos, bytes_t(len));
79     } else {
80       Packets.push_back(bytes_t(len));
81     }
82   } else if (odd < 20 && Packets.size() > 1) {
83     // ~10% chance to drop a packet
84     auto pos = (Seed >> 16) % Packets.size();
85     Packets.erase(Packets.begin() + pos);
86   } else if (Packets.size() > 0) {
87     // ~80% chance to mutate a packet, maximium length 255
88     auto pos = (Seed >> 16) % Packets.size();
89     auto& p = Packets[pos];
90 
91     auto size = p.size();
92     p.resize(MAX_PACKET_SIZE);
93     size = LLVMFuzzerMutate(p.data(), size, MAX_PACKET_SIZE);
94     p.resize(size);
95   }
96 
97   Fuzz_FixPackets(Packets, Seed);
98 
99   Size = PackPackets(Packets, Data, MaxSize);
100   FUZZLOG("Packet size:%zu, data=%s", Packets.size(),
101           BytesToHex(Data, Size).c_str());
102   return Size;
103 }
104 
LLVMFuzzerTestOneInput(const uint8_t * Data,size_t Size)105 extern "C" int LLVMFuzzerTestOneInput(const uint8_t* Data, size_t Size) {
106   const char* argv[] = {fuzzer_name};
107   base::CommandLine::Init(1, argv);
108   logging::SetLogItems(false, false, false, false);
109 
110   if (Size > 0) {
111     auto Packets = UnpackPackets(Data, Size);
112     Fuzz_RunPackets(Packets);
113   }
114 
115   if (__gcov_flush) {
116     __gcov_flush();
117   }
118 
119   return 0;
120 }
121 
LLVMFuzzerInitialize(int * argc,char *** argv)122 extern "C" int LLVMFuzzerInitialize(int* argc, char*** argv) {
123   base::CommandLine args(*argc, *argv);
124   if (args.HasSwitch("v") || args.HasSwitch("verbose")) {
125     nfc_debug_enabled = true;
126     FUZZLOG("Debugging output enabled");
127   } else {
128     nfc_debug_enabled = false;
129   }
130 
131   return 0;
132 }
133