1 /* SanitizeCoverage.cpp ported to AFL++ LTO :-) */
2
3 #define AFL_LLVM_PASS
4
5 #include <stdio.h>
6 #include <stdlib.h>
7 #include <unistd.h>
8 #include <string.h>
9 #include <sys/time.h>
10
11 #include <list>
12 #include <string>
13 #include <fstream>
14 #include <set>
15 #include <iostream>
16
17 #include "llvm/Transforms/Instrumentation/SanitizerCoverage.h"
18 #include "llvm/ADT/ArrayRef.h"
19 #include "llvm/ADT/SmallVector.h"
20 #if LLVM_VERSION_MAJOR < 17
21 #include "llvm/ADT/Triple.h"
22 #include "llvm/Analysis/EHPersonalities.h"
23 #else
24 #include "llvm/IR/EHPersonalities.h"
25 #endif
26 #include "llvm/Analysis/PostDominators.h"
27 #include "llvm/Analysis/ValueTracking.h"
28 #include "llvm/IR/BasicBlock.h"
29 #include "llvm/IR/CFG.h"
30 #include "llvm/IR/Constant.h"
31 #include "llvm/IR/DataLayout.h"
32 #include "llvm/IR/DebugInfo.h"
33 #include "llvm/IR/Dominators.h"
34 #include "llvm/IR/Function.h"
35 #include "llvm/IR/GlobalVariable.h"
36 #include "llvm/IR/IRBuilder.h"
37 #include "llvm/IR/InlineAsm.h"
38 #include "llvm/IR/Instructions.h"
39 #include "llvm/IR/IntrinsicInst.h"
40 #include "llvm/IR/Intrinsics.h"
41 #include "llvm/IR/LLVMContext.h"
42 #include "llvm/IR/MDBuilder.h"
43 #include "llvm/IR/Mangler.h"
44 #include "llvm/IR/Module.h"
45 #include "llvm/IR/Type.h"
46 #include "llvm/InitializePasses.h"
47 #include "llvm/Pass.h"
48 #include "llvm/Support/CommandLine.h"
49 #include "llvm/Support/Debug.h"
50 #include "llvm/Support/SpecialCaseList.h"
51 #include "llvm/Support/VirtualFileSystem.h"
52 #include "llvm/Support/raw_ostream.h"
53 #include "llvm/Transforms/Instrumentation.h"
54 #if LLVM_VERSION_MAJOR < 17
55 #include "llvm/Transforms/IPO/PassManagerBuilder.h"
56 #endif
57 #include "llvm/Transforms/Utils/BasicBlockUtils.h"
58 #include "llvm/Transforms/Utils/BasicBlockUtils.h"
59 #include "llvm/Transforms/Utils/ModuleUtils.h"
60 #include "llvm/Passes/PassPlugin.h"
61 #include "llvm/Passes/PassBuilder.h"
62 #include "llvm/IR/PassManager.h"
63
64 #include "config.h"
65 #include "debug.h"
66 #include "afl-llvm-common.h"
67
68 using namespace llvm;
69
70 #define DEBUG_TYPE "sancov"
71
72 const char SanCovTracePCIndirName[] = "__sanitizer_cov_trace_pc_indir";
73 const char SanCovTracePCName[] = "__sanitizer_cov_trace_pc";
74 // const char SanCovTracePCGuardName =
75 // "__sanitizer_cov_trace_pc_guard";
76 const char SanCovGuardsSectionName[] = "sancov_guards";
77 const char SanCovCountersSectionName[] = "sancov_cntrs";
78 const char SanCovBoolFlagSectionName[] = "sancov_bools";
79 const char SanCovPCsSectionName[] = "sancov_pcs";
80
81 static cl::opt<int> ClCoverageLevel(
82 "lto-coverage-level",
83 cl::desc("Sanitizer Coverage. 0: none, 1: entry block, 2: all blocks, "
84 "3: all blocks and critical edges"),
85 cl::Hidden, cl::init(3));
86
87 static cl::opt<bool> ClTracePC("lto-coverage-trace-pc",
88 cl::desc("Experimental pc tracing"), cl::Hidden,
89 cl::init(false));
90
91 static cl::opt<bool> ClTracePCGuard("lto-coverage-trace-pc-guard",
92 cl::desc("pc tracing with a guard"),
93 cl::Hidden, cl::init(false));
94
95 // If true, we create a global variable that contains PCs of all instrumented
96 // BBs, put this global into a named section, and pass this section's bounds
97 // to __sanitizer_cov_pcs_init.
98 // This way the coverage instrumentation does not need to acquire the PCs
99 // at run-time. Works with trace-pc-guard, inline-8bit-counters, and
100 // inline-bool-flag.
101 static cl::opt<bool> ClCreatePCTable("lto-coverage-pc-table",
102 cl::desc("create a static PC table"),
103 cl::Hidden, cl::init(false));
104
105 static cl::opt<bool> ClInline8bitCounters(
106 "lto-coverage-inline-8bit-counters",
107 cl::desc("increments 8-bit counter for every edge"), cl::Hidden,
108 cl::init(false));
109
110 static cl::opt<bool> ClInlineBoolFlag(
111 "lto-coverage-inline-bool-flag",
112 cl::desc("sets a boolean flag for every edge"), cl::Hidden,
113 cl::init(false));
114
115 static cl::opt<bool> ClPruneBlocks(
116 "lto-coverage-prune-blocks",
117 cl::desc("Reduce the number of instrumented blocks"), cl::Hidden,
118 cl::init(true));
119
120 namespace llvm {
121
122 void initializeModuleSanitizerCoverageLTOLegacyPassPass(PassRegistry &PB);
123
124 }
125
126 namespace {
127
getOptions(int LegacyCoverageLevel)128 SanitizerCoverageOptions getOptions(int LegacyCoverageLevel) {
129
130 SanitizerCoverageOptions Res;
131 switch (LegacyCoverageLevel) {
132
133 case 0:
134 Res.CoverageType = SanitizerCoverageOptions::SCK_None;
135 break;
136 case 1:
137 Res.CoverageType = SanitizerCoverageOptions::SCK_Function;
138 break;
139 case 2:
140 Res.CoverageType = SanitizerCoverageOptions::SCK_BB;
141 break;
142 case 3:
143 Res.CoverageType = SanitizerCoverageOptions::SCK_Edge;
144 break;
145 case 4:
146 Res.CoverageType = SanitizerCoverageOptions::SCK_Edge;
147 Res.IndirectCalls = true;
148 break;
149
150 }
151
152 return Res;
153
154 }
155
OverrideFromCL(SanitizerCoverageOptions Options)156 SanitizerCoverageOptions OverrideFromCL(SanitizerCoverageOptions Options) {
157
158 // Sets CoverageType and IndirectCalls.
159 SanitizerCoverageOptions CLOpts = getOptions(ClCoverageLevel);
160 Options.CoverageType = std::max(Options.CoverageType, CLOpts.CoverageType);
161 Options.IndirectCalls |= CLOpts.IndirectCalls;
162 Options.TracePC |= ClTracePC;
163 Options.TracePCGuard |= ClTracePCGuard;
164 Options.Inline8bitCounters |= ClInline8bitCounters;
165 Options.InlineBoolFlag |= ClInlineBoolFlag;
166 Options.PCTable |= ClCreatePCTable;
167 Options.NoPrune |= !ClPruneBlocks;
168 if (!Options.TracePCGuard && !Options.TracePC &&
169 !Options.Inline8bitCounters && !Options.InlineBoolFlag)
170 Options.TracePCGuard = true; // TracePCGuard is default.
171 return Options;
172
173 }
174
175 using DomTreeCallback = function_ref<const DominatorTree *(Function &F)>;
176 using PostDomTreeCallback =
177 function_ref<const PostDominatorTree *(Function &F)>;
178
179 class ModuleSanitizerCoverageLTO
180 : public PassInfoMixin<ModuleSanitizerCoverageLTO> {
181
182 public:
ModuleSanitizerCoverageLTO(const SanitizerCoverageOptions & Options=SanitizerCoverageOptions ())183 ModuleSanitizerCoverageLTO(
184 const SanitizerCoverageOptions &Options = SanitizerCoverageOptions())
185 : Options(OverrideFromCL(Options)) {
186
187 }
188
189 bool instrumentModule(Module &M, DomTreeCallback DTCallback,
190 PostDomTreeCallback PDTCallback);
191
192 PreservedAnalyses run(Module &M, ModuleAnalysisManager &MAM);
193
194 private:
195 void instrumentFunction(Function &F, DomTreeCallback DTCallback,
196 PostDomTreeCallback PDTCallback);
197 void InjectCoverageForIndirectCalls(Function &F,
198 ArrayRef<Instruction *> IndirCalls);
199 bool InjectCoverage(Function &F, ArrayRef<BasicBlock *> AllBlocks,
200 bool IsLeafFunc = true);
201 GlobalVariable *CreateFunctionLocalArrayInSection(size_t NumElements,
202 Function &F, Type *Ty,
203 const char *Section);
204 GlobalVariable *CreatePCArray(Function &F, ArrayRef<BasicBlock *> AllBlocks);
205 void CreateFunctionLocalArrays(Function &F, ArrayRef<BasicBlock *> AllBlocks);
206 void InjectCoverageAtBlock(Function &F, BasicBlock &BB, size_t Idx,
207 bool IsLeafFunc = true);
208 // std::pair<Value *, Value *> CreateSecStartEnd(Module &M, const char
209 // *Section,
210 // Type *Ty);
211
SetNoSanitizeMetadata(Instruction * I)212 void SetNoSanitizeMetadata(Instruction *I) {
213
214 I->setMetadata(I->getModule()->getMDKindID("nosanitize"),
215 MDNode::get(*C, None));
216
217 }
218
219 std::string getSectionName(const std::string &Section) const;
220 // std::string getSectionStart(const std::string &Section) const;
221 // std::string getSectionEnd(const std::string &Section) const;
222 FunctionCallee SanCovTracePCIndir;
223 FunctionCallee SanCovTracePC /*, SanCovTracePCGuard*/;
224 Type *IntptrTy, *IntptrPtrTy, *Int64Ty, *Int64PtrTy, *Int32Ty, *Int32PtrTy,
225 *Int16Ty, *Int8Ty, *Int8PtrTy, *Int1Ty, *Int1PtrTy;
226 Module *CurModule;
227 std::string CurModuleUniqueId;
228 Triple TargetTriple;
229 LLVMContext *C;
230 const DataLayout *DL;
231
232 GlobalVariable *FunctionGuardArray; // for trace-pc-guard.
233 GlobalVariable *Function8bitCounterArray; // for inline-8bit-counters.
234 GlobalVariable *FunctionBoolArray; // for inline-bool-flag.
235 GlobalVariable *FunctionPCsArray; // for pc-table.
236 SmallVector<GlobalValue *, 20> GlobalsToAppendToUsed;
237 SmallVector<GlobalValue *, 20> GlobalsToAppendToCompilerUsed;
238
239 SanitizerCoverageOptions Options;
240
241 // AFL++ START
242 // const SpecialCaseList * Allowlist;
243 // const SpecialCaseList * Blocklist;
244 uint32_t autodictionary = 1;
245 uint32_t autodictionary_no_main = 0;
246 uint32_t inst = 0;
247 uint32_t afl_global_id = 0;
248 uint32_t unhandled = 0;
249 uint32_t select_cnt = 0;
250 uint64_t map_addr = 0;
251 const char *skip_nozero = NULL;
252 const char *use_threadsafe_counters = nullptr;
253 std::vector<BasicBlock *> BlockList;
254 DenseMap<Value *, std::string *> valueMap;
255 std::vector<std::string> dictionary;
256 IntegerType *Int8Tyi = NULL;
257 IntegerType *Int32Tyi = NULL;
258 IntegerType *Int64Tyi = NULL;
259 ConstantInt *Zero = NULL;
260 ConstantInt *One = NULL;
261 LLVMContext *Ct = NULL;
262 Module *Mo = NULL;
263 GlobalVariable *AFLMapPtr = NULL;
264 Value *MapPtrFixed = NULL;
265 std::ofstream dFile;
266 size_t found = 0;
267 // AFL++ END
268
269 };
270
271 class ModuleSanitizerCoverageLTOLegacyPass : public ModulePass {
272
273 public:
274 static char ID;
getPassName() const275 StringRef getPassName() const override {
276
277 return "sancov-lto";
278
279 }
280
getAnalysisUsage(AnalysisUsage & AU) const281 void getAnalysisUsage(AnalysisUsage &AU) const override {
282
283 AU.addRequired<DominatorTreeWrapperPass>();
284 AU.addRequired<PostDominatorTreeWrapperPass>();
285
286 }
287
ModuleSanitizerCoverageLTOLegacyPass(const SanitizerCoverageOptions & Options=SanitizerCoverageOptions ())288 ModuleSanitizerCoverageLTOLegacyPass(
289 const SanitizerCoverageOptions &Options = SanitizerCoverageOptions())
290 : ModulePass(ID), Options(Options) {
291
292 initializeModuleSanitizerCoverageLTOLegacyPassPass(
293 *PassRegistry::getPassRegistry());
294
295 }
296
runOnModule(Module & M)297 bool runOnModule(Module &M) override {
298
299 ModuleSanitizerCoverageLTO ModuleSancov(Options);
300 auto DTCallback = [this](Function &F) -> const DominatorTree * {
301
302 return &this->getAnalysis<DominatorTreeWrapperPass>(F).getDomTree();
303
304 };
305
306 auto PDTCallback = [this](Function &F) -> const PostDominatorTree * {
307
308 return &this->getAnalysis<PostDominatorTreeWrapperPass>(F)
309 .getPostDomTree();
310
311 };
312
313 return ModuleSancov.instrumentModule(M, DTCallback, PDTCallback);
314
315 }
316
317 private:
318 SanitizerCoverageOptions Options;
319
320 };
321
322 } // namespace
323
324 extern "C" ::llvm::PassPluginLibraryInfo LLVM_ATTRIBUTE_WEAK
llvmGetPassPluginInfo()325 llvmGetPassPluginInfo() {
326
327 return {LLVM_PLUGIN_API_VERSION, "SanitizerCoverageLTO", "v0.1",
328 /* lambda to insert our pass into the pass pipeline. */
329 [](PassBuilder &PB) {
330
331 #if LLVM_VERSION_MAJOR <= 13
332 using OptimizationLevel = typename PassBuilder::OptimizationLevel;
333 #endif
334 #if LLVM_VERSION_MAJOR >= 15
335 PB.registerFullLinkTimeOptimizationLastEPCallback(
336 #else
337 PB.registerOptimizerLastEPCallback(
338 #endif
339 [](ModulePassManager &MPM, OptimizationLevel OL) {
340
341 MPM.addPass(ModuleSanitizerCoverageLTO());
342
343 });
344
345 }};
346
347 }
348
run(Module & M,ModuleAnalysisManager & MAM)349 PreservedAnalyses ModuleSanitizerCoverageLTO::run(Module &M,
350 ModuleAnalysisManager &MAM) {
351
352 ModuleSanitizerCoverageLTO ModuleSancov(Options);
353 auto &FAM = MAM.getResult<FunctionAnalysisManagerModuleProxy>(M).getManager();
354 auto DTCallback = [&FAM](Function &F) -> const DominatorTree *{
355
356 return &FAM.getResult<DominatorTreeAnalysis>(F);
357
358 };
359
360 auto PDTCallback = [&FAM](Function &F) -> const PostDominatorTree * {
361
362 return &FAM.getResult<PostDominatorTreeAnalysis>(F);
363
364 };
365
366 if (ModuleSancov.instrumentModule(M, DTCallback, PDTCallback))
367 return PreservedAnalyses::none();
368
369 return PreservedAnalyses::all();
370
371 }
372
instrumentModule(Module & M,DomTreeCallback DTCallback,PostDomTreeCallback PDTCallback)373 bool ModuleSanitizerCoverageLTO::instrumentModule(
374 Module &M, DomTreeCallback DTCallback, PostDomTreeCallback PDTCallback) {
375
376 if (Options.CoverageType == SanitizerCoverageOptions::SCK_None) return false;
377 /*
378 if (Allowlist &&
379 !Allowlist->inSection("coverage", "src", MNAME))
380 return false;
381 if (Blocklist &&
382 Blocklist->inSection("coverage", "src", MNAME))
383 return false;
384 */
385 BlockList.clear();
386 valueMap.clear();
387 dictionary.clear();
388 C = &(M.getContext());
389 DL = &M.getDataLayout();
390 CurModule = &M;
391 CurModuleUniqueId = getUniqueModuleId(CurModule);
392 TargetTriple = Triple(M.getTargetTriple());
393 FunctionGuardArray = nullptr;
394 Function8bitCounterArray = nullptr;
395 FunctionBoolArray = nullptr;
396 FunctionPCsArray = nullptr;
397 IntptrTy = Type::getIntNTy(*C, DL->getPointerSizeInBits());
398 IntptrPtrTy = PointerType::getUnqual(IntptrTy);
399 Type *VoidTy = Type::getVoidTy(*C);
400 IRBuilder<> IRB(*C);
401 Int64PtrTy = PointerType::getUnqual(IRB.getInt64Ty());
402 Int32PtrTy = PointerType::getUnqual(IRB.getInt32Ty());
403 Int8PtrTy = PointerType::getUnqual(IRB.getInt8Ty());
404 Int1PtrTy = PointerType::getUnqual(IRB.getInt1Ty());
405 Int64Ty = IRB.getInt64Ty();
406 Int32Ty = IRB.getInt32Ty();
407 Int16Ty = IRB.getInt16Ty();
408 Int8Ty = IRB.getInt8Ty();
409 Int1Ty = IRB.getInt1Ty();
410
411 /* AFL++ START */
412 char *ptr;
413 LLVMContext &Ctx = M.getContext();
414 Ct = &Ctx;
415 Int8Tyi = IntegerType::getInt8Ty(Ctx);
416 Int32Tyi = IntegerType::getInt32Ty(Ctx);
417 Int64Tyi = IntegerType::getInt64Ty(Ctx);
418
419 /* Show a banner */
420 setvbuf(stdout, NULL, _IONBF, 0);
421 if (getenv("AFL_DEBUG")) { debug = 1; }
422 if (getenv("AFL_LLVM_DICT2FILE_NO_MAIN")) { autodictionary_no_main = 1; }
423
424 if ((isatty(2) && !getenv("AFL_QUIET")) || debug) {
425
426 SAYF(cCYA "afl-llvm-lto" VERSION cRST
427 " by Marc \"vanHauser\" Heuse <[email protected]>\n");
428
429 } else
430
431 be_quiet = 1;
432
433 skip_nozero = getenv("AFL_LLVM_SKIP_NEVERZERO");
434 use_threadsafe_counters = getenv("AFL_LLVM_THREADSAFE_INST");
435
436 if ((ptr = getenv("AFL_LLVM_LTO_STARTID")) != NULL)
437 if ((afl_global_id = atoi(ptr)) < 0)
438 FATAL("AFL_LLVM_LTO_STARTID value of \"%s\" is negative\n", ptr);
439
440 if (afl_global_id < 4) { afl_global_id = 4; }
441
442 if ((ptr = getenv("AFL_LLVM_DOCUMENT_IDS")) != NULL) {
443
444 dFile.open(ptr, std::ofstream::out | std::ofstream::app);
445 if (dFile.is_open()) WARNF("Cannot access document file %s", ptr);
446
447 }
448
449 // we make this the default as the fixed map has problems with
450 // defered forkserver, early constructors, ifuncs and maybe more
451 /*if (getenv("AFL_LLVM_MAP_DYNAMIC"))*/
452 map_addr = 0;
453
454 if ((ptr = getenv("AFL_LLVM_MAP_ADDR"))) {
455
456 uint64_t val;
457 if (!*ptr || !strcmp(ptr, "0") || !strcmp(ptr, "0x0")) {
458
459 map_addr = 0;
460
461 } else if (getenv("AFL_LLVM_MAP_DYNAMIC")) {
462
463 FATAL(
464 "AFL_LLVM_MAP_ADDR and AFL_LLVM_MAP_DYNAMIC cannot be used together");
465
466 } else if (strncmp(ptr, "0x", 2) != 0) {
467
468 map_addr = 0x10000; // the default
469
470 } else {
471
472 val = strtoull(ptr, NULL, 16);
473 if (val < 0x100 || val > 0xffffffff00000000) {
474
475 FATAL(
476 "AFL_LLVM_MAP_ADDR must be a value between 0x100 and "
477 "0xffffffff00000000");
478
479 }
480
481 map_addr = val;
482
483 }
484
485 }
486
487 /* Get/set the globals for the SHM region. */
488
489 if (!map_addr) {
490
491 AFLMapPtr =
492 new GlobalVariable(M, PointerType::get(Int8Tyi, 0), false,
493 GlobalValue::ExternalLinkage, 0, "__afl_area_ptr");
494
495 } else {
496
497 ConstantInt *MapAddr = ConstantInt::get(Int64Tyi, map_addr);
498 MapPtrFixed =
499 ConstantExpr::getIntToPtr(MapAddr, PointerType::getUnqual(Int8Tyi));
500
501 }
502
503 Zero = ConstantInt::get(Int8Tyi, 0);
504 One = ConstantInt::get(Int8Tyi, 1);
505
506 initInstrumentList();
507 scanForDangerousFunctions(&M);
508 Mo = &M;
509
510 if (autodictionary) {
511
512 for (auto &F : M) {
513
514 if (!isInInstrumentList(&F, MNAME) || !F.size()) { continue; }
515
516 if (autodictionary_no_main &&
517 (!F.getName().compare("main") || !F.getName().compare("_main"))) {
518
519 continue;
520
521 }
522
523 for (auto &BB : F) {
524
525 for (auto &IN : BB) {
526
527 CallInst *callInst = nullptr;
528 CmpInst *cmpInst = nullptr;
529
530 if ((cmpInst = dyn_cast<CmpInst>(&IN))) {
531
532 Value *op = cmpInst->getOperand(1);
533 ConstantInt *ilen = dyn_cast<ConstantInt>(op);
534
535 if (ilen && ilen->uge(0xffffffffffffffff) == false) {
536
537 u64 val2 = 0, val = ilen->getZExtValue();
538 u32 len = 0;
539 if (val > 0x10000 && val < 0xffffffff) len = 4;
540 if (val > 0x100000001 && val < 0xffffffffffffffff) len = 8;
541
542 if (len) {
543
544 auto c = cmpInst->getPredicate();
545
546 switch (c) {
547
548 case CmpInst::FCMP_OGT: // fall through
549 case CmpInst::FCMP_OLE: // fall through
550 case CmpInst::ICMP_SLE: // fall through
551 case CmpInst::ICMP_SGT:
552
553 // signed comparison and it is a negative constant
554 if ((len == 4 && (val & 80000000)) ||
555 (len == 8 && (val & 8000000000000000))) {
556
557 if ((val & 0xffff) != 1) val2 = val - 1;
558 break;
559
560 }
561
562 // fall through
563
564 case CmpInst::FCMP_UGT: // fall through
565 case CmpInst::FCMP_ULE: // fall through
566 case CmpInst::ICMP_UGT: // fall through
567 case CmpInst::ICMP_ULE:
568 if ((val & 0xffff) != 0xfffe) val2 = val + 1;
569 break;
570
571 case CmpInst::FCMP_OLT: // fall through
572 case CmpInst::FCMP_OGE: // fall through
573 case CmpInst::ICMP_SLT: // fall through
574 case CmpInst::ICMP_SGE:
575
576 // signed comparison and it is a negative constant
577 if ((len == 4 && (val & 80000000)) ||
578 (len == 8 && (val & 8000000000000000))) {
579
580 if ((val & 0xffff) != 1) val2 = val - 1;
581 break;
582
583 }
584
585 // fall through
586
587 case CmpInst::FCMP_ULT: // fall through
588 case CmpInst::FCMP_UGE: // fall through
589 case CmpInst::ICMP_ULT: // fall through
590 case CmpInst::ICMP_UGE:
591 if ((val & 0xffff) != 1) val2 = val - 1;
592 break;
593
594 default:
595 val2 = 0;
596
597 }
598
599 dictionary.push_back(std::string((char *)&val, len));
600 found++;
601
602 if (val2) {
603
604 dictionary.push_back(std::string((char *)&val2, len));
605 found++;
606
607 }
608
609 }
610
611 }
612
613 }
614
615 if ((callInst = dyn_cast<CallInst>(&IN))) {
616
617 bool isStrcmp = true;
618 bool isMemcmp = true;
619 bool isStrncmp = true;
620 bool isStrcasecmp = true;
621 bool isStrncasecmp = true;
622 bool isIntMemcpy = true;
623 bool isStdString = true;
624 size_t optLen = 0;
625
626 Function *Callee = callInst->getCalledFunction();
627 if (!Callee) continue;
628 if (callInst->getCallingConv() != llvm::CallingConv::C) continue;
629 std::string FuncName = Callee->getName().str();
630
631 isStrcmp &= (!FuncName.compare("strcmp") ||
632 !FuncName.compare("xmlStrcmp") ||
633 !FuncName.compare("xmlStrEqual") ||
634 !FuncName.compare("g_strcmp0") ||
635 !FuncName.compare("curl_strequal") ||
636 !FuncName.compare("strcsequal"));
637 isMemcmp &=
638 (!FuncName.compare("memcmp") || !FuncName.compare("bcmp") ||
639 !FuncName.compare("CRYPTO_memcmp") ||
640 !FuncName.compare("OPENSSL_memcmp") ||
641 !FuncName.compare("memcmp_const_time") ||
642 !FuncName.compare("memcmpct"));
643 isStrncmp &= (!FuncName.compare("strncmp") ||
644 !FuncName.compare("xmlStrncmp") ||
645 !FuncName.compare("curl_strnequal"));
646 isStrcasecmp &= (!FuncName.compare("strcasecmp") ||
647 !FuncName.compare("stricmp") ||
648 !FuncName.compare("ap_cstr_casecmp") ||
649 !FuncName.compare("OPENSSL_strcasecmp") ||
650 !FuncName.compare("xmlStrcasecmp") ||
651 !FuncName.compare("g_strcasecmp") ||
652 !FuncName.compare("g_ascii_strcasecmp") ||
653 !FuncName.compare("Curl_strcasecompare") ||
654 !FuncName.compare("Curl_safe_strcasecompare") ||
655 !FuncName.compare("cmsstrcasecmp"));
656 isStrncasecmp &= (!FuncName.compare("strncasecmp") ||
657 !FuncName.compare("strnicmp") ||
658 !FuncName.compare("ap_cstr_casecmpn") ||
659 !FuncName.compare("OPENSSL_strncasecmp") ||
660 !FuncName.compare("xmlStrncasecmp") ||
661 !FuncName.compare("g_ascii_strncasecmp") ||
662 !FuncName.compare("Curl_strncasecompare") ||
663 !FuncName.compare("g_strncasecmp"));
664
665 isIntMemcpy &= !FuncName.compare("llvm.memcpy.p0i8.p0i8.i64");
666 isStdString &=
667 ((FuncName.find("basic_string") != std::string::npos &&
668 FuncName.find("compare") != std::string::npos) ||
669 (FuncName.find("basic_string") != std::string::npos &&
670 FuncName.find("find") != std::string::npos));
671
672 /* we do something different here, putting this BB and the
673 successors in a block map */
674 if (!FuncName.compare("__afl_persistent_loop")) {
675
676 BlockList.push_back(&BB);
677 for (succ_iterator SI = succ_begin(&BB), SE = succ_end(&BB);
678 SI != SE; ++SI) {
679
680 BasicBlock *succ = *SI;
681 BlockList.push_back(succ);
682
683 }
684
685 }
686
687 if (!isStrcmp && !isMemcmp && !isStrncmp && !isStrcasecmp &&
688 !isStrncasecmp && !isIntMemcpy && !isStdString)
689 continue;
690
691 /* Verify the strcmp/memcmp/strncmp/strcasecmp/strncasecmp function
692 * prototype */
693 FunctionType *FT = Callee->getFunctionType();
694
695 isStrcmp &=
696 FT->getNumParams() == 2 &&
697 FT->getReturnType()->isIntegerTy(32) &&
698 FT->getParamType(0) == FT->getParamType(1) &&
699 FT->getParamType(0) ==
700 IntegerType::getInt8Ty(M.getContext())->getPointerTo(0);
701 isStrcasecmp &=
702 FT->getNumParams() == 2 &&
703 FT->getReturnType()->isIntegerTy(32) &&
704 FT->getParamType(0) == FT->getParamType(1) &&
705 FT->getParamType(0) ==
706 IntegerType::getInt8Ty(M.getContext())->getPointerTo(0);
707 isMemcmp &= FT->getNumParams() == 3 &&
708 FT->getReturnType()->isIntegerTy(32) &&
709 FT->getParamType(0)->isPointerTy() &&
710 FT->getParamType(1)->isPointerTy() &&
711 FT->getParamType(2)->isIntegerTy();
712 isStrncmp &=
713 FT->getNumParams() == 3 &&
714 FT->getReturnType()->isIntegerTy(32) &&
715 FT->getParamType(0) == FT->getParamType(1) &&
716 FT->getParamType(0) ==
717 IntegerType::getInt8Ty(M.getContext())->getPointerTo(0) &&
718 FT->getParamType(2)->isIntegerTy();
719 isStrncasecmp &=
720 FT->getNumParams() == 3 &&
721 FT->getReturnType()->isIntegerTy(32) &&
722 FT->getParamType(0) == FT->getParamType(1) &&
723 FT->getParamType(0) ==
724 IntegerType::getInt8Ty(M.getContext())->getPointerTo(0) &&
725 FT->getParamType(2)->isIntegerTy();
726 isStdString &= FT->getNumParams() >= 2 &&
727 FT->getParamType(0)->isPointerTy() &&
728 FT->getParamType(1)->isPointerTy();
729
730 if (!isStrcmp && !isMemcmp && !isStrncmp && !isStrcasecmp &&
731 !isStrncasecmp && !isIntMemcpy && !isStdString)
732 continue;
733
734 /* is a str{n,}{case,}cmp/memcmp, check if we have
735 * str{case,}cmp(x, "const") or str{case,}cmp("const", x)
736 * strn{case,}cmp(x, "const", ..) or strn{case,}cmp("const", x, ..)
737 * memcmp(x, "const", ..) or memcmp("const", x, ..) */
738 Value *Str1P = callInst->getArgOperand(0),
739 *Str2P = callInst->getArgOperand(1);
740 std::string Str1, Str2;
741 StringRef TmpStr;
742 bool HasStr1 = getConstantStringInfo(Str1P, TmpStr);
743 if (TmpStr.empty())
744 HasStr1 = false;
745 else
746 Str1 = TmpStr.str();
747 bool HasStr2 = getConstantStringInfo(Str2P, TmpStr);
748 if (TmpStr.empty())
749 HasStr2 = false;
750 else
751 Str2 = TmpStr.str();
752
753 if (debug)
754 fprintf(stderr, "F:%s %p(%s)->\"%s\"(%s) %p(%s)->\"%s\"(%s)\n",
755 FuncName.c_str(), Str1P, Str1P->getName().str().c_str(),
756 Str1.c_str(), HasStr1 == true ? "true" : "false", Str2P,
757 Str2P->getName().str().c_str(), Str2.c_str(),
758 HasStr2 == true ? "true" : "false");
759
760 // we handle the 2nd parameter first because of llvm memcpy
761 if (!HasStr2) {
762
763 auto *Ptr = dyn_cast<ConstantExpr>(Str2P);
764 if (Ptr && Ptr->getOpcode() == Instruction::GetElementPtr) {
765
766 if (auto *Var = dyn_cast<GlobalVariable>(Ptr->getOperand(0))) {
767
768 if (Var->hasInitializer()) {
769
770 if (auto *Array = dyn_cast<ConstantDataArray>(
771 Var->getInitializer())) {
772
773 HasStr2 = true;
774 Str2 = Array->getRawDataValues().str();
775
776 }
777
778 }
779
780 }
781
782 }
783
784 }
785
786 // for the internal memcpy routine we only care for the second
787 // parameter and are not reporting anything.
788 if (isIntMemcpy == true) {
789
790 if (HasStr2 == true) {
791
792 Value *op2 = callInst->getArgOperand(2);
793 ConstantInt *ilen = dyn_cast<ConstantInt>(op2);
794 if (ilen) {
795
796 uint64_t literalLength = Str2.size();
797 uint64_t optLength = ilen->getZExtValue();
798 if (optLength > literalLength + 1) {
799
800 optLength = Str2.length() + 1;
801
802 }
803
804 if (literalLength + 1 == optLength) {
805
806 Str2.append("\0", 1); // add null byte
807
808 }
809
810 }
811
812 valueMap[Str1P] = new std::string(Str2);
813
814 if (debug)
815 fprintf(stderr, "Saved: %s for %p\n", Str2.c_str(), Str1P);
816 continue;
817
818 }
819
820 continue;
821
822 }
823
824 // Neither a literal nor a global variable?
825 // maybe it is a local variable that we saved
826 if (!HasStr2) {
827
828 std::string *strng = valueMap[Str2P];
829 if (strng && !strng->empty()) {
830
831 Str2 = *strng;
832 HasStr2 = true;
833 if (debug)
834 fprintf(stderr, "Filled2: %s for %p\n", strng->c_str(),
835 Str2P);
836
837 }
838
839 }
840
841 if (!HasStr1) {
842
843 auto Ptr = dyn_cast<ConstantExpr>(Str1P);
844
845 if (Ptr && Ptr->getOpcode() == Instruction::GetElementPtr) {
846
847 if (auto *Var = dyn_cast<GlobalVariable>(Ptr->getOperand(0))) {
848
849 if (Var->hasInitializer()) {
850
851 if (auto *Array = dyn_cast<ConstantDataArray>(
852 Var->getInitializer())) {
853
854 HasStr1 = true;
855 Str1 = Array->getRawDataValues().str();
856
857 }
858
859 }
860
861 }
862
863 }
864
865 }
866
867 // Neither a literal nor a global variable?
868 // maybe it is a local variable that we saved
869 if (!HasStr1) {
870
871 std::string *strng = valueMap[Str1P];
872 if (strng && !strng->empty()) {
873
874 Str1 = *strng;
875 HasStr1 = true;
876 if (debug)
877 fprintf(stderr, "Filled1: %s for %p\n", strng->c_str(),
878 Str1P);
879
880 }
881
882 }
883
884 /* handle cases of one string is const, one string is variable */
885 if (!(HasStr1 ^ HasStr2)) continue;
886
887 std::string thestring;
888
889 if (HasStr1)
890 thestring = Str1;
891 else
892 thestring = Str2;
893
894 optLen = thestring.length();
895 if (optLen < 2 || (optLen == 2 && !thestring[1])) { continue; }
896
897 if (isMemcmp || isStrncmp || isStrncasecmp) {
898
899 Value *op2 = callInst->getArgOperand(2);
900 ConstantInt *ilen = dyn_cast<ConstantInt>(op2);
901
902 if (ilen) {
903
904 uint64_t literalLength = optLen;
905 optLen = ilen->getZExtValue();
906 if (optLen > thestring.length() + 1) {
907
908 optLen = thestring.length() + 1;
909
910 }
911
912 if (optLen < 2) { continue; }
913 if (literalLength + 1 == optLen) { // add null byte
914
915 thestring.append("\0", 1);
916
917 }
918
919 }
920
921 }
922
923 // add null byte if this is a string compare function and a null
924 // was not already added
925 if (!isMemcmp) {
926
927 /*
928 if (addedNull == false && thestring[optLen - 1] !=
929 '\0') {
930
931 thestring.append("\0", 1); // add null byte
932 optLen++;
933
934 }
935
936 */
937 if (!isStdString &&
938 thestring.find('\0', 0) != std::string::npos) {
939
940 // ensure we do not have garbage
941 size_t offset = thestring.find('\0', 0);
942 if (offset + 1 < optLen) optLen = offset + 1;
943 thestring = thestring.substr(0, optLen);
944
945 }
946
947 }
948
949 if (!be_quiet) {
950
951 std::string outstring;
952 fprintf(stderr, "%s: length %zu/%zu \"", FuncName.c_str(), optLen,
953 thestring.length());
954 for (uint16_t i = 0; i < (uint16_t)thestring.length(); i++) {
955
956 uint8_t c = thestring[i];
957 if (c <= 32 || c >= 127)
958 fprintf(stderr, "\\x%02x", c);
959 else
960 fprintf(stderr, "%c", c);
961
962 }
963
964 fprintf(stderr, "\"\n");
965
966 }
967
968 // we take the longer string, even if the compare was to a
969 // shorter part. Note that depending on the optimizer of the
970 // compiler this can be wrong, but it is more likely that this
971 // is helping the fuzzer
972 if (optLen != thestring.length()) optLen = thestring.length();
973 if (optLen > MAX_AUTO_EXTRA) optLen = MAX_AUTO_EXTRA;
974 if (optLen < MIN_AUTO_EXTRA) // too short? skip
975 continue;
976
977 dictionary.push_back(thestring.substr(0, optLen));
978
979 }
980
981 }
982
983 }
984
985 }
986
987 }
988
989 // AFL++ END
990
991 SanCovTracePCIndir =
992 M.getOrInsertFunction(SanCovTracePCIndirName, VoidTy, IntptrTy);
993 // Make sure smaller parameters are zero-extended to i64 as required by the
994 // x86_64 ABI.
995 AttributeList SanCovTraceCmpZeroExtAL;
996 if (TargetTriple.getArch() == Triple::x86_64) {
997
998 SanCovTraceCmpZeroExtAL =
999 SanCovTraceCmpZeroExtAL.addParamAttribute(*C, 0, Attribute::ZExt);
1000 SanCovTraceCmpZeroExtAL =
1001 SanCovTraceCmpZeroExtAL.addParamAttribute(*C, 1, Attribute::ZExt);
1002
1003 }
1004
1005 SanCovTracePC = M.getOrInsertFunction(SanCovTracePCName, VoidTy);
1006
1007 // SanCovTracePCGuard =
1008 // M.getOrInsertFunction(SanCovTracePCGuardName, VoidTy, Int32PtrTy);
1009
1010 for (auto &F : M)
1011 instrumentFunction(F, DTCallback, PDTCallback);
1012
1013 // AFL++ START
1014 if (dFile.is_open()) dFile.close();
1015
1016 if (!getenv("AFL_LLVM_LTO_SKIPINIT") &&
1017 (!getenv("AFL_LLVM_LTO_DONTWRITEID") || dictionary.size() || map_addr)) {
1018
1019 // yes we could create our own function, insert it into ctors ...
1020 // but this would be a pain in the butt ... so we use afl-llvm-rt-lto.o
1021
1022 Function *f = M.getFunction("__afl_auto_init_globals");
1023
1024 if (!f) {
1025
1026 fprintf(stderr,
1027 "Error: init function could not be found (this should not "
1028 "happen)\n");
1029 exit(-1);
1030
1031 }
1032
1033 BasicBlock *bb = &f->getEntryBlock();
1034 if (!bb) {
1035
1036 fprintf(stderr,
1037 "Error: init function does not have an EntryBlock (this should "
1038 "not happen)\n");
1039 exit(-1);
1040
1041 }
1042
1043 BasicBlock::iterator IP = bb->getFirstInsertionPt();
1044 IRBuilder<> IRB(&(*IP));
1045
1046 if (map_addr) {
1047
1048 GlobalVariable *AFLMapAddrFixed = new GlobalVariable(
1049 M, Int64Tyi, true, GlobalValue::ExternalLinkage, 0, "__afl_map_addr");
1050 ConstantInt *MapAddr = ConstantInt::get(Int64Tyi, map_addr);
1051 StoreInst *StoreMapAddr = IRB.CreateStore(MapAddr, AFLMapAddrFixed);
1052 ModuleSanitizerCoverageLTO::SetNoSanitizeMetadata(StoreMapAddr);
1053
1054 }
1055
1056 if (getenv("AFL_LLVM_LTO_DONTWRITEID") == NULL) {
1057
1058 uint32_t write_loc = afl_global_id;
1059
1060 write_loc = (((afl_global_id + 8) >> 3) << 3);
1061
1062 GlobalVariable *AFLFinalLoc =
1063 new GlobalVariable(M, Int32Tyi, true, GlobalValue::ExternalLinkage, 0,
1064 "__afl_final_loc");
1065 ConstantInt *const_loc = ConstantInt::get(Int32Tyi, write_loc);
1066 StoreInst *StoreFinalLoc = IRB.CreateStore(const_loc, AFLFinalLoc);
1067 ModuleSanitizerCoverageLTO::SetNoSanitizeMetadata(StoreFinalLoc);
1068
1069 }
1070
1071 if (dictionary.size()) {
1072
1073 size_t memlen = 0, count = 0, offset = 0;
1074
1075 // sort and unique the dictionary
1076 std::sort(dictionary.begin(), dictionary.end());
1077 auto last = std::unique(dictionary.begin(), dictionary.end());
1078 dictionary.erase(last, dictionary.end());
1079
1080 for (auto token : dictionary) {
1081
1082 memlen += token.length();
1083 count++;
1084
1085 }
1086
1087 if (!be_quiet)
1088 printf("AUTODICTIONARY: %zu string%s found\n", count,
1089 count == 1 ? "" : "s");
1090
1091 if (count) {
1092
1093 auto ptrhld = std::unique_ptr<char[]>(new char[memlen + count]);
1094
1095 count = 0;
1096
1097 for (auto token : dictionary) {
1098
1099 if (offset + token.length() < 0xfffff0 && count < MAX_AUTO_EXTRAS) {
1100
1101 ptrhld.get()[offset++] = (uint8_t)token.length();
1102 memcpy(ptrhld.get() + offset, token.c_str(), token.length());
1103 offset += token.length();
1104 count++;
1105
1106 }
1107
1108 }
1109
1110 GlobalVariable *AFLDictionaryLen =
1111 new GlobalVariable(M, Int32Tyi, false, GlobalValue::ExternalLinkage,
1112 0, "__afl_dictionary_len");
1113 ConstantInt *const_len = ConstantInt::get(Int32Tyi, offset);
1114 StoreInst *StoreDictLen = IRB.CreateStore(const_len, AFLDictionaryLen);
1115 ModuleSanitizerCoverageLTO::SetNoSanitizeMetadata(StoreDictLen);
1116
1117 ArrayType *ArrayTy = ArrayType::get(IntegerType::get(Ctx, 8), offset);
1118 GlobalVariable *AFLInternalDictionary = new GlobalVariable(
1119 M, ArrayTy, true, GlobalValue::ExternalLinkage,
1120 ConstantDataArray::get(Ctx,
1121 *(new ArrayRef<char>(ptrhld.get(), offset))),
1122 "__afl_internal_dictionary");
1123 AFLInternalDictionary->setInitializer(ConstantDataArray::get(
1124 Ctx, *(new ArrayRef<char>(ptrhld.get(), offset))));
1125 AFLInternalDictionary->setConstant(true);
1126
1127 GlobalVariable *AFLDictionary = new GlobalVariable(
1128 M, PointerType::get(Int8Tyi, 0), false,
1129 GlobalValue::ExternalLinkage, 0, "__afl_dictionary");
1130
1131 Value *AFLDictOff = IRB.CreateGEP(Int8Ty, AFLInternalDictionary, Zero);
1132 Value *AFLDictPtr =
1133 IRB.CreatePointerCast(AFLDictOff, PointerType::get(Int8Tyi, 0));
1134 StoreInst *StoreDict = IRB.CreateStore(AFLDictPtr, AFLDictionary);
1135 ModuleSanitizerCoverageLTO::SetNoSanitizeMetadata(StoreDict);
1136
1137 }
1138
1139 }
1140
1141 }
1142
1143 /* Say something nice. */
1144
1145 if (!be_quiet) {
1146
1147 if (!inst)
1148 WARNF("No instrumentation targets found.");
1149 else {
1150
1151 char modeline[100];
1152 snprintf(modeline, sizeof(modeline), "%s%s%s%s%s%s",
1153 getenv("AFL_HARDEN") ? "hardened" : "non-hardened",
1154 getenv("AFL_USE_ASAN") ? ", ASAN" : "",
1155 getenv("AFL_USE_MSAN") ? ", MSAN" : "",
1156 getenv("AFL_USE_TSAN") ? ", TSAN" : "",
1157 getenv("AFL_USE_CFISAN") ? ", CFISAN" : "",
1158 getenv("AFL_USE_UBSAN") ? ", UBSAN" : "");
1159 OKF("Instrumented %u locations (%u selects) without collisions (%llu "
1160 "collisions have been avoided) (%s mode).",
1161 inst, select_cnt, calculateCollisions(inst), modeline);
1162
1163 }
1164
1165 }
1166
1167 // AFL++ END
1168
1169 // We don't reference these arrays directly in any of our runtime functions,
1170 // so we need to prevent them from being dead stripped.
1171 if (TargetTriple.isOSBinFormatMachO()) appendToUsed(M, GlobalsToAppendToUsed);
1172 appendToCompilerUsed(M, GlobalsToAppendToCompilerUsed);
1173 return true;
1174
1175 }
1176
1177 // True if block has successors and it dominates all of them.
isFullDominator(const BasicBlock * BB,const DominatorTree * DT)1178 static bool isFullDominator(const BasicBlock *BB, const DominatorTree *DT) {
1179
1180 if (succ_begin(BB) == succ_end(BB)) return false;
1181
1182 for (const BasicBlock *SUCC : make_range(succ_begin(BB), succ_end(BB))) {
1183
1184 if (!DT->dominates(BB, SUCC)) return false;
1185
1186 }
1187
1188 return true;
1189
1190 }
1191
1192 // True if block has predecessors and it postdominates all of them.
isFullPostDominator(const BasicBlock * BB,const PostDominatorTree * PDT)1193 static bool isFullPostDominator(const BasicBlock *BB,
1194 const PostDominatorTree *PDT) {
1195
1196 if (pred_begin(BB) == pred_end(BB)) return false;
1197
1198 for (const BasicBlock *PRED : make_range(pred_begin(BB), pred_end(BB))) {
1199
1200 if (!PDT->dominates(BB, PRED)) return false;
1201
1202 }
1203
1204 return true;
1205
1206 }
1207
shouldInstrumentBlock(const Function & F,const BasicBlock * BB,const DominatorTree * DT,const PostDominatorTree * PDT,const SanitizerCoverageOptions & Options)1208 static bool shouldInstrumentBlock(const Function &F, const BasicBlock *BB,
1209 const DominatorTree *DT,
1210 const PostDominatorTree *PDT,
1211 const SanitizerCoverageOptions &Options) {
1212
1213 // Don't insert coverage for blocks containing nothing but unreachable: we
1214 // will never call __sanitizer_cov() for them, so counting them in
1215 // NumberOfInstrumentedBlocks() might complicate calculation of code coverage
1216 // percentage. Also, unreachable instructions frequently have no debug
1217 // locations.
1218 if (isa<UnreachableInst>(BB->getFirstNonPHIOrDbgOrLifetime())) return false;
1219
1220 // Don't insert coverage into blocks without a valid insertion point
1221 // (catchswitch blocks).
1222 if (BB->getFirstInsertionPt() == BB->end()) return false;
1223
1224 // AFL++ START
1225 if (!Options.NoPrune && &F.getEntryBlock() == BB && F.size() > 1)
1226 return false;
1227 // AFL++ END
1228
1229 if (Options.NoPrune || &F.getEntryBlock() == BB) return true;
1230
1231 if (Options.CoverageType == SanitizerCoverageOptions::SCK_Function &&
1232 &F.getEntryBlock() != BB)
1233 return false;
1234
1235 // Do not instrument full dominators, or full post-dominators with multiple
1236 // predecessors.
1237 return !isFullDominator(BB, DT) &&
1238 !(isFullPostDominator(BB, PDT) && !BB->getSinglePredecessor());
1239
1240 }
1241
instrumentFunction(Function & F,DomTreeCallback DTCallback,PostDomTreeCallback PDTCallback)1242 void ModuleSanitizerCoverageLTO::instrumentFunction(
1243 Function &F, DomTreeCallback DTCallback, PostDomTreeCallback PDTCallback) {
1244
1245 if (F.empty()) return;
1246 if (F.getName().find(".module_ctor") != std::string::npos)
1247 return; // Should not instrument sanitizer init functions.
1248 #if LLVM_VERSION_MAJOR >= 18
1249 if (F.getName().starts_with("__sanitizer_"))
1250 #else
1251 if (F.getName().startswith("__sanitizer_"))
1252 #endif
1253 return; // Don't instrument __sanitizer_* callbacks.
1254 // Don't touch available_externally functions, their actual body is elsewhere.
1255 if (F.getLinkage() == GlobalValue::AvailableExternallyLinkage) return;
1256 // Don't instrument MSVC CRT configuration helpers. They may run before normal
1257 // initialization.
1258 if (F.getName() == "__local_stdio_printf_options" ||
1259 F.getName() == "__local_stdio_scanf_options")
1260 return;
1261 if (isa<UnreachableInst>(F.getEntryBlock().getTerminator())) return;
1262 // Don't instrument functions using SEH for now. Splitting basic blocks like
1263 // we do for coverage breaks WinEHPrepare.
1264 // FIXME: Remove this when SEH no longer uses landingpad pattern matching.
1265 if (F.hasPersonalityFn() &&
1266 isAsynchronousEHPersonality(classifyEHPersonality(F.getPersonalityFn())))
1267 return;
1268 // if (Allowlist && !Allowlist->inSection("coverage", "fun", F.getName()))
1269 // return;
1270 // if (Blocklist && Blocklist->inSection("coverage", "fun", F.getName()))
1271 // return;
1272
1273 // AFL++ START
1274 if (!F.size()) return;
1275 if (!isInInstrumentList(&F, FMNAME)) return;
1276 // AFL++ END
1277
1278 if (Options.CoverageType >= SanitizerCoverageOptions::SCK_Edge)
1279 SplitAllCriticalEdges(
1280 F, CriticalEdgeSplittingOptions().setIgnoreUnreachableDests());
1281 SmallVector<Instruction *, 8> IndirCalls;
1282 SmallVector<BasicBlock *, 16> BlocksToInstrument;
1283
1284 const DominatorTree *DT = DTCallback(F);
1285 const PostDominatorTree *PDT = PDTCallback(F);
1286 bool IsLeafFunc = true;
1287 uint32_t skip_next = 0;
1288
1289 for (auto &BB : F) {
1290
1291 for (auto &IN : BB) {
1292
1293 CallInst *callInst = nullptr;
1294
1295 if ((callInst = dyn_cast<CallInst>(&IN))) {
1296
1297 Function *Callee = callInst->getCalledFunction();
1298 if (!Callee) continue;
1299 if (callInst->getCallingConv() != llvm::CallingConv::C) continue;
1300 StringRef FuncName = Callee->getName();
1301 if (!FuncName.compare(StringRef("dlopen")) ||
1302 !FuncName.compare(StringRef("_dlopen"))) {
1303
1304 fprintf(stderr,
1305 "WARNING: dlopen() detected. To have coverage for a library "
1306 "that your target dlopen()'s this must either happen before "
1307 "__AFL_INIT() or you must use AFL_PRELOAD to preload all "
1308 "dlopen()'ed libraries!\n");
1309 continue;
1310
1311 }
1312
1313 if (FuncName.compare(StringRef("__afl_coverage_interesting"))) continue;
1314
1315 Value *val = ConstantInt::get(Int32Ty, ++afl_global_id);
1316 callInst->setOperand(1, val);
1317 ++inst;
1318
1319 }
1320
1321 SelectInst *selectInst = nullptr;
1322
1323 /*
1324 std::string errMsg;
1325 raw_string_ostream os(errMsg);
1326 IN.print(os);
1327 fprintf(stderr, "X(%u): %s\n", skip_next, os.str().c_str());
1328 */
1329 if (!skip_next && (selectInst = dyn_cast<SelectInst>(&IN))) {
1330
1331 uint32_t vector_cnt = 0;
1332 Value *condition = selectInst->getCondition();
1333 Value *result;
1334 auto t = condition->getType();
1335 IRBuilder<> IRB(selectInst->getNextNode());
1336
1337 ++select_cnt;
1338
1339 if (t->getTypeID() == llvm::Type::IntegerTyID) {
1340
1341 Value *val1 = ConstantInt::get(Int32Ty, ++afl_global_id);
1342 Value *val2 = ConstantInt::get(Int32Ty, ++afl_global_id);
1343 result = IRB.CreateSelect(condition, val1, val2);
1344 skip_next = 1;
1345 inst += 2;
1346
1347 } else
1348
1349 #if LLVM_VERSION_MAJOR >= 14
1350 if (t->getTypeID() == llvm::Type::FixedVectorTyID) {
1351
1352 FixedVectorType *tt = dyn_cast<FixedVectorType>(t);
1353 if (tt) {
1354
1355 uint32_t elements = tt->getElementCount().getFixedValue();
1356 vector_cnt = elements;
1357 inst += vector_cnt * 2;
1358 if (elements) {
1359
1360 FixedVectorType *GuardPtr1 =
1361 FixedVectorType::get(Int32Ty, elements);
1362 FixedVectorType *GuardPtr2 =
1363 FixedVectorType::get(Int32Ty, elements);
1364 Value *x, *y;
1365
1366 Value *val1 = ConstantInt::get(Int32Ty, ++afl_global_id);
1367 Value *val2 = ConstantInt::get(Int32Ty, ++afl_global_id);
1368 x = IRB.CreateInsertElement(GuardPtr1, val1, (uint64_t)0);
1369 y = IRB.CreateInsertElement(GuardPtr2, val2, (uint64_t)0);
1370
1371 for (uint64_t i = 1; i < elements; i++) {
1372
1373 val1 = ConstantInt::get(Int32Ty, ++afl_global_id);
1374 val2 = ConstantInt::get(Int32Ty, ++afl_global_id);
1375 x = IRB.CreateInsertElement(GuardPtr1, val1, i);
1376 y = IRB.CreateInsertElement(GuardPtr2, val2, i);
1377
1378 }
1379
1380 result = IRB.CreateSelect(condition, x, y);
1381 skip_next = 1;
1382
1383 }
1384
1385 }
1386
1387 } else
1388
1389 #endif
1390 {
1391
1392 unhandled++;
1393 continue;
1394
1395 }
1396
1397 uint32_t vector_cur = 0;
1398 /* Load SHM pointer */
1399 LoadInst *MapPtr =
1400 IRB.CreateLoad(PointerType::get(Int8Ty, 0), AFLMapPtr);
1401 ModuleSanitizerCoverageLTO::SetNoSanitizeMetadata(MapPtr);
1402
1403 while (1) {
1404
1405 /* Get CurLoc */
1406 Value *MapPtrIdx = nullptr;
1407
1408 /* Load counter for CurLoc */
1409 if (!vector_cnt) {
1410
1411 MapPtrIdx = IRB.CreateGEP(Int8Ty, MapPtr, result);
1412
1413 } else {
1414
1415 auto element = IRB.CreateExtractElement(result, vector_cur++);
1416 MapPtrIdx = IRB.CreateGEP(Int8Ty, MapPtr, element);
1417
1418 }
1419
1420 if (use_threadsafe_counters) {
1421
1422 IRB.CreateAtomicRMW(llvm::AtomicRMWInst::BinOp::Add, MapPtrIdx, One,
1423 #if LLVM_VERSION_MAJOR >= 13
1424 llvm::MaybeAlign(1),
1425 #endif
1426 llvm::AtomicOrdering::Monotonic);
1427
1428 } else {
1429
1430 LoadInst *Counter = IRB.CreateLoad(IRB.getInt8Ty(), MapPtrIdx);
1431 ModuleSanitizerCoverageLTO::SetNoSanitizeMetadata(Counter);
1432
1433 /* Update bitmap */
1434
1435 Value *Incr = IRB.CreateAdd(Counter, One);
1436
1437 if (skip_nozero == NULL) {
1438
1439 auto cf = IRB.CreateICmpEQ(Incr, Zero);
1440 auto carry = IRB.CreateZExt(cf, Int8Ty);
1441 Incr = IRB.CreateAdd(Incr, carry);
1442
1443 }
1444
1445 auto nosan = IRB.CreateStore(Incr, MapPtrIdx);
1446 ModuleSanitizerCoverageLTO::SetNoSanitizeMetadata(nosan);
1447
1448 }
1449
1450 if (!vector_cnt || vector_cnt == vector_cur) { break; }
1451
1452 }
1453
1454 skip_next = 1;
1455
1456 } else {
1457
1458 skip_next = 0;
1459
1460 }
1461
1462 }
1463
1464 if (shouldInstrumentBlock(F, &BB, DT, PDT, Options))
1465 BlocksToInstrument.push_back(&BB);
1466 for (auto &Inst : BB) {
1467
1468 if (Options.IndirectCalls) {
1469
1470 CallBase *CB = dyn_cast<CallBase>(&Inst);
1471 if (CB && !CB->getCalledFunction()) IndirCalls.push_back(&Inst);
1472
1473 }
1474
1475 }
1476
1477 }
1478
1479 InjectCoverage(F, BlocksToInstrument, IsLeafFunc);
1480 InjectCoverageForIndirectCalls(F, IndirCalls);
1481
1482 }
1483
CreateFunctionLocalArrayInSection(size_t NumElements,Function & F,Type * Ty,const char * Section)1484 GlobalVariable *ModuleSanitizerCoverageLTO::CreateFunctionLocalArrayInSection(
1485 size_t NumElements, Function &F, Type *Ty, const char *Section) {
1486
1487 ArrayType *ArrayTy = ArrayType::get(Ty, NumElements);
1488 auto Array = new GlobalVariable(
1489 *CurModule, ArrayTy, false, GlobalVariable::PrivateLinkage,
1490 Constant::getNullValue(ArrayTy), "__sancov_gen_");
1491
1492 #if LLVM_VERSION_MAJOR >= 13
1493 if (TargetTriple.supportsCOMDAT() &&
1494 (TargetTriple.isOSBinFormatELF() || !F.isInterposable()))
1495 if (auto Comdat = getOrCreateFunctionComdat(F, TargetTriple))
1496 Array->setComdat(Comdat);
1497 #else
1498 if (TargetTriple.supportsCOMDAT() && !F.isInterposable())
1499 if (auto Comdat =
1500 GetOrCreateFunctionComdat(F, TargetTriple, CurModuleUniqueId))
1501 Array->setComdat(Comdat);
1502 #endif
1503 Array->setSection(getSectionName(Section));
1504 Array->setAlignment(Align(DL->getTypeStoreSize(Ty).getFixedValue()));
1505 GlobalsToAppendToUsed.push_back(Array);
1506 GlobalsToAppendToCompilerUsed.push_back(Array);
1507 MDNode *MD = MDNode::get(F.getContext(), ValueAsMetadata::get(&F));
1508 Array->addMetadata(LLVMContext::MD_associated, *MD);
1509
1510 return Array;
1511
1512 }
1513
CreatePCArray(Function & F,ArrayRef<BasicBlock * > AllBlocks)1514 GlobalVariable *ModuleSanitizerCoverageLTO::CreatePCArray(
1515 Function &F, ArrayRef<BasicBlock *> AllBlocks) {
1516
1517 size_t N = AllBlocks.size();
1518 assert(N);
1519 SmallVector<Constant *, 32> PCs;
1520 IRBuilder<> IRB(&*F.getEntryBlock().getFirstInsertionPt());
1521 for (size_t i = 0; i < N; i++) {
1522
1523 if (&F.getEntryBlock() == AllBlocks[i]) {
1524
1525 PCs.push_back((Constant *)IRB.CreatePointerCast(&F, IntptrPtrTy));
1526 PCs.push_back((Constant *)IRB.CreateIntToPtr(
1527 ConstantInt::get(IntptrTy, 1), IntptrPtrTy));
1528
1529 } else {
1530
1531 PCs.push_back((Constant *)IRB.CreatePointerCast(
1532 BlockAddress::get(AllBlocks[i]), IntptrPtrTy));
1533 PCs.push_back((Constant *)IRB.CreateIntToPtr(
1534 ConstantInt::get(IntptrTy, 0), IntptrPtrTy));
1535
1536 }
1537
1538 }
1539
1540 auto *PCArray = CreateFunctionLocalArrayInSection(N * 2, F, IntptrPtrTy,
1541 SanCovPCsSectionName);
1542 PCArray->setInitializer(
1543 ConstantArray::get(ArrayType::get(IntptrPtrTy, N * 2), PCs));
1544 PCArray->setConstant(true);
1545
1546 return PCArray;
1547
1548 }
1549
CreateFunctionLocalArrays(Function & F,ArrayRef<BasicBlock * > AllBlocks)1550 void ModuleSanitizerCoverageLTO::CreateFunctionLocalArrays(
1551 Function &F, ArrayRef<BasicBlock *> AllBlocks) {
1552
1553 if (Options.TracePCGuard)
1554 FunctionGuardArray = CreateFunctionLocalArrayInSection(
1555 AllBlocks.size(), F, Int32Ty, SanCovGuardsSectionName);
1556 if (Options.Inline8bitCounters)
1557 Function8bitCounterArray = CreateFunctionLocalArrayInSection(
1558 AllBlocks.size(), F, Int8Ty, SanCovCountersSectionName);
1559 if (Options.InlineBoolFlag)
1560 FunctionBoolArray = CreateFunctionLocalArrayInSection(
1561 AllBlocks.size(), F, Int1Ty, SanCovBoolFlagSectionName);
1562 if (Options.PCTable) FunctionPCsArray = CreatePCArray(F, AllBlocks);
1563
1564 }
1565
InjectCoverage(Function & F,ArrayRef<BasicBlock * > AllBlocks,bool IsLeafFunc)1566 bool ModuleSanitizerCoverageLTO::InjectCoverage(
1567 Function &F, ArrayRef<BasicBlock *> AllBlocks, bool IsLeafFunc) {
1568
1569 if (AllBlocks.empty()) return false;
1570 CreateFunctionLocalArrays(F, AllBlocks);
1571
1572 for (size_t i = 0, N = AllBlocks.size(); i < N; i++) {
1573
1574 // AFL++ START
1575 if (BlockList.size()) {
1576
1577 int skip = 0;
1578 for (uint32_t k = 0; k < BlockList.size(); k++) {
1579
1580 if (AllBlocks[i] == BlockList[k]) {
1581
1582 if (debug)
1583 fprintf(stderr,
1584 "DEBUG: Function %s skipping BB with/after __afl_loop\n",
1585 F.getName().str().c_str());
1586 skip = 1;
1587
1588 }
1589
1590 }
1591
1592 if (skip) continue;
1593
1594 }
1595
1596 // AFL++ END
1597
1598 InjectCoverageAtBlock(F, *AllBlocks[i], i, IsLeafFunc);
1599
1600 }
1601
1602 return true;
1603
1604 }
1605
1606 // On every indirect call we call a run-time function
1607 // __sanitizer_cov_indir_call* with two parameters:
1608 // - callee address,
1609 // - global cache array that contains CacheSize pointers (zero-initialized).
1610 // The cache is used to speed up recording the caller-callee pairs.
1611 // The address of the caller is passed implicitly via caller PC.
1612 // CacheSize is encoded in the name of the run-time function.
InjectCoverageForIndirectCalls(Function & F,ArrayRef<Instruction * > IndirCalls)1613 void ModuleSanitizerCoverageLTO::InjectCoverageForIndirectCalls(
1614 Function &F, ArrayRef<Instruction *> IndirCalls) {
1615
1616 if (IndirCalls.empty()) return;
1617 assert(Options.TracePC || Options.TracePCGuard ||
1618 Options.Inline8bitCounters || Options.InlineBoolFlag);
1619 for (auto I : IndirCalls) {
1620
1621 IRBuilder<> IRB(I);
1622 CallBase &CB = cast<CallBase>(*I);
1623 Value *Callee = CB.getCalledOperand();
1624 if (isa<InlineAsm>(Callee)) continue;
1625 IRB.CreateCall(SanCovTracePCIndir, IRB.CreatePointerCast(Callee, IntptrTy));
1626
1627 }
1628
1629 }
1630
InjectCoverageAtBlock(Function & F,BasicBlock & BB,size_t Idx,bool IsLeafFunc)1631 void ModuleSanitizerCoverageLTO::InjectCoverageAtBlock(Function &F,
1632 BasicBlock &BB,
1633 size_t Idx,
1634 bool IsLeafFunc) {
1635
1636 BasicBlock::iterator IP = BB.getFirstInsertionPt();
1637 bool IsEntryBB = &BB == &F.getEntryBlock();
1638
1639 if (IsEntryBB) {
1640
1641 // Keep static allocas and llvm.localescape calls in the entry block. Even
1642 // if we aren't splitting the block, it's nice for allocas to be before
1643 // calls.
1644 IP = PrepareToSplitEntryBlock(BB, IP);
1645
1646 }
1647
1648 IRBuilder<> IRB(&*IP);
1649 if (Options.TracePC) {
1650
1651 IRB.CreateCall(SanCovTracePC)
1652 #if LLVM_VERSION_MAJOR >= 12
1653 ->setCannotMerge(); // gets the PC using GET_CALLER_PC.
1654 #else
1655 ->cannotMerge(); // gets the PC using GET_CALLER_PC.
1656 #endif
1657
1658 }
1659
1660 if (Options.TracePCGuard) {
1661
1662 // AFL++ START
1663 ++afl_global_id;
1664
1665 if (dFile.is_open()) {
1666
1667 unsigned long long int moduleID =
1668 (((unsigned long long int)(rand() & 0xffffffff)) << 32) | getpid();
1669 dFile << "ModuleID=" << moduleID << " Function=" << F.getName().str()
1670 << " edgeID=" << afl_global_id << "\n";
1671
1672 }
1673
1674 /* Set the ID of the inserted basic block */
1675
1676 ConstantInt *CurLoc = ConstantInt::get(Int32Tyi, afl_global_id);
1677
1678 /* Load SHM pointer */
1679
1680 Value *MapPtrIdx;
1681
1682 if (map_addr) {
1683
1684 MapPtrIdx = IRB.CreateGEP(Int8Ty, MapPtrFixed, CurLoc);
1685
1686 } else {
1687
1688 LoadInst *MapPtr = IRB.CreateLoad(PointerType::get(Int8Ty, 0), AFLMapPtr);
1689 ModuleSanitizerCoverageLTO::SetNoSanitizeMetadata(MapPtr);
1690 MapPtrIdx = IRB.CreateGEP(Int8Ty, MapPtr, CurLoc);
1691
1692 }
1693
1694 /* Update bitmap */
1695 if (use_threadsafe_counters) { /* Atomic */
1696
1697 IRB.CreateAtomicRMW(llvm::AtomicRMWInst::BinOp::Add, MapPtrIdx, One,
1698 #if LLVM_VERSION_MAJOR >= 13
1699 llvm::MaybeAlign(1),
1700 #endif
1701 llvm::AtomicOrdering::Monotonic);
1702
1703 } else {
1704
1705 LoadInst *Counter = IRB.CreateLoad(IRB.getInt8Ty(), MapPtrIdx);
1706 ModuleSanitizerCoverageLTO::SetNoSanitizeMetadata(Counter);
1707
1708 Value *Incr = IRB.CreateAdd(Counter, One);
1709
1710 if (skip_nozero == NULL) {
1711
1712 auto cf = IRB.CreateICmpEQ(Incr, Zero);
1713 auto carry = IRB.CreateZExt(cf, Int8Tyi);
1714 Incr = IRB.CreateAdd(Incr, carry);
1715
1716 }
1717
1718 auto nosan = IRB.CreateStore(Incr, MapPtrIdx);
1719 ModuleSanitizerCoverageLTO::SetNoSanitizeMetadata(nosan);
1720
1721 }
1722
1723 // done :)
1724
1725 inst++;
1726 // AFL++ END
1727
1728 /*
1729 XXXXXXXXXXXXXXXXXXX
1730
1731 auto GuardPtr = IRB.CreateIntToPtr(
1732 IRB.CreateAdd(IRB.CreatePointerCast(FunctionGuardArray, IntptrTy),
1733 ConstantInt::get(IntptrTy, Idx * 4)),
1734 Int32PtrTy);
1735
1736 IRB.CreateCall(SanCovTracePCGuard, GuardPtr)->setCannotMerge();
1737 */
1738
1739 }
1740
1741 if (Options.Inline8bitCounters) {
1742
1743 auto CounterPtr = IRB.CreateGEP(
1744 Function8bitCounterArray->getValueType(), Function8bitCounterArray,
1745 {ConstantInt::get(IntptrTy, 0), ConstantInt::get(IntptrTy, Idx)});
1746 auto Load = IRB.CreateLoad(Int8Ty, CounterPtr);
1747 auto Inc = IRB.CreateAdd(Load, ConstantInt::get(Int8Ty, 1));
1748 auto Store = IRB.CreateStore(Inc, CounterPtr);
1749 SetNoSanitizeMetadata(Load);
1750 SetNoSanitizeMetadata(Store);
1751
1752 }
1753
1754 if (Options.InlineBoolFlag) {
1755
1756 auto FlagPtr = IRB.CreateGEP(
1757 FunctionBoolArray->getValueType(), FunctionBoolArray,
1758 {ConstantInt::get(IntptrTy, 0), ConstantInt::get(IntptrTy, Idx)});
1759 auto Load = IRB.CreateLoad(Int1Ty, FlagPtr);
1760 auto ThenTerm =
1761 SplitBlockAndInsertIfThen(IRB.CreateIsNull(Load), &*IP, false);
1762 IRBuilder<> ThenIRB(ThenTerm);
1763 auto Store = ThenIRB.CreateStore(ConstantInt::getTrue(Int1Ty), FlagPtr);
1764 SetNoSanitizeMetadata(Load);
1765 SetNoSanitizeMetadata(Store);
1766
1767 }
1768
1769 }
1770
getSectionName(const std::string & Section) const1771 std::string ModuleSanitizerCoverageLTO::getSectionName(
1772 const std::string &Section) const {
1773
1774 if (TargetTriple.isOSBinFormatCOFF()) {
1775
1776 if (Section == SanCovCountersSectionName) return ".SCOV$CM";
1777 if (Section == SanCovBoolFlagSectionName) return ".SCOV$BM";
1778 if (Section == SanCovPCsSectionName) return ".SCOVP$M";
1779 return ".SCOV$GM"; // For SanCovGuardsSectionName.
1780
1781 }
1782
1783 if (TargetTriple.isOSBinFormatMachO()) return "__DATA,__" + Section;
1784 return "__" + Section;
1785
1786 }
1787
1788 char ModuleSanitizerCoverageLTOLegacyPass::ID = 0;
1789
1790 INITIALIZE_PASS_BEGIN(ModuleSanitizerCoverageLTOLegacyPass, "sancov-lto",
1791 "Pass for instrumenting coverage on functions", false,
1792 false)
INITIALIZE_PASS_DEPENDENCY(DominatorTreeWrapperPass)1793 INITIALIZE_PASS_DEPENDENCY(DominatorTreeWrapperPass)
1794 INITIALIZE_PASS_DEPENDENCY(PostDominatorTreeWrapperPass)
1795 INITIALIZE_PASS_END(ModuleSanitizerCoverageLTOLegacyPass, "sancov-lto",
1796 "Pass for instrumenting coverage on functions", false,
1797 false)
1798
1799 #if LLVM_VERSION_MAJOR < 16
1800 static void registerLTOPass(const PassManagerBuilder &,
1801 legacy::PassManagerBase &PM) {
1802
1803 auto p = new ModuleSanitizerCoverageLTOLegacyPass();
1804 PM.add(p);
1805
1806 }
1807
1808 static RegisterStandardPasses RegisterCompTransPass(
1809 PassManagerBuilder::EP_OptimizerLast, registerLTOPass);
1810
1811 static RegisterStandardPasses RegisterCompTransPass0(
1812 PassManagerBuilder::EP_EnabledOnOptLevel0, registerLTOPass);
1813
1814 #if LLVM_VERSION_MAJOR >= 11
1815 static RegisterStandardPasses RegisterCompTransPassLTO(
1816 PassManagerBuilder::EP_FullLinkTimeOptimizationLast, registerLTOPass);
1817 #endif
1818 #endif
1819
1820