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