blob: 890a592c17c986f3aa3d307e14d5a3e43ff384a0 [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
Anna Zaks8f4caf52011-11-18 02:26:36 +000029 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;
Anna Zaksdf18c5a2011-11-16 19:58:13 +000037
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;
Anna Zaks1009ac72011-12-14 00:56:02 +000042 void processFscanf(const CallExpr *CE, CheckerContext &C) const;
Anna Zaksdf18c5a2011-11-16 19:58:13 +000043 void processRetTaint(const CallExpr *CE, CheckerContext &C) const;
44
45public:
46 void checkPostStmt(const CallExpr *CE, CheckerContext &C) const;
47};
48}
49
Anna Zaks8f4caf52011-11-18 02:26:36 +000050inline void GenericTaintChecker::initBugType() const {
51 if (!BT)
52 BT.reset(new BugType("Tainted data checking", "General"));
53}
54
Anna Zaksdf18c5a2011-11-16 19:58:13 +000055void GenericTaintChecker::checkPostStmt(const CallExpr *CE,
56 CheckerContext &C) const {
57 if (!C.getState())
58 return;
59
60 StringRef Name = C.getCalleeName(CE);
61
62 // Define the attack surface.
63 // Set the evaluation function by switching on the callee name.
64 FnCheck evalFunction = llvm::StringSwitch<FnCheck>(Name)
65 .Case("scanf", &GenericTaintChecker::processScanf)
Anna Zaks1009ac72011-12-14 00:56:02 +000066 .Case("fscanf", &GenericTaintChecker::processFscanf)
67 .Case("sscanf", &GenericTaintChecker::processFscanf)
68 // TODO: Add support for vfscanf & family.
Anna Zaksdf18c5a2011-11-16 19:58:13 +000069 .Case("getchar", &GenericTaintChecker::processRetTaint)
Anna Zakse55a22b2011-12-14 00:55:58 +000070 .Case("getenv", &GenericTaintChecker::processRetTaint)
Anna Zaks1009ac72011-12-14 00:56:02 +000071 .Case("fopen", &GenericTaintChecker::processRetTaint)
72 .Case("fdopen", &GenericTaintChecker::processRetTaint)
73 .Case("freopen", &GenericTaintChecker::processRetTaint)
Anna Zaksdf18c5a2011-11-16 19:58:13 +000074 .Default(NULL);
75
76 // If the callee isn't defined, it is not of security concern.
77 // Check and evaluate the call.
78 if (evalFunction)
79 (this->*evalFunction)(CE, C);
80
81}
Anna Zaks8f4caf52011-11-18 02:26:36 +000082
83SymbolRef GenericTaintChecker::getPointedToSymbol(CheckerContext &C,
84 const Expr* Arg,
85 bool IssueWarning) const {
86 const ProgramState *State = C.getState();
Anna Zaksdf18c5a2011-11-16 19:58:13 +000087 SVal AddrVal = State->getSVal(Arg->IgnoreParenCasts());
Anna Zakse3d250e2011-12-11 18:43:40 +000088
89 // TODO: Taint is not going to propagate?
90 if (AddrVal.isUnknownOrUndef())
91 return 0;
92
Anna Zaksdf18c5a2011-11-16 19:58:13 +000093 Loc *AddrLoc = dyn_cast<Loc>(&AddrVal);
Anna Zaks8f4caf52011-11-18 02:26:36 +000094
95 if (!AddrLoc && !IssueWarning)
96 return 0;
97
98 // If the Expr is not a location, issue a warning.
99 if (!AddrLoc) {
100 assert(IssueWarning);
101 if (ExplodedNode *N = C.generateSink(State)) {
102 initBugType();
103 BugReport *report = new BugReport(*BT, "Pointer argument is expected.",N);
104 report->addRange(Arg->getSourceRange());
105 C.EmitReport(report);
106 }
107 return 0;
108 }
109
Anna Zaksdf18c5a2011-11-16 19:58:13 +0000110 SVal Val = State->getSVal(*AddrLoc);
111 return Val.getAsSymbol();
112}
113
114
115void GenericTaintChecker::processScanf(const CallExpr *CE,
116 CheckerContext &C) const {
117 const ProgramState *State = C.getState();
Anna Zaks1009ac72011-12-14 00:56:02 +0000118 assert(CE->getNumArgs() >= 2);
Anna Zaksdf18c5a2011-11-16 19:58:13 +0000119 SVal x = State->getSVal(CE->getArg(1));
120 // All arguments except for the very first one should get taint.
121 for (unsigned int i = 1; i < CE->getNumArgs(); ++i) {
122 // The arguments are pointer arguments. The data they are pointing at is
123 // tainted after the call.
124 const Expr* Arg = CE->getArg(i);
Anna Zaks8f4caf52011-11-18 02:26:36 +0000125 SymbolRef Sym = getPointedToSymbol(C, Arg);
Anna Zaksdf18c5a2011-11-16 19:58:13 +0000126 if (Sym)
127 State = State->addTaint(Sym);
128 }
129 C.addTransition(State);
Anna Zaks1009ac72011-12-14 00:56:02 +0000130}
Anna Zaksdf18c5a2011-11-16 19:58:13 +0000131
Anna Zaks1009ac72011-12-14 00:56:02 +0000132/// If argument 0 (file descriptor) is tainted, all arguments except for arg 0
133/// and arg 1 should get taint.
134void GenericTaintChecker::processFscanf(const CallExpr *CE,
135 CheckerContext &C) const {
136 const ProgramState *State = C.getState();
137 assert(CE->getNumArgs() >= 2);
138
139 // Check is the file descriptor is tainted.
140 if (!State->isTainted(CE->getArg(0)))
141 return;
142
143 // All arguments except for the first two should get taint.
144 for (unsigned int i = 2; i < CE->getNumArgs(); ++i) {
145 // The arguments are pointer arguments. The data they are pointing at is
146 // tainted after the call.
147 const Expr* Arg = CE->getArg(i);
148 SymbolRef Sym = getPointedToSymbol(C, Arg);
149 if (Sym)
150 State = State->addTaint(Sym);
151 }
152 C.addTransition(State);
Anna Zaksdf18c5a2011-11-16 19:58:13 +0000153}
154
155void GenericTaintChecker::processRetTaint(const CallExpr *CE,
156 CheckerContext &C) const {
157 const ProgramState *NewState = C.getState()->addTaint(CE);
158 C.addTransition(NewState);
159}
160
161void ento::registerGenericTaintChecker(CheckerManager &mgr) {
162 mgr.registerChecker<GenericTaintChecker>();
163}