GenericTaintChecker.cpp revision 8f4caf5fec2de9b18f9c5fc69696d9f6cf66bcc5
1//== GenericTaintChecker.cpp ----------------------------------- -*- C++ -*--=// 2// 3// The LLVM Compiler Infrastructure 4// 5// This file is distributed under the University of Illinois Open Source 6// License. See LICENSE.TXT for details. 7// 8//===----------------------------------------------------------------------===// 9// 10// This checker defines the attack surface for generic taint propagation. 11// 12// The taint information produced by it might be useful to other checkers. For 13// example, checkers should report errors which involve tainted data more 14// aggressively, even if the involved symbols are under constrained. 15// 16//===----------------------------------------------------------------------===// 17#include "ClangSACheckers.h" 18#include "clang/StaticAnalyzer/Core/Checker.h" 19#include "clang/StaticAnalyzer/Core/CheckerManager.h" 20#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h" 21#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h" 22 23using namespace clang; 24using namespace ento; 25 26namespace { 27class GenericTaintChecker : public Checker< check::PostStmt<CallExpr> > { 28 29 mutable llvm::OwningPtr<BugType> BT; 30 void initBugType() const; 31 32 /// Given a pointer argument, get the symbol of the value it contains 33 /// (points to). 34 SymbolRef getPointedToSymbol(CheckerContext &C, 35 const Expr* Arg, 36 bool IssueWarning = true) const; 37 38 /// Functions defining the attacke surface. 39 typedef void (GenericTaintChecker::*FnCheck)(const CallExpr *, 40 CheckerContext &C) const; 41 void processScanf(const CallExpr *CE, CheckerContext &C) const; 42 void processRetTaint(const CallExpr *CE, CheckerContext &C) const; 43 44public: 45 void checkPostStmt(const CallExpr *CE, CheckerContext &C) const; 46}; 47} 48 49inline void GenericTaintChecker::initBugType() const { 50 if (!BT) 51 BT.reset(new BugType("Tainted data checking", "General")); 52} 53 54void GenericTaintChecker::checkPostStmt(const CallExpr *CE, 55 CheckerContext &C) const { 56 if (!C.getState()) 57 return; 58 59 StringRef Name = C.getCalleeName(CE); 60 61 // Define the attack surface. 62 // Set the evaluation function by switching on the callee name. 63 FnCheck evalFunction = llvm::StringSwitch<FnCheck>(Name) 64 .Case("scanf", &GenericTaintChecker::processScanf) 65 .Case("getchar", &GenericTaintChecker::processRetTaint) 66 .Default(NULL); 67 68 // If the callee isn't defined, it is not of security concern. 69 // Check and evaluate the call. 70 if (evalFunction) 71 (this->*evalFunction)(CE, C); 72 73} 74 75SymbolRef GenericTaintChecker::getPointedToSymbol(CheckerContext &C, 76 const Expr* Arg, 77 bool IssueWarning) const { 78 const ProgramState *State = C.getState(); 79 SVal AddrVal = State->getSVal(Arg->IgnoreParenCasts()); 80 Loc *AddrLoc = dyn_cast<Loc>(&AddrVal); 81 82 if (!AddrLoc && !IssueWarning) 83 return 0; 84 85 // If the Expr is not a location, issue a warning. 86 if (!AddrLoc) { 87 assert(IssueWarning); 88 if (ExplodedNode *N = C.generateSink(State)) { 89 initBugType(); 90 BugReport *report = new BugReport(*BT, "Pointer argument is expected.",N); 91 report->addRange(Arg->getSourceRange()); 92 C.EmitReport(report); 93 } 94 return 0; 95 } 96 97 SVal Val = State->getSVal(*AddrLoc); 98 return Val.getAsSymbol(); 99} 100 101 102void GenericTaintChecker::processScanf(const CallExpr *CE, 103 CheckerContext &C) const { 104 const ProgramState *State = C.getState(); 105 assert(CE->getNumArgs() == 2); 106 SVal x = State->getSVal(CE->getArg(1)); 107 // All arguments except for the very first one should get taint. 108 for (unsigned int i = 1; i < CE->getNumArgs(); ++i) { 109 // The arguments are pointer arguments. The data they are pointing at is 110 // tainted after the call. 111 const Expr* Arg = CE->getArg(i); 112 SymbolRef Sym = getPointedToSymbol(C, Arg); 113 if (Sym) 114 State = State->addTaint(Sym); 115 } 116 C.addTransition(State); 117 118} 119 120void GenericTaintChecker::processRetTaint(const CallExpr *CE, 121 CheckerContext &C) const { 122 const ProgramState *NewState = C.getState()->addTaint(CE); 123 C.addTransition(NewState); 124} 125 126void ento::registerGenericTaintChecker(CheckerManager &mgr) { 127 mgr.registerChecker<GenericTaintChecker>(); 128} 129