1 /* 2 american fuzzy lop++ - LLVM Injection instrumentation 3 -------------------------------------------------- 4 5 Written by Marc Heuse <[email protected]> 6 7 Copyright 2015, 2016 Google Inc. All rights reserved. 8 Copyright 2019-2024 AFLplusplus Project. All rights reserved. 9 10 Licensed under the Apache License, Version 2.0 (the "License"); 11 you may not use this file except in compliance with the License. 12 You may obtain a copy of the License at: 13 14 https://www.apache.org/licenses/LICENSE-2.0 15 16 */ 17 18 #include <stdio.h> 19 #include <stdlib.h> 20 #include <unistd.h> 21 22 #include <list> 23 #include <string> 24 #include <fstream> 25 #include <sys/time.h> 26 #include "llvm/Config/llvm-config.h" 27 28 #include "llvm/ADT/Statistic.h" 29 #include "llvm/IR/IRBuilder.h" 30 #if LLVM_VERSION_MAJOR >= 11 /* use new pass manager */ 31 #include "llvm/Passes/PassPlugin.h" 32 #include "llvm/Passes/PassBuilder.h" 33 #include "llvm/IR/PassManager.h" 34 #else 35 #include "llvm/IR/LegacyPassManager.h" 36 #include "llvm/Transforms/IPO/PassManagerBuilder.h" 37 #endif 38 #include "llvm/IR/Module.h" 39 #include "llvm/Support/Debug.h" 40 #include "llvm/Support/raw_ostream.h" 41 #if LLVM_VERSION_MAJOR < 17 42 #include "llvm/Transforms/IPO/PassManagerBuilder.h" 43 #endif 44 #include "llvm/Transforms/Utils/BasicBlockUtils.h" 45 #include "llvm/Pass.h" 46 #include "llvm/Analysis/ValueTracking.h" 47 48 #include "llvm/IR/IRBuilder.h" 49 #if LLVM_VERSION_MAJOR >= 4 || \ 50 (LLVM_VERSION_MAJOR == 3 && LLVM_VERSION_MINOR > 4) 51 #include "llvm/IR/Verifier.h" 52 #include "llvm/IR/DebugInfo.h" 53 #else 54 #include "llvm/Analysis/Verifier.h" 55 #include "llvm/DebugInfo.h" 56 #define nullptr 0 57 #endif 58 59 #include <set> 60 #include "afl-llvm-common.h" 61 62 using namespace llvm; 63 64 namespace { 65 66 #if LLVM_VERSION_MAJOR >= 11 /* use new pass manager */ 67 class InjectionRoutines : public PassInfoMixin<InjectionRoutines> { 68 69 public: InjectionRoutines()70 InjectionRoutines() { 71 72 #else 73 class InjectionRoutines : public ModulePass { 74 75 public: 76 static char ID; 77 InjectionRoutines() : ModulePass(ID) { 78 79 #endif 80 81 initInstrumentList(); 82 83 } 84 85 #if LLVM_VERSION_MAJOR >= 11 /* use new pass manager */ 86 PreservedAnalyses run(Module &M, ModuleAnalysisManager &MAM); 87 #else 88 bool runOnModule(Module &M) override; 89 90 #if LLVM_VERSION_MAJOR >= 4 91 StringRef getPassName() const override { 92 93 #else 94 const char *getPassName() const override { 95 96 #endif 97 return "Injection routines"; 98 99 } 100 101 #endif 102 103 private: 104 bool hookRtns(Module &M); 105 106 bool doSQL = false; 107 bool doLDAP = false; 108 bool doXSS = false; 109 110 }; 111 112 } // namespace 113 114 #if LLVM_MAJOR >= 11 115 extern "C" ::llvm::PassPluginLibraryInfo LLVM_ATTRIBUTE_WEAK 116 llvmGetPassPluginInfo() { 117 118 return {LLVM_PLUGIN_API_VERSION, "Injectionroutines", "v0.1", 119 /* lambda to insert our pass into the pass pipeline. */ 120 [](PassBuilder &PB) { 121 122 #if LLVM_VERSION_MAJOR <= 13 123 using OptimizationLevel = typename PassBuilder::OptimizationLevel; 124 #endif 125 PB.registerOptimizerLastEPCallback( 126 [](ModulePassManager &MPM, OptimizationLevel OL) { 127 128 MPM.addPass(InjectionRoutines()); 129 130 }); 131 132 }}; 133 134 } 135 136 #else 137 char InjectionRoutines::ID = 0; 138 #endif 139 140 bool InjectionRoutines::hookRtns(Module &M) { 141 142 std::vector<CallInst *> calls, llvmStdStd, llvmStdC, gccStdStd, gccStdC, 143 Memcmp, Strcmp, Strncmp; 144 LLVMContext &C = M.getContext(); 145 146 Type *VoidTy = Type::getVoidTy(C); 147 IntegerType *Int8Ty = IntegerType::getInt8Ty(C); 148 PointerType *i8PtrTy = PointerType::get(Int8Ty, 0); 149 150 #if LLVM_VERSION_MAJOR >= 9 151 FunctionCallee 152 #else 153 Constant * 154 #endif 155 c1 = M.getOrInsertFunction("__afl_injection_sql", VoidTy, i8PtrTy 156 #if LLVM_VERSION_MAJOR < 5 157 , 158 NULL 159 #endif 160 ); 161 #if LLVM_VERSION_MAJOR >= 9 162 FunctionCallee sqlfunc = c1; 163 #else 164 Function *sqlfunc = cast<Function>(c1); 165 #endif 166 167 #if LLVM_VERSION_MAJOR >= 9 168 FunctionCallee 169 #else 170 Constant * 171 #endif 172 c2 = M.getOrInsertFunction("__afl_injection_ldap", VoidTy, i8PtrTy 173 #if LLVM_VERSION_MAJOR < 5 174 , 175 NULL 176 #endif 177 ); 178 #if LLVM_VERSION_MAJOR >= 9 179 FunctionCallee ldapfunc = c2; 180 #else 181 Function *ldapfunc = cast<Function>(c2); 182 #endif 183 184 #if LLVM_VERSION_MAJOR >= 9 185 FunctionCallee 186 #else 187 Constant * 188 #endif 189 c3 = M.getOrInsertFunction("__afl_injection_xss", VoidTy, i8PtrTy 190 #if LLVM_VERSION_MAJOR < 5 191 , 192 NULL 193 #endif 194 ); 195 #if LLVM_VERSION_MAJOR >= 9 196 FunctionCallee xssfunc = c3; 197 #else 198 Function *xssfunc = cast<Function>(c3); 199 #endif 200 201 #if LLVM_VERSION_MAJOR >= 9 202 FunctionCallee FuncPtr; 203 #else 204 Function *FuncPtr; 205 #endif 206 207 /* iterate over all functions, bbs and instruction and add suitable calls */ 208 for (auto &F : M) { 209 210 if (!isInInstrumentList(&F, MNAME)) continue; 211 212 for (auto &BB : F) { 213 214 for (auto &IN : BB) { 215 216 CallInst *callInst = nullptr; 217 218 if ((callInst = dyn_cast<CallInst>(&IN))) { 219 220 Function *Callee = callInst->getCalledFunction(); 221 if (!Callee) continue; 222 if (callInst->getCallingConv() != llvm::CallingConv::C) continue; 223 224 std::string FuncName = Callee->getName().str(); 225 FuncPtr = nullptr; 226 size_t param = 0; 227 228 // Marker: ADD_TO_INJECTIONS 229 // If you just need to add another function to test for SQL etc. 230 // then add them here. 231 // To add a new class or to work on e.g. std::string/Rust strings/... 232 // you will need to add a function to afl-compiler-rt.c.o and 233 // and upwards in this file add a pointer to that function to use 234 // here. 235 236 if (doSQL && 237 (FuncName.compare("sqlite3_exec") == 0 || 238 FuncName.compare("PQexec") == 0 || FuncName.compare("") == 0 || 239 FuncName.compare("PQexecParams") == 0 || 240 FuncName.compare("mysql_query") == 0)) { 241 242 if (!be_quiet) { 243 244 errs() << "Injection SQL hook: " << FuncName << "\n"; 245 246 } 247 248 FuncPtr = sqlfunc; 249 param = 1; 250 251 } 252 253 if (doLDAP && (FuncName.compare("ldap_search_ext") == 0 || 254 FuncName.compare("ldap_search_ext_s") == 0)) { 255 256 if (!be_quiet) { 257 258 errs() << "Injection LDAP hook: " << FuncName << "\n"; 259 260 } 261 262 FuncPtr = ldapfunc; 263 param = 1; 264 265 } 266 267 if (doXSS && (FuncName.compare("htmlReadMemory") == 0)) { 268 269 if (!be_quiet) { 270 271 errs() << "Injection XSS hook: " << FuncName << "\n"; 272 273 } 274 275 FuncPtr = xssfunc; 276 param = 1; 277 278 } 279 280 if (FuncPtr) { 281 282 IRBuilder<> IRB(callInst->getParent()); 283 IRB.SetInsertPoint(callInst); 284 285 Value *parameter = callInst->getArgOperand(param); 286 287 std::vector<Value *> args; 288 Value *casted = IRB.CreatePointerCast(parameter, i8PtrTy); 289 args.push_back(casted); 290 IRB.CreateCall(FuncPtr, args); 291 292 } 293 294 } 295 296 } 297 298 } 299 300 } 301 302 return true; 303 304 } 305 306 #if LLVM_VERSION_MAJOR >= 11 /* use new pass manager */ 307 PreservedAnalyses InjectionRoutines::run(Module &M, 308 ModuleAnalysisManager &MAM) { 309 310 #else 311 bool InjectionRoutines::runOnModule(Module &M) { 312 313 #endif 314 315 if (getenv("AFL_QUIET") == NULL) 316 printf("Running injection-pass by Marc Heuse ([email protected])\n"); 317 else 318 be_quiet = 1; 319 if (getenv("AFL_LLVM_INJECTIONS_ALL")) { 320 321 doSQL = true; 322 doLDAP = true; 323 doXSS = true; 324 325 } 326 327 if (getenv("AFL_LLVM_INJECTIONS_SQL")) { doSQL = true; } 328 if (getenv("AFL_LLVM_INJECTIONS_LDAP")) { doLDAP = true; } 329 if (getenv("AFL_LLVM_INJECTIONS_XSS")) { doXSS = true; } 330 331 hookRtns(M); 332 #if LLVM_VERSION_MAJOR >= 11 /* use new pass manager */ 333 auto PA = PreservedAnalyses::all(); 334 #endif 335 verifyModule(M); 336 337 #if LLVM_VERSION_MAJOR >= 11 /* use new pass manager */ 338 return PA; 339 #else 340 return true; 341 #endif 342 343 } 344 345 #if LLVM_VERSION_MAJOR < 11 /* use old pass manager */ 346 static void registerInjectionRoutinesPass(const PassManagerBuilder &, 347 legacy::PassManagerBase &PM) { 348 349 auto p = new InjectionRoutines(); 350 PM.add(p); 351 352 } 353 354 static RegisterStandardPasses RegisterInjectionRoutinesPass( 355 PassManagerBuilder::EP_OptimizerLast, registerInjectionRoutinesPass); 356 357 static RegisterStandardPasses RegisterInjectionRoutinesPass0( 358 PassManagerBuilder::EP_EnabledOnOptLevel0, registerInjectionRoutinesPass); 359 360 #if LLVM_VERSION_MAJOR >= 11 361 static RegisterStandardPasses RegisterInjectionRoutinesPassLTO( 362 PassManagerBuilder::EP_FullLinkTimeOptimizationLast, 363 registerInjectionRoutinesPass); 364 #endif 365 #endif 366 367