blob: 0fcfdf8ff59d836ac45721f6bf85a225209e1807 [file] [log] [blame]
Anna Zaksdf18c5a2011-11-16 19:58:13 +00001//== 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}