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<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 
37 public:
38   void checkPostStmt(const CallExpr *CE, CheckerContext &C) const;
39 };
40 }
41 
42 void 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 }
62 static 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 
71 void 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 
89 void GenericTaintChecker::processRetTaint(const CallExpr *CE,
90                                           CheckerContext &C) const {
91   const ProgramState *NewState = C.getState()->addTaint(CE);
92   C.addTransition(NewState);
93 }
94 
95 void ento::registerGenericTaintChecker(CheckerManager &mgr) {
96   mgr.registerChecker<GenericTaintChecker>();
97 }
98