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 
23 using namespace clang;
24 using namespace ento;
25 
26 namespace {
27 class 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 
44 public:
45   void checkPostStmt(const CallExpr *CE, CheckerContext &C) const;
46 };
47 }
48 
49 inline void GenericTaintChecker::initBugType() const {
50   if (!BT)
51     BT.reset(new BugType("Tainted data checking", "General"));
52 }
53 
54 void 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 
75 SymbolRef 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 
102 void 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 
120 void GenericTaintChecker::processRetTaint(const CallExpr *CE,
121                                           CheckerContext &C) const {
122   const ProgramState *NewState = C.getState()->addTaint(CE);
123   C.addTransition(NewState);
124 }
125 
126 void ento::registerGenericTaintChecker(CheckerManager &mgr) {
127   mgr.registerChecker<GenericTaintChecker>();
128 }
129