1- // ===- FuzzerDFSan .cpp - DFSan -based fuzzer mutator ----- ------------------===//
1+ // ===- FuzzerTraceState .cpp - Trace -based fuzzer mutator ------------------===//
22//
33// The LLVM Compiler Infrastructure
44//
55// This file is distributed under the University of Illinois Open Source
66// License. See LICENSE.TXT for details.
77//
88// ===----------------------------------------------------------------------===//
9+ // This file implements a mutation algorithm based on instruction traces and
10+ // on taint analysis feedback from DFSan.
11+ //
12+ // Instruction traces are special hooks inserted by the compiler around
13+ // interesting instructions. Currently supported traces:
14+ // * __sanitizer_cov_trace_cmp -- inserted before every ICMP instruction,
15+ // receives the type, size and arguments of ICMP.
16+ //
17+ // Every time a traced event is intercepted we analyse the data involved
18+ // in the event and suggest a mutation for future executions.
19+ // For example if 4 bytes of data that derive from input bytes {4,5,6,7}
20+ // are compared with a constant 12345,
21+ // we try to insert 12345, 12344, 12346 into bytes
22+ // {4,5,6,7} of the next fuzzed inputs.
23+ //
24+ // The fuzzer can work only with the traces, or with both traces and DFSan.
25+ //
926// DataFlowSanitizer (DFSan) is a tool for
1027// generalised dynamic data flow (taint) analysis:
1128// http://clang.llvm.org/docs/DataFlowSanitizer.html .
1229//
13- // This file implements a mutation algorithm based on taint
14- // analysis feedback from DFSan.
15- //
16- // The approach has some similarity to "Taint-based Directed Whitebox Fuzzing"
30+ // The approach with DFSan-based fuzzing has some similarity to
31+ // "Taint-based Directed Whitebox Fuzzing"
1732// by Vijay Ganesh & Tim Leek & Martin Rinard:
1833// http://dspace.mit.edu/openaccess-disseminate/1721.1/59320,
1934// but it uses a full blown LLVM IR taint analysis and separate instrumentation
2035// to analyze all of the "attack points" at once.
2136//
22- // Workflow:
37+ // Workflow with DFSan :
2338// * lib/Fuzzer/Fuzzer*.cpp is compiled w/o any instrumentation.
24- // * The code under test is compiled with DFSan *and* with special extra hooks
25- // that are inserted before dfsan. Currently supported hooks:
26- // - __sanitizer_cov_trace_cmp: inserted before every ICMP instruction,
27- // receives the type, size and arguments of ICMP.
39+ // * The code under test is compiled with DFSan *and* with instruction traces.
2840// * Every call to HOOK(a,b) is replaced by DFSan with
2941// __dfsw_HOOK(a, b, label(a), label(b)) so that __dfsw_HOOK
3042// gets all the taint labels for the arguments.
3446// * The __dfsw_* functions (implemented in this file) record the
3547// parameters (i.e. the application data and the corresponding taint labels)
3648// in a global state.
37- // * Fuzzer::MutateWithDFSan() tries to use the data recorded by __dfsw_*
38- // hooks to guide the fuzzing towards new application states.
39- // For example if 4 bytes of data that derive from input bytes {4,5,6,7}
40- // are compared with a constant 12345 and the comparison always yields
41- // the same result, we try to insert 12345, 12344, 12346 into bytes
42- // {4,5,6,7} of the next fuzzed inputs.
49+ // * Fuzzer::ApplyTraceBasedMutation() tries to use the data recorded
50+ // by __dfsw_* hooks to guide the fuzzing towards new application states.
4351//
44- // This code does not function when DFSan is not linked in.
52+ // Parts of this code will not function when DFSan is not linked in.
4553// Instead of using ifdefs and thus requiring a separate build of lib/Fuzzer
4654// we redeclare the dfsan_* interface functions as weak and check if they
4755// are nullptr before calling.
5361// like test/dfsan/DFSanSimpleCmpTest.cpp.
5462// ===----------------------------------------------------------------------===//
5563
56- /* Example of manual usage:
64+ /* Example of manual usage (-fsanitize=dataflow is optional) :
5765(
5866 cd $LLVM/lib/Fuzzer/
5967 clang -fPIC -c -g -O2 -std=c++11 Fuzzer*.cpp
@@ -168,9 +176,9 @@ struct TraceBasedMutation {
168176 uint64_t Data;
169177};
170178
171- class DFSanState {
179+ class TraceState {
172180 public:
173- DFSanState (const Fuzzer::FuzzingOptions &Options, const Unit &CurrentUnit)
181+ TraceState (const Fuzzer::FuzzingOptions &Options, const Unit &CurrentUnit)
174182 : Options(Options), CurrentUnit(CurrentUnit) {}
175183
176184 LabelRange GetLabelRange (dfsan_label L);
@@ -208,7 +216,7 @@ class DFSanState {
208216 const Unit &CurrentUnit;
209217};
210218
211- LabelRange DFSanState ::GetLabelRange (dfsan_label L) {
219+ LabelRange TraceState ::GetLabelRange (dfsan_label L) {
212220 LabelRange &LR = LabelRanges[L];
213221 if (LR.Beg < LR.End || L == 0 )
214222 return LR;
@@ -218,7 +226,7 @@ LabelRange DFSanState::GetLabelRange(dfsan_label L) {
218226 return LR = LabelRange::Singleton (LI);
219227}
220228
221- void DFSanState ::ApplyTraceBasedMutation (size_t Idx, fuzzer::Unit *U) {
229+ void TraceState ::ApplyTraceBasedMutation (size_t Idx, fuzzer::Unit *U) {
222230 assert (Idx < Mutations.size ());
223231 auto &M = Mutations[Idx];
224232 if (Options.Verbosity >= 3 )
@@ -227,7 +235,7 @@ void DFSanState::ApplyTraceBasedMutation(size_t Idx, fuzzer::Unit *U) {
227235 memcpy (U->data () + M.Pos , &M.Data , M.Size );
228236}
229237
230- void DFSanState ::DFSanCmpCallback (uintptr_t PC, size_t CmpSize, size_t CmpType,
238+ void TraceState ::DFSanCmpCallback (uintptr_t PC, size_t CmpSize, size_t CmpType,
231239 uint64_t Arg1, uint64_t Arg2, dfsan_label L1,
232240 dfsan_label L2) {
233241 assert (ReallyHaveDFSan ());
@@ -263,7 +271,7 @@ void DFSanState::DFSanCmpCallback(uintptr_t PC, size_t CmpSize, size_t CmpType,
263271 << " \n " ;
264272}
265273
266- int DFSanState ::TryToAddDesiredData (uint64_t PresentData, uint64_t DesiredData,
274+ int TraceState ::TryToAddDesiredData (uint64_t PresentData, uint64_t DesiredData,
267275 size_t DataSize) {
268276 int Res = 0 ;
269277 const uint8_t *Beg = CurrentUnit.data ();
@@ -284,7 +292,7 @@ int DFSanState::TryToAddDesiredData(uint64_t PresentData, uint64_t DesiredData,
284292 return Res;
285293}
286294
287- void DFSanState ::TraceCmpCallback (size_t CmpSize, size_t CmpType, uint64_t Arg1,
295+ void TraceState ::TraceCmpCallback (size_t CmpSize, size_t CmpType, uint64_t Arg1,
288296 uint64_t Arg2) {
289297 if (!Options.UseTraces ) return ;
290298 int Added = 0 ;
@@ -298,29 +306,29 @@ void DFSanState::TraceCmpCallback(size_t CmpSize, size_t CmpType, uint64_t Arg1,
298306 }
299307}
300308
301- static DFSanState *DFSan ;
309+ static TraceState *TS ;
302310
303311void Fuzzer::StartTraceRecording () {
304- if (!DFSan ) return ;
305- DFSan ->StartTraceRecording ();
312+ if (!TS ) return ;
313+ TS ->StartTraceRecording ();
306314}
307315
308316size_t Fuzzer::StopTraceRecording () {
309- if (!DFSan ) return 0 ;
310- return DFSan ->StopTraceRecording ();
317+ if (!TS ) return 0 ;
318+ return TS ->StopTraceRecording ();
311319}
312320
313321void Fuzzer::ApplyTraceBasedMutation (size_t Idx, Unit *U) {
314- assert (DFSan );
315- DFSan ->ApplyTraceBasedMutation (Idx, U);
322+ assert (TS );
323+ TS ->ApplyTraceBasedMutation (Idx, U);
316324}
317325
318- void Fuzzer::InitializeDFSan () {
319- if (!Options.UseDFSan ) return ;
320- DFSan = new DFSanState (Options, CurrentUnit);
326+ void Fuzzer::InitializeTraceState () {
327+ if (!Options.UseTraces && !Options. UseDFSan ) return ;
328+ TS = new TraceState (Options, CurrentUnit);
321329 CurrentUnit.resize (Options.MaxLen );
322330 // The rest really requires DFSan.
323- if (!ReallyHaveDFSan ()) return ;
331+ if (!ReallyHaveDFSan () || !Options. UseDFSan ) return ;
324332 for (size_t i = 0 ; i < static_cast <size_t >(Options.MaxLen ); i++) {
325333 dfsan_label L = dfsan_create_label (" input" , (void *)(i + 1 ));
326334 // We assume that no one else has called dfsan_create_label before.
@@ -331,38 +339,40 @@ void Fuzzer::InitializeDFSan() {
331339
332340} // namespace fuzzer
333341
334- using fuzzer::DFSan ;
342+ using fuzzer::TS ;
335343
336344extern " C" {
337345void __dfsw___sanitizer_cov_trace_cmp (uint64_t SizeAndType, uint64_t Arg1,
338346 uint64_t Arg2, dfsan_label L0,
339347 dfsan_label L1, dfsan_label L2) {
348+ assert (TS);
340349 assert (L0 == 0 );
341350 uintptr_t PC = reinterpret_cast <uintptr_t >(__builtin_return_address (0 ));
342351 uint64_t CmpSize = (SizeAndType >> 32 ) / 8 ;
343352 uint64_t Type = (SizeAndType << 32 ) >> 32 ;
344- DFSan ->DFSanCmpCallback (PC, CmpSize, Type, Arg1, Arg2, L1, L2);
353+ TS ->DFSanCmpCallback (PC, CmpSize, Type, Arg1, Arg2, L1, L2);
345354}
346355
347356void dfsan_weak_hook_memcmp (void *caller_pc, const void *s1, const void *s2,
348357 size_t n, dfsan_label s1_label,
349358 dfsan_label s2_label, dfsan_label n_label) {
359+ assert (TS);
350360 uintptr_t PC = reinterpret_cast <uintptr_t >(caller_pc);
351361 uint64_t S1 = 0 , S2 = 0 ;
352362 // Simplification: handle only first 8 bytes.
353363 memcpy (&S1, s1, std::min (n, sizeof (S1)));
354364 memcpy (&S2, s2, std::min (n, sizeof (S2)));
355365 dfsan_label L1 = dfsan_read_label (s1, n);
356366 dfsan_label L2 = dfsan_read_label (s2, n);
357- DFSan ->DFSanCmpCallback (PC, n, fuzzer::ICMP_EQ, S1, S2, L1, L2);
367+ TS ->DFSanCmpCallback (PC, n, fuzzer::ICMP_EQ, S1, S2, L1, L2);
358368}
359369
360370void __sanitizer_cov_trace_cmp (uint64_t SizeAndType, uint64_t Arg1,
361371 uint64_t Arg2) {
362- if (!DFSan ) return ;
372+ if (!TS ) return ;
363373 uint64_t CmpSize = (SizeAndType >> 32 ) / 8 ;
364374 uint64_t Type = (SizeAndType << 32 ) >> 32 ;
365- DFSan ->TraceCmpCallback (CmpSize, Type, Arg1, Arg2);
375+ TS ->TraceCmpCallback (CmpSize, Type, Arg1, Arg2);
366376}
367377
368378} // extern "C"
0 commit comments