GenericTaintChecker.cpp revision df18c5ae6c48d3b56f7f9550875c53dc46eb8d78
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<BuiltinBug> BT; 30 31 /// Functions defining the attacke surface. 32 typedef void (GenericTaintChecker::*FnCheck)(const CallExpr *, 33 CheckerContext &C) const; 34 void processScanf(const CallExpr *CE, CheckerContext &C) const; 35 void processRetTaint(const CallExpr *CE, CheckerContext &C) const; 36 37public: 38 void checkPostStmt(const CallExpr *CE, CheckerContext &C) const; 39}; 40} 41 42void GenericTaintChecker::checkPostStmt(const CallExpr *CE, 43 CheckerContext &C) const { 44 if (!C.getState()) 45 return; 46 47 StringRef Name = C.getCalleeName(CE); 48 49 // Define the attack surface. 50 // Set the evaluation function by switching on the callee name. 51 FnCheck evalFunction = llvm::StringSwitch<FnCheck>(Name) 52 .Case("scanf", &GenericTaintChecker::processScanf) 53 .Case("getchar", &GenericTaintChecker::processRetTaint) 54 .Default(NULL); 55 56 // If the callee isn't defined, it is not of security concern. 57 // Check and evaluate the call. 58 if (evalFunction) 59 (this->*evalFunction)(CE, C); 60 61} 62static SymbolRef getPointedToSymbol(const ProgramState *State, 63 const Expr* Arg) { 64 SVal AddrVal = State->getSVal(Arg->IgnoreParenCasts()); 65 Loc *AddrLoc = dyn_cast<Loc>(&AddrVal); 66 SVal Val = State->getSVal(*AddrLoc); 67 return Val.getAsSymbol(); 68} 69 70 71void GenericTaintChecker::processScanf(const CallExpr *CE, 72 CheckerContext &C) const { 73 const ProgramState *State = C.getState(); 74 assert(CE->getNumArgs() == 2); 75 SVal x = State->getSVal(CE->getArg(1)); 76 // All arguments except for the very first one should get taint. 77 for (unsigned int i = 1; i < CE->getNumArgs(); ++i) { 78 // The arguments are pointer arguments. The data they are pointing at is 79 // tainted after the call. 80 const Expr* Arg = CE->getArg(i); 81 SymbolRef Sym = getPointedToSymbol(State, Arg); 82 if (Sym) 83 State = State->addTaint(Sym); 84 } 85 C.addTransition(State); 86 87} 88 89void GenericTaintChecker::processRetTaint(const CallExpr *CE, 90 CheckerContext &C) const { 91 const ProgramState *NewState = C.getState()->addTaint(CE); 92 C.addTransition(NewState); 93} 94 95void ento::registerGenericTaintChecker(CheckerManager &mgr) { 96 mgr.registerChecker<GenericTaintChecker>(); 97} 98