76 #include <sanitizer/dfsan_interface.h>
80 #include <unordered_map>
86 void dfsan_set_label(dfsan_label label,
void *
addr,
size_t size);
88 void dfsan_add_label(dfsan_label label,
void *addr,
size_t size);
90 const struct dfsan_label_info *dfsan_get_label_info(dfsan_label label);
92 dfsan_label dfsan_read_label(
const void *addr,
size_t size);
98 return &dfsan_create_label !=
nullptr;
117 template <
class U,
class S>
120 case ICMP_EQ :
return Arg1 == Arg2;
121 case ICMP_NE :
return Arg1 != Arg2;
126 case ICMP_SGT:
return (S)Arg1 > (S)Arg2;
127 case ICMP_SGE:
return (S)Arg1 >= (S)Arg2;
128 case ICMP_SLT:
return (S)Arg1 < (S)Arg2;
129 case ICMP_SLE:
return (S)Arg1 <= (S)Arg2;
130 default: assert(0 &&
"unsupported CmpType");
135 static bool ComputeCmp(
size_t CmpSize,
size_t CmpType, uint64_t Arg1,
137 if (CmpSize == 8)
return ComputeCmp<uint64_t, int64_t>(CmpType, Arg1, Arg2);
138 if (CmpSize == 4)
return ComputeCmp<uint32_t, int32_t>(CmpType, Arg1, Arg2);
139 if (CmpSize == 2)
return ComputeCmp<uint16_t, int16_t>(CmpType, Arg1, Arg2);
140 if (CmpSize == 1)
return ComputeCmp<uint8_t, int8_t>(CmpType, Arg1, Arg2);
141 assert(0 &&
"unsupported type size");
150 LabelRange(uint16_t Beg = 0, uint16_t End = 0) : Beg(Beg), End(End) {}
153 if (LR1.
Beg == LR1.
End)
return LR2;
154 if (LR2.
Beg == LR2.
End)
return LR1;
158 return *
this = Join(*
this, LR);
161 uint16_t Idx = (uint16_t)(uintptr_t)LI->userdata;
163 return {(uint16_t)(Idx - 1), Idx};
177 : Options(Options), CurrentUnit(CurrentUnit) {}
180 void DFSanCmpCallback(uintptr_t PC,
size_t CmpSize,
size_t CmpType,
181 uint64_t Arg1, uint64_t Arg2, dfsan_label L1,
183 void TraceCmpCallback(
size_t CmpSize,
size_t CmpType, uint64_t Arg1,
185 int TryToAddDesiredData(uint64_t PresentData, uint64_t DesiredData,
189 if (!Options.UseTraces)
return;
190 RecordingTraces =
true;
195 RecordingTraces =
false;
196 std::random_shuffle(Mutations.begin(), Mutations.end());
197 return Mutations.size();
200 void ApplyTraceBasedMutation(
size_t Idx,
fuzzer::Unit *U);
203 bool IsTwoByteData(uint64_t Data) {
204 int64_t
Signed =
static_cast<int64_t
>(Data);
206 return Signed == 0 || Signed == -1L;
208 bool RecordingTraces =
false;
209 std::vector<TraceBasedMutation> Mutations;
210 LabelRange LabelRanges[1 << (
sizeof(dfsan_label) * 8)] = {};
211 const Fuzzer::FuzzingOptions &Options;
212 const Unit &CurrentUnit;
217 if (LR.
Beg < LR.
End || L == 0)
219 const dfsan_label_info *LI = dfsan_get_label_info(L);
220 if (LI->l1 || LI->l2)
221 return LR = LabelRange::Join(GetLabelRange(LI->l1), GetLabelRange(LI->l2));
222 return LR = LabelRange::Singleton(LI);
225 void TraceState::ApplyTraceBasedMutation(
size_t Idx,
fuzzer::Unit *U) {
226 assert(Idx < Mutations.size());
227 auto &M = Mutations[Idx];
228 if (Options.Verbosity >= 3)
229 Printf(
"TBM %zd %zd %zd\n", M.Pos, M.Size, M.Data);
230 if (M.Pos + M.Size > U->size())
return;
231 memcpy(U->data() + M.Pos, &M.Data, M.Size);
234 void TraceState::DFSanCmpCallback(uintptr_t PC,
size_t CmpSize,
size_t CmpType,
235 uint64_t Arg1, uint64_t Arg2, dfsan_label L1,
238 if (!RecordingTraces)
return;
239 if (L1 == 0 && L2 == 0)
241 if (L1 != 0 && L2 != 0)
243 bool Res =
ComputeCmp(CmpSize, CmpType, Arg1, Arg2);
244 uint64_t Data = L1 ? Arg2 : Arg1;
245 LabelRange LR = L1 ? GetLabelRange(L1) : GetLabelRange(L2);
247 for (
size_t Pos = LR.
Beg; Pos + CmpSize <= LR.
End; Pos++) {
248 Mutations.push_back({Pos, CmpSize, Data});
249 Mutations.push_back({Pos, CmpSize, Data + 1});
250 Mutations.push_back({Pos, CmpSize, Data - 1});
253 if (CmpSize > LR.
End - LR.
Beg)
257 if (Options.Verbosity >= 3)
258 Printf(
"DFSAN: PC %lx S %zd T %zd A1 %llx A2 %llx R %d L1 %d L2 %d MU %zd\n",
259 PC, CmpSize, CmpType, Arg1, Arg2, Res, L1, L2, Mutations.size());
262 int TraceState::TryToAddDesiredData(uint64_t PresentData, uint64_t DesiredData,
265 const uint8_t *Beg = CurrentUnit.data();
266 const uint8_t *End = Beg + CurrentUnit.size();
267 for (
const uint8_t *Cur = Beg; Cur < End; Cur += DataSize) {
268 Cur = (uint8_t *)memmem(Cur, End - Cur, &PresentData, DataSize);
271 size_t Pos = Cur - Beg;
272 assert(Pos < CurrentUnit.size());
273 Mutations.push_back({Pos, DataSize, DesiredData});
274 Mutations.push_back({Pos, DataSize, DesiredData + 1});
275 Mutations.push_back({Pos, DataSize, DesiredData - 1});
282 void TraceState::TraceCmpCallback(
size_t CmpSize,
size_t CmpType, uint64_t Arg1,
284 if (!RecordingTraces)
return;
286 if (Options.Verbosity >= 3)
287 Printf(
"TraceCmp: %zd %zd\n", Arg1, Arg2);
288 Added += TryToAddDesiredData(Arg1, Arg2, CmpSize);
289 Added += TryToAddDesiredData(Arg2, Arg1, CmpSize);
290 if (!Added && CmpSize == 4 && IsTwoByteData(Arg1) && IsTwoByteData(Arg2)) {
291 Added += TryToAddDesiredData(Arg1, Arg2, 2);
292 Added += TryToAddDesiredData(Arg2, Arg1, 2);
298 void Fuzzer::StartTraceRecording() {
303 size_t Fuzzer::StopTraceRecording() {
308 void Fuzzer::ApplyTraceBasedMutation(
size_t Idx,
Unit *U) {
313 void Fuzzer::InitializeTraceState() {
314 if (!Options.UseTraces)
return;
316 CurrentUnit.resize(Options.MaxLen);
319 for (
size_t i = 0; i < static_cast<size_t>(Options.MaxLen); i++) {
320 dfsan_label L = dfsan_create_label(
"input", (
void*)(i + 1));
323 dfsan_set_label(L, &CurrentUnit[i], 1);
333 uint64_t Arg2, dfsan_label L0,
334 dfsan_label L1, dfsan_label L2) {
337 uintptr_t PC =
reinterpret_cast<uintptr_t
>(__builtin_return_address(0));
338 uint64_t CmpSize = (SizeAndType >> 32) / 8;
339 uint64_t
Type = (SizeAndType << 32) >> 32;
344 size_t n, dfsan_label s1_label,
345 dfsan_label s2_label, dfsan_label n_label) {
347 uintptr_t PC =
reinterpret_cast<uintptr_t
>(caller_pc);
348 uint64_t S1 = 0, S2 = 0;
350 memcpy(&S1, s1,
std::min(n,
sizeof(S1)));
351 memcpy(&S2, s2,
std::min(n,
sizeof(S2)));
352 dfsan_label L1 = dfsan_read_label(s1, n);
353 dfsan_label L2 = dfsan_read_label(s2, n);
360 uint64_t CmpSize = (SizeAndType >> 32) / 8;
361 uint64_t
Type = (SizeAndType << 32) >> 32;
LabelRange & Join(LabelRange LR)
LabelRange(uint16_t Beg=0, uint16_t End=0)
TraceState(const Fuzzer::FuzzingOptions &Options, const Unit &CurrentUnit)
static bool ReallyHaveDFSan()
static LabelRange Join(LabelRange LR1, LabelRange LR2)
Number of individual test Apply this number of consecutive mutations to each input exit after the first new interesting input is found the minimized corpus is saved into the first input directory Number of jobs to run If min(jobs, NumberOfCpuCores()/2)\" is used.") FUZZER_FLAG_INT(reload
unsigned greater or equal
void TraceCmpCallback(size_t CmpSize, size_t CmpType, uint64_t Arg1, uint64_t Arg2)
void __sanitizer_cov_trace_cmp(uint64_t SizeAndType, uint64_t Arg1, uint64_t Arg2)
void Printf(const char *Fmt,...)
void ApplyTraceBasedMutation(size_t Idx, fuzzer::Unit *U)
void StartTraceRecording()
static LabelRange Singleton(const dfsan_label_info *LI)
void DFSanCmpCallback(uintptr_t PC, size_t CmpSize, size_t CmpType, uint64_t Arg1, uint64_t Arg2, dfsan_label L1, dfsan_label L2)
void __dfsw___sanitizer_cov_trace_cmp(uint64_t SizeAndType, uint64_t Arg1, uint64_t Arg2, dfsan_label L0, dfsan_label L1, dfsan_label L2)
size_t StopTraceRecording()
void dfsan_weak_hook_memcmp(void *caller_pc, const void *s1, const void *s2, size_t n, dfsan_label s1_label, dfsan_label s2_label, dfsan_label n_label)
__attribute__((weak)) dfsan_label dfsan_create_label(const char *desc
std::vector< uint8_t > Unit
static bool ComputeCmp(size_t CmpSize, size_t CmpType, uint64_t Arg1, uint64_t Arg2)