blob: 3076982018a38d0da9c059d2a2a4965172b594fd [file] [log] [blame]
Anna Zaks5c5bf9b2011-11-16 19:58:13 +00001//== GenericTaintChecker.cpp ----------------------------------- -*- C++ -*--=//
2//
Chandler Carruth2946cd72019-01-19 08:50:56 +00003// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
Anna Zaks5c5bf9b2011-11-16 19:58:13 +00006//
7//===----------------------------------------------------------------------===//
8//
9// This checker defines the attack surface for generic taint propagation.
10//
11// The taint information produced by it might be useful to other checkers. For
12// example, checkers should report errors which involve tainted data more
13// aggressively, even if the involved symbols are under constrained.
14//
15//===----------------------------------------------------------------------===//
Kristof Umann76a21502018-12-15 16:23:51 +000016#include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h"
Chandler Carruth3a022472012-12-04 09:13:33 +000017#include "clang/AST/Attr.h"
18#include "clang/Basic/Builtins.h"
19#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
Anna Zaks5c5bf9b2011-11-16 19:58:13 +000020#include "clang/StaticAnalyzer/Core/Checker.h"
21#include "clang/StaticAnalyzer/Core/CheckerManager.h"
22#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
Anna Zaks3b0ab202011-12-17 00:26:34 +000023#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h"
Anna Zaksb3fa8d72012-01-12 02:22:34 +000024#include <climits>
Anna Zaks5c5bf9b2011-11-16 19:58:13 +000025
26using namespace clang;
27using namespace ento;
28
29namespace {
Artem Dergachevb68cb542018-12-19 23:35:08 +000030class GenericTaintChecker
31 : public Checker<check::PostStmt<CallExpr>, check::PreStmt<CallExpr>> {
Anna Zaks3b0ab202011-12-17 00:26:34 +000032public:
Artem Dergachevb68cb542018-12-19 23:35:08 +000033 static void *getTag() {
34 static int Tag;
35 return &Tag;
36 }
Anna Zaks0244cd72012-01-14 02:48:40 +000037
38 void checkPostStmt(const CallExpr *CE, CheckerContext &C) const;
Anna Zaks0244cd72012-01-14 02:48:40 +000039
40 void checkPreStmt(const CallExpr *CE, CheckerContext &C) const;
Anna Zaks5c5bf9b2011-11-16 19:58:13 +000041
Anna Zaks3b0ab202011-12-17 00:26:34 +000042private:
Anna Zaksbf740512012-01-24 19:32:25 +000043 static const unsigned InvalidArgIndex = UINT_MAX;
44 /// Denotes the return vale.
45 static const unsigned ReturnValueIndex = UINT_MAX - 1;
Anna Zaks0244cd72012-01-14 02:48:40 +000046
Ahmed Charlesb8984322014-03-07 20:03:18 +000047 mutable std::unique_ptr<BugType> BT;
Anna Zaks5d324e52012-01-18 02:45:07 +000048 inline void initBugType() const {
49 if (!BT)
Alexander Kornienko4aca9b12014-02-11 21:49:21 +000050 BT.reset(new BugType(this, "Use of Untrusted Data", "Untrusted Data"));
Anna Zaks5d324e52012-01-18 02:45:07 +000051 }
Anna Zaks457c6872011-11-18 02:26:36 +000052
Adrian Prantl9fc8faf2018-05-09 01:00:01 +000053 /// Catch taint related bugs. Check if tainted data is passed to a
Anna Zaksb3fa8d72012-01-12 02:22:34 +000054 /// system call etc.
Anna Zaks126a2ef2012-01-07 02:33:10 +000055 bool checkPre(const CallExpr *CE, CheckerContext &C) const;
56
Adrian Prantl9fc8faf2018-05-09 01:00:01 +000057 /// Add taint sources on a pre-visit.
Anna Zaksb3fa8d72012-01-12 02:22:34 +000058 void addSourcesPre(const CallExpr *CE, CheckerContext &C) const;
59
Adrian Prantl9fc8faf2018-05-09 01:00:01 +000060 /// Propagate taint generated at pre-visit.
Anna Zaksb3fa8d72012-01-12 02:22:34 +000061 bool propagateFromPre(const CallExpr *CE, CheckerContext &C) const;
62
Adrian Prantl9fc8faf2018-05-09 01:00:01 +000063 /// Add taint sources on a post visit.
Anna Zaksb3fa8d72012-01-12 02:22:34 +000064 void addSourcesPost(const CallExpr *CE, CheckerContext &C) const;
65
Anna Zaksbf740512012-01-24 19:32:25 +000066 /// Check if the region the expression evaluates to is the standard input,
67 /// and thus, is tainted.
68 static bool isStdin(const Expr *E, CheckerContext &C);
69
Adrian Prantl9fc8faf2018-05-09 01:00:01 +000070 /// Given a pointer argument, return the value it points to.
Artem Dergacheveed7a312017-05-29 15:42:56 +000071 static Optional<SVal> getPointedToSVal(CheckerContext &C, const Expr *Arg);
Anna Zaks5c5bf9b2011-11-16 19:58:13 +000072
Anna Zaks3b0ab202011-12-17 00:26:34 +000073 /// Functions defining the attack surface.
Artem Dergachevb68cb542018-12-19 23:35:08 +000074 typedef ProgramStateRef (GenericTaintChecker::*FnCheck)(
75 const CallExpr *, CheckerContext &C) const;
Ted Kremenek49b1e382012-01-26 21:29:00 +000076 ProgramStateRef postScanf(const CallExpr *CE, CheckerContext &C) const;
77 ProgramStateRef postSocket(const CallExpr *CE, CheckerContext &C) const;
78 ProgramStateRef postRetTaint(const CallExpr *CE, CheckerContext &C) const;
Anna Zaks3b0ab202011-12-17 00:26:34 +000079
80 /// Taint the scanned input if the file is tainted.
Ted Kremenek49b1e382012-01-26 21:29:00 +000081 ProgramStateRef preFscanf(const CallExpr *CE, CheckerContext &C) const;
Anna Zaks5c5bf9b2011-11-16 19:58:13 +000082
Anna Zaks126a2ef2012-01-07 02:33:10 +000083 /// Check for CWE-134: Uncontrolled Format String.
Anna Zaks0244cd72012-01-14 02:48:40 +000084 static const char MsgUncontrolledFormatString[];
Anna Zaks126a2ef2012-01-07 02:33:10 +000085 bool checkUncontrolledFormatString(const CallExpr *CE,
86 CheckerContext &C) const;
87
Anna Zaks0244cd72012-01-14 02:48:40 +000088 /// Check for:
89 /// CERT/STR02-C. "Sanitize data passed to complex subsystems"
90 /// CWE-78, "Failure to Sanitize Data into an OS Command"
91 static const char MsgSanitizeSystemArgs[];
92 bool checkSystemCall(const CallExpr *CE, StringRef Name,
93 CheckerContext &C) const;
Anna Zaks3b0ab202011-12-17 00:26:34 +000094
Anna Zaks560dbe92012-01-18 02:45:11 +000095 /// Check if tainted data is used as a buffer size ins strn.. functions,
96 /// and allocators.
97 static const char MsgTaintedBufferSize[];
98 bool checkTaintedBufferSize(const CallExpr *CE, const FunctionDecl *FDecl,
99 CheckerContext &C) const;
100
Anna Zaks0244cd72012-01-14 02:48:40 +0000101 /// Generate a report if the expression is tainted or points to tainted data.
102 bool generateReportIfTainted(const Expr *E, const char Msg[],
103 CheckerContext &C) const;
Ted Kremenek3a0678e2015-09-08 03:50:52 +0000104
Dmitri Gribenkof8579502013-01-12 19:30:44 +0000105 typedef SmallVector<unsigned, 2> ArgVector;
Anna Zaks3b0ab202011-12-17 00:26:34 +0000106
Adrian Prantl9fc8faf2018-05-09 01:00:01 +0000107 /// A struct used to specify taint propagation rules for a function.
Anna Zaks3666d2c2012-01-17 00:37:02 +0000108 ///
109 /// If any of the possible taint source arguments is tainted, all of the
110 /// destination arguments should also be tainted. Use InvalidArgIndex in the
111 /// src list to specify that all of the arguments can introduce taint. Use
112 /// InvalidArgIndex in the dst arguments to signify that all the non-const
113 /// pointer and reference arguments might be tainted on return. If
114 /// ReturnValueIndex is added to the dst list, the return value will be
115 /// tainted.
116 struct TaintPropagationRule {
117 /// List of arguments which can be taint sources and should be checked.
118 ArgVector SrcArgs;
119 /// List of arguments which should be tainted on function return.
120 ArgVector DstArgs;
Anna Zaks5d324e52012-01-18 02:45:07 +0000121 // TODO: Check if using other data structures would be more optimal.
Anna Zaks3666d2c2012-01-17 00:37:02 +0000122
123 TaintPropagationRule() {}
124
Artem Dergachevb68cb542018-12-19 23:35:08 +0000125 TaintPropagationRule(unsigned SArg, unsigned DArg, bool TaintRet = false) {
Anna Zaks3666d2c2012-01-17 00:37:02 +0000126 SrcArgs.push_back(SArg);
127 DstArgs.push_back(DArg);
Anna Zaks5d324e52012-01-18 02:45:07 +0000128 if (TaintRet)
129 DstArgs.push_back(ReturnValueIndex);
Anna Zaks3666d2c2012-01-17 00:37:02 +0000130 }
131
Artem Dergachevb68cb542018-12-19 23:35:08 +0000132 TaintPropagationRule(unsigned SArg1, unsigned SArg2, unsigned DArg,
133 bool TaintRet = false) {
Anna Zaks5d324e52012-01-18 02:45:07 +0000134 SrcArgs.push_back(SArg1);
135 SrcArgs.push_back(SArg2);
136 DstArgs.push_back(DArg);
137 if (TaintRet)
138 DstArgs.push_back(ReturnValueIndex);
139 }
140
141 /// Get the propagation rule for a given function.
142 static TaintPropagationRule
Artem Dergachevb68cb542018-12-19 23:35:08 +0000143 getTaintPropagationRule(const FunctionDecl *FDecl, StringRef Name,
144 CheckerContext &C);
Anna Zaks5d324e52012-01-18 02:45:07 +0000145
Anna Zaks3666d2c2012-01-17 00:37:02 +0000146 inline void addSrcArg(unsigned A) { SrcArgs.push_back(A); }
Artem Dergachevb68cb542018-12-19 23:35:08 +0000147 inline void addDstArg(unsigned A) { DstArgs.push_back(A); }
Anna Zaks3666d2c2012-01-17 00:37:02 +0000148
Anna Zaks5d324e52012-01-18 02:45:07 +0000149 inline bool isNull() const { return SrcArgs.empty(); }
150
151 inline bool isDestinationArgument(unsigned ArgNum) const {
Artem Dergachevb68cb542018-12-19 23:35:08 +0000152 return (std::find(DstArgs.begin(), DstArgs.end(), ArgNum) !=
153 DstArgs.end());
Anna Zaks5d324e52012-01-18 02:45:07 +0000154 }
Anna Zaks3666d2c2012-01-17 00:37:02 +0000155
Anna Zaksbf740512012-01-24 19:32:25 +0000156 static inline bool isTaintedOrPointsToTainted(const Expr *E,
Ted Kremenek49b1e382012-01-26 21:29:00 +0000157 ProgramStateRef State,
Anna Zaksbf740512012-01-24 19:32:25 +0000158 CheckerContext &C) {
Artem Dergacheveed7a312017-05-29 15:42:56 +0000159 if (State->isTainted(E, C.getLocationContext()) || isStdin(E, C))
160 return true;
161
162 if (!E->getType().getTypePtr()->isPointerType())
163 return false;
164
165 Optional<SVal> V = getPointedToSVal(C, E);
166 return (V && State->isTainted(*V));
Anna Zaksbf740512012-01-24 19:32:25 +0000167 }
168
Adrian Prantl9fc8faf2018-05-09 01:00:01 +0000169 /// Pre-process a function which propagates taint according to the
Anna Zaks7f6a6b72012-01-18 02:45:13 +0000170 /// taint rule.
Ted Kremenek49b1e382012-01-26 21:29:00 +0000171 ProgramStateRef process(const CallExpr *CE, CheckerContext &C) const;
Anna Zaks7f6a6b72012-01-18 02:45:13 +0000172 };
Anna Zaks5c5bf9b2011-11-16 19:58:13 +0000173};
Anna Zaks5d324e52012-01-18 02:45:07 +0000174
175const unsigned GenericTaintChecker::ReturnValueIndex;
176const unsigned GenericTaintChecker::InvalidArgIndex;
177
Anna Zaks0244cd72012-01-14 02:48:40 +0000178const char GenericTaintChecker::MsgUncontrolledFormatString[] =
Artem Dergachevb68cb542018-12-19 23:35:08 +0000179 "Untrusted data is used as a format string "
180 "(CWE-134: Uncontrolled Format String)";
Anna Zaks0244cd72012-01-14 02:48:40 +0000181
182const char GenericTaintChecker::MsgSanitizeSystemArgs[] =
Artem Dergachevb68cb542018-12-19 23:35:08 +0000183 "Untrusted data is passed to a system call "
184 "(CERT/STR02-C. Sanitize data passed to complex subsystems)";
Anna Zaks560dbe92012-01-18 02:45:11 +0000185
186const char GenericTaintChecker::MsgTaintedBufferSize[] =
Artem Dergachevb68cb542018-12-19 23:35:08 +0000187 "Untrusted data is used to specify the buffer size "
188 "(CERT/STR31-C. Guarantee that storage for strings has sufficient space "
189 "for "
190 "character data and the null terminator)";
Anna Zaks560dbe92012-01-18 02:45:11 +0000191
192} // end of anonymous namespace
Anna Zaks5c5bf9b2011-11-16 19:58:13 +0000193
Anna Zaksb3fa8d72012-01-12 02:22:34 +0000194/// A set which is used to pass information from call pre-visit instruction
195/// to the call post-visit. The values are unsigned integers, which are either
196/// ReturnValueIndex, or indexes of the pointer/reference argument, which
197/// points to data, which should be tainted on return.
Jordan Rose0c153cb2012-11-02 01:54:06 +0000198REGISTER_SET_WITH_PROGRAMSTATE(TaintArgsOnPostVisit, unsigned)
Anna Zaks3b0ab202011-12-17 00:26:34 +0000199
Anna Zaks5d324e52012-01-18 02:45:07 +0000200GenericTaintChecker::TaintPropagationRule
201GenericTaintChecker::TaintPropagationRule::getTaintPropagationRule(
Artem Dergachevb68cb542018-12-19 23:35:08 +0000202 const FunctionDecl *FDecl, StringRef Name, CheckerContext &C) {
Enrico Pertoso4432d872015-06-03 09:10:58 +0000203 // TODO: Currently, we might lose precision here: we always mark a return
Anna Zaksbf740512012-01-24 19:32:25 +0000204 // value as tainted even if it's just a pointer, pointing to tainted data.
205
Anna Zaks5d324e52012-01-18 02:45:07 +0000206 // Check for exact name match for functions without builtin substitutes.
Artem Dergachevb68cb542018-12-19 23:35:08 +0000207 TaintPropagationRule Rule =
208 llvm::StringSwitch<TaintPropagationRule>(Name)
209 .Case("atoi", TaintPropagationRule(0, ReturnValueIndex))
210 .Case("atol", TaintPropagationRule(0, ReturnValueIndex))
211 .Case("atoll", TaintPropagationRule(0, ReturnValueIndex))
212 .Case("getc", TaintPropagationRule(0, ReturnValueIndex))
213 .Case("fgetc", TaintPropagationRule(0, ReturnValueIndex))
214 .Case("getc_unlocked", TaintPropagationRule(0, ReturnValueIndex))
215 .Case("getw", TaintPropagationRule(0, ReturnValueIndex))
216 .Case("toupper", TaintPropagationRule(0, ReturnValueIndex))
217 .Case("tolower", TaintPropagationRule(0, ReturnValueIndex))
218 .Case("strchr", TaintPropagationRule(0, ReturnValueIndex))
219 .Case("strrchr", TaintPropagationRule(0, ReturnValueIndex))
220 .Case("read", TaintPropagationRule(0, 2, 1, true))
221 .Case("pread", TaintPropagationRule(InvalidArgIndex, 1, true))
222 .Case("gets", TaintPropagationRule(InvalidArgIndex, 0, true))
223 .Case("fgets", TaintPropagationRule(2, 0, true))
224 .Case("getline", TaintPropagationRule(2, 0))
225 .Case("getdelim", TaintPropagationRule(3, 0))
226 .Case("fgetln", TaintPropagationRule(0, ReturnValueIndex))
227 .Default(TaintPropagationRule());
Anna Zaks5d324e52012-01-18 02:45:07 +0000228
229 if (!Rule.isNull())
230 return Rule;
231
232 // Check if it's one of the memory setting/copying functions.
233 // This check is specialized but faster then calling isCLibraryFunction.
234 unsigned BId = 0;
Artem Dergachevb68cb542018-12-19 23:35:08 +0000235 if ((BId = FDecl->getMemoryFunctionKind()))
236 switch (BId) {
Anna Zaks5d324e52012-01-18 02:45:07 +0000237 case Builtin::BImemcpy:
238 case Builtin::BImemmove:
239 case Builtin::BIstrncpy:
240 case Builtin::BIstrncat:
241 return TaintPropagationRule(1, 2, 0, true);
Anna Zaks5d324e52012-01-18 02:45:07 +0000242 case Builtin::BIstrlcpy:
243 case Builtin::BIstrlcat:
244 return TaintPropagationRule(1, 2, 0, false);
Anna Zaks5d324e52012-01-18 02:45:07 +0000245 case Builtin::BIstrndup:
246 return TaintPropagationRule(0, 1, ReturnValueIndex);
Anna Zaks5d324e52012-01-18 02:45:07 +0000247
248 default:
249 break;
250 };
251
252 // Process all other functions which could be defined as builtins.
253 if (Rule.isNull()) {
254 if (C.isCLibraryFunction(FDecl, "snprintf") ||
255 C.isCLibraryFunction(FDecl, "sprintf"))
256 return TaintPropagationRule(InvalidArgIndex, 0, true);
257 else if (C.isCLibraryFunction(FDecl, "strcpy") ||
258 C.isCLibraryFunction(FDecl, "stpcpy") ||
259 C.isCLibraryFunction(FDecl, "strcat"))
260 return TaintPropagationRule(1, 0, true);
261 else if (C.isCLibraryFunction(FDecl, "bcopy"))
262 return TaintPropagationRule(0, 2, 1, false);
263 else if (C.isCLibraryFunction(FDecl, "strdup") ||
264 C.isCLibraryFunction(FDecl, "strdupa"))
265 return TaintPropagationRule(0, ReturnValueIndex);
Anna Zaks560dbe92012-01-18 02:45:11 +0000266 else if (C.isCLibraryFunction(FDecl, "wcsdup"))
267 return TaintPropagationRule(0, ReturnValueIndex);
Anna Zaks5d324e52012-01-18 02:45:07 +0000268 }
269
270 // Skipping the following functions, since they might be used for cleansing
271 // or smart memory copy:
Benjamin Kramer474261a2012-06-02 10:20:41 +0000272 // - memccpy - copying until hitting a special character.
Anna Zaks5d324e52012-01-18 02:45:07 +0000273
274 return TaintPropagationRule();
Anna Zaks457c6872011-11-18 02:26:36 +0000275}
276
Anna Zaks3b0ab202011-12-17 00:26:34 +0000277void GenericTaintChecker::checkPreStmt(const CallExpr *CE,
278 CheckerContext &C) const {
Anna Zaks126a2ef2012-01-07 02:33:10 +0000279 // Check for errors first.
280 if (checkPre(CE, C))
281 return;
Anna Zaks3b0ab202011-12-17 00:26:34 +0000282
Anna Zaks126a2ef2012-01-07 02:33:10 +0000283 // Add taint second.
Anna Zaksb3fa8d72012-01-12 02:22:34 +0000284 addSourcesPre(CE, C);
Anna Zaks126a2ef2012-01-07 02:33:10 +0000285}
286
287void GenericTaintChecker::checkPostStmt(const CallExpr *CE,
288 CheckerContext &C) const {
Anna Zaksb3fa8d72012-01-12 02:22:34 +0000289 if (propagateFromPre(CE, C))
290 return;
291 addSourcesPost(CE, C);
Anna Zaks126a2ef2012-01-07 02:33:10 +0000292}
293
Anna Zaksb3fa8d72012-01-12 02:22:34 +0000294void GenericTaintChecker::addSourcesPre(const CallExpr *CE,
295 CheckerContext &C) const {
Craig Topper0dbb7832014-05-27 02:45:47 +0000296 ProgramStateRef State = nullptr;
Anna Zaks5d324e52012-01-18 02:45:07 +0000297 const FunctionDecl *FDecl = C.getCalleeDecl(CE);
Jordan Rose6cd16c52012-07-10 23:13:01 +0000298 if (!FDecl || FDecl->getKind() != Decl::Function)
299 return;
300
Anna Zaks5d324e52012-01-18 02:45:07 +0000301 StringRef Name = C.getCalleeName(FDecl);
Anna Zaksb3fa8d72012-01-12 02:22:34 +0000302 if (Name.empty())
303 return;
Anna Zaks3666d2c2012-01-17 00:37:02 +0000304
Anna Zaks5d324e52012-01-18 02:45:07 +0000305 // First, try generating a propagation rule for this function.
306 TaintPropagationRule Rule =
Artem Dergachevb68cb542018-12-19 23:35:08 +0000307 TaintPropagationRule::getTaintPropagationRule(FDecl, Name, C);
Anna Zaks3666d2c2012-01-17 00:37:02 +0000308 if (!Rule.isNull()) {
Anna Zaks7f6a6b72012-01-18 02:45:13 +0000309 State = Rule.process(CE, C);
Anna Zaks3666d2c2012-01-17 00:37:02 +0000310 if (!State)
311 return;
312 C.addTransition(State);
Anna Zaks5d324e52012-01-18 02:45:07 +0000313 return;
Anna Zaks3666d2c2012-01-17 00:37:02 +0000314 }
315
Anna Zaks5d324e52012-01-18 02:45:07 +0000316 // Otherwise, check if we have custom pre-processing implemented.
Anna Zaks3b0ab202011-12-17 00:26:34 +0000317 FnCheck evalFunction = llvm::StringSwitch<FnCheck>(Name)
Artem Dergachevb68cb542018-12-19 23:35:08 +0000318 .Case("fscanf", &GenericTaintChecker::preFscanf)
319 .Default(nullptr);
Anna Zaks3b0ab202011-12-17 00:26:34 +0000320 // Check and evaluate the call.
321 if (evalFunction)
322 State = (this->*evalFunction)(CE, C);
323 if (!State)
Anna Zaks5c5bf9b2011-11-16 19:58:13 +0000324 return;
Anna Zaks3b0ab202011-12-17 00:26:34 +0000325 C.addTransition(State);
326}
327
Anna Zaksb3fa8d72012-01-12 02:22:34 +0000328bool GenericTaintChecker::propagateFromPre(const CallExpr *CE,
329 CheckerContext &C) const {
Ted Kremenek49b1e382012-01-26 21:29:00 +0000330 ProgramStateRef State = C.getState();
Anna Zaksb3fa8d72012-01-12 02:22:34 +0000331
332 // Depending on what was tainted at pre-visit, we determined a set of
333 // arguments which should be tainted after the function returns. These are
334 // stored in the state as TaintArgsOnPostVisit set.
Jordan Rose0c153cb2012-11-02 01:54:06 +0000335 TaintArgsOnPostVisitTy TaintArgs = State->get<TaintArgsOnPostVisit>();
Anna Zaksbf740512012-01-24 19:32:25 +0000336 if (TaintArgs.isEmpty())
337 return false;
338
Artem Dergachevb68cb542018-12-19 23:35:08 +0000339 for (llvm::ImmutableSet<unsigned>::iterator I = TaintArgs.begin(),
340 E = TaintArgs.end();
341 I != E; ++I) {
342 unsigned ArgNum = *I;
Anna Zaksb3fa8d72012-01-12 02:22:34 +0000343
344 // Special handling for the tainted return value.
345 if (ArgNum == ReturnValueIndex) {
346 State = State->addTaint(CE, C.getLocationContext());
347 continue;
348 }
349
350 // The arguments are pointer arguments. The data they are pointing at is
351 // tainted after the call.
Anna Zaksb508d292012-04-10 23:41:11 +0000352 if (CE->getNumArgs() < (ArgNum + 1))
353 return false;
Artem Dergachevb68cb542018-12-19 23:35:08 +0000354 const Expr *Arg = CE->getArg(ArgNum);
Artem Dergacheveed7a312017-05-29 15:42:56 +0000355 Optional<SVal> V = getPointedToSVal(C, Arg);
356 if (V)
357 State = State->addTaint(*V);
Anna Zaksb3fa8d72012-01-12 02:22:34 +0000358 }
359
360 // Clear up the taint info from the state.
361 State = State->remove<TaintArgsOnPostVisit>();
362
363 if (State != C.getState()) {
364 C.addTransition(State);
365 return true;
366 }
367 return false;
368}
369
370void GenericTaintChecker::addSourcesPost(const CallExpr *CE,
371 CheckerContext &C) const {
Anna Zaks5c5bf9b2011-11-16 19:58:13 +0000372 // Define the attack surface.
373 // Set the evaluation function by switching on the callee name.
Jordan Rose6cd16c52012-07-10 23:13:01 +0000374 const FunctionDecl *FDecl = C.getCalleeDecl(CE);
375 if (!FDecl || FDecl->getKind() != Decl::Function)
376 return;
377
378 StringRef Name = C.getCalleeName(FDecl);
Anna Zaksb3fa8d72012-01-12 02:22:34 +0000379 if (Name.empty())
380 return;
Artem Dergachevb68cb542018-12-19 23:35:08 +0000381 FnCheck evalFunction =
382 llvm::StringSwitch<FnCheck>(Name)
383 .Case("scanf", &GenericTaintChecker::postScanf)
384 // TODO: Add support for vfscanf & family.
385 .Case("getchar", &GenericTaintChecker::postRetTaint)
386 .Case("getchar_unlocked", &GenericTaintChecker::postRetTaint)
387 .Case("getenv", &GenericTaintChecker::postRetTaint)
388 .Case("fopen", &GenericTaintChecker::postRetTaint)
389 .Case("fdopen", &GenericTaintChecker::postRetTaint)
390 .Case("freopen", &GenericTaintChecker::postRetTaint)
391 .Case("getch", &GenericTaintChecker::postRetTaint)
392 .Case("wgetch", &GenericTaintChecker::postRetTaint)
393 .Case("socket", &GenericTaintChecker::postSocket)
394 .Default(nullptr);
Anna Zaks5c5bf9b2011-11-16 19:58:13 +0000395
396 // If the callee isn't defined, it is not of security concern.
397 // Check and evaluate the call.
Craig Topper0dbb7832014-05-27 02:45:47 +0000398 ProgramStateRef State = nullptr;
Anna Zaks5c5bf9b2011-11-16 19:58:13 +0000399 if (evalFunction)
Anna Zaks3b0ab202011-12-17 00:26:34 +0000400 State = (this->*evalFunction)(CE, C);
401 if (!State)
402 return;
Anna Zaks5c5bf9b2011-11-16 19:58:13 +0000403
Anna Zaks3b0ab202011-12-17 00:26:34 +0000404 C.addTransition(State);
Anna Zaks5c5bf9b2011-11-16 19:58:13 +0000405}
Anna Zaks457c6872011-11-18 02:26:36 +0000406
Artem Dergachevb68cb542018-12-19 23:35:08 +0000407bool GenericTaintChecker::checkPre(const CallExpr *CE,
408 CheckerContext &C) const {
Anna Zaks126a2ef2012-01-07 02:33:10 +0000409
410 if (checkUncontrolledFormatString(CE, C))
411 return true;
412
Anna Zaks560dbe92012-01-18 02:45:11 +0000413 const FunctionDecl *FDecl = C.getCalleeDecl(CE);
Jordan Rose6cd16c52012-07-10 23:13:01 +0000414 if (!FDecl || FDecl->getKind() != Decl::Function)
415 return false;
416
Anna Zaks560dbe92012-01-18 02:45:11 +0000417 StringRef Name = C.getCalleeName(FDecl);
Anna Zaks0244cd72012-01-14 02:48:40 +0000418 if (Name.empty())
419 return false;
420
421 if (checkSystemCall(CE, Name, C))
422 return true;
423
Anna Zaks560dbe92012-01-18 02:45:11 +0000424 if (checkTaintedBufferSize(CE, FDecl, C))
425 return true;
426
Anna Zaks126a2ef2012-01-07 02:33:10 +0000427 return false;
428}
429
Artem Dergacheveed7a312017-05-29 15:42:56 +0000430Optional<SVal> GenericTaintChecker::getPointedToSVal(CheckerContext &C,
Artem Dergachev3ef5deb2017-12-12 02:27:55 +0000431 const Expr *Arg) {
Ted Kremenek49b1e382012-01-26 21:29:00 +0000432 ProgramStateRef State = C.getState();
George Karpenkovd703ec92018-01-17 20:27:29 +0000433 SVal AddrVal = C.getSVal(Arg->IgnoreParens());
Anna Zakse48ee502011-12-16 18:28:50 +0000434 if (AddrVal.isUnknownOrUndef())
Artem Dergacheveed7a312017-05-29 15:42:56 +0000435 return None;
Anna Zaks7c96b7d2011-12-11 18:43:40 +0000436
David Blaikie05785d12013-02-20 22:23:23 +0000437 Optional<Loc> AddrLoc = AddrVal.getAs<Loc>();
Anna Zaks7f6a6b72012-01-18 02:45:13 +0000438 if (!AddrLoc)
Artem Dergacheveed7a312017-05-29 15:42:56 +0000439 return None;
Anna Zaks457c6872011-11-18 02:26:36 +0000440
Artem Dergachev3ef5deb2017-12-12 02:27:55 +0000441 QualType ArgTy = Arg->getType().getCanonicalType();
442 if (!ArgTy->isPointerType())
443 return None;
444
445 QualType ValTy = ArgTy->getPointeeType();
446
447 // Do not dereference void pointers. Treat them as byte pointers instead.
448 // FIXME: we might want to consider more than just the first byte.
449 if (ValTy->isVoidType())
450 ValTy = C.getASTContext().CharTy;
451
452 return State->getSVal(*AddrLoc, ValTy);
Anna Zaks5c5bf9b2011-11-16 19:58:13 +0000453}
454
Ted Kremenek3a0678e2015-09-08 03:50:52 +0000455ProgramStateRef
Anna Zaks7f6a6b72012-01-18 02:45:13 +0000456GenericTaintChecker::TaintPropagationRule::process(const CallExpr *CE,
457 CheckerContext &C) const {
Ted Kremenek49b1e382012-01-26 21:29:00 +0000458 ProgramStateRef State = C.getState();
Anna Zaks3666d2c2012-01-17 00:37:02 +0000459
460 // Check for taint in arguments.
461 bool IsTainted = false;
Artem Dergachevb68cb542018-12-19 23:35:08 +0000462 for (ArgVector::const_iterator I = SrcArgs.begin(), E = SrcArgs.end(); I != E;
463 ++I) {
Anna Zaks3666d2c2012-01-17 00:37:02 +0000464 unsigned ArgNum = *I;
465
466 if (ArgNum == InvalidArgIndex) {
Anna Zaks5d324e52012-01-18 02:45:07 +0000467 // Check if any of the arguments is tainted, but skip the
468 // destination arguments.
469 for (unsigned int i = 0; i < CE->getNumArgs(); ++i) {
Anna Zaks7f6a6b72012-01-18 02:45:13 +0000470 if (isDestinationArgument(i))
Anna Zaks5d324e52012-01-18 02:45:07 +0000471 continue;
Anna Zaksbf740512012-01-24 19:32:25 +0000472 if ((IsTainted = isTaintedOrPointsToTainted(CE->getArg(i), State, C)))
Anna Zaks3666d2c2012-01-17 00:37:02 +0000473 break;
Anna Zaks5d324e52012-01-18 02:45:07 +0000474 }
Anna Zaks3666d2c2012-01-17 00:37:02 +0000475 break;
476 }
477
Anna Zaksb508d292012-04-10 23:41:11 +0000478 if (CE->getNumArgs() < (ArgNum + 1))
479 return State;
Anna Zaksbf740512012-01-24 19:32:25 +0000480 if ((IsTainted = isTaintedOrPointsToTainted(CE->getArg(ArgNum), State, C)))
Anna Zaks3666d2c2012-01-17 00:37:02 +0000481 break;
482 }
483 if (!IsTainted)
484 return State;
485
486 // Mark the arguments which should be tainted after the function returns.
Artem Dergachevb68cb542018-12-19 23:35:08 +0000487 for (ArgVector::const_iterator I = DstArgs.begin(), E = DstArgs.end(); I != E;
488 ++I) {
Anna Zaks3666d2c2012-01-17 00:37:02 +0000489 unsigned ArgNum = *I;
490
491 // Should we mark all arguments as tainted?
492 if (ArgNum == InvalidArgIndex) {
493 // For all pointer and references that were passed in:
494 // If they are not pointing to const data, mark data as tainted.
495 // TODO: So far we are just going one level down; ideally we'd need to
496 // recurse here.
497 for (unsigned int i = 0; i < CE->getNumArgs(); ++i) {
498 const Expr *Arg = CE->getArg(i);
499 // Process pointer argument.
500 const Type *ArgTy = Arg->getType().getTypePtr();
501 QualType PType = ArgTy->getPointeeType();
Artem Dergachevb68cb542018-12-19 23:35:08 +0000502 if ((!PType.isNull() && !PType.isConstQualified()) ||
503 (ArgTy->isReferenceType() && !Arg->getType().isConstQualified()))
Anna Zaks3666d2c2012-01-17 00:37:02 +0000504 State = State->add<TaintArgsOnPostVisit>(i);
505 }
506 continue;
507 }
508
509 // Should mark the return value?
510 if (ArgNum == ReturnValueIndex) {
511 State = State->add<TaintArgsOnPostVisit>(ReturnValueIndex);
512 continue;
513 }
514
515 // Mark the given argument.
516 assert(ArgNum < CE->getNumArgs());
517 State = State->add<TaintArgsOnPostVisit>(ArgNum);
518 }
519
520 return State;
521}
522
Anna Zaksb3fa8d72012-01-12 02:22:34 +0000523// If argument 0 (file descriptor) is tainted, all arguments except for arg 0
524// and arg 1 should get taint.
Ted Kremenek49b1e382012-01-26 21:29:00 +0000525ProgramStateRef GenericTaintChecker::preFscanf(const CallExpr *CE,
Artem Dergachevb68cb542018-12-19 23:35:08 +0000526 CheckerContext &C) const {
Anna Zaks3b0ab202011-12-17 00:26:34 +0000527 assert(CE->getNumArgs() >= 2);
Ted Kremenek49b1e382012-01-26 21:29:00 +0000528 ProgramStateRef State = C.getState();
Anna Zaks3b0ab202011-12-17 00:26:34 +0000529
530 // Check is the file descriptor is tainted.
Ted Kremenek632e3b72012-01-06 22:09:28 +0000531 if (State->isTainted(CE->getArg(0), C.getLocationContext()) ||
Anna Zaksb3fa8d72012-01-12 02:22:34 +0000532 isStdin(CE->getArg(0), C)) {
533 // All arguments except for the first two should get taint.
534 for (unsigned int i = 2; i < CE->getNumArgs(); ++i)
Artem Dergachevb68cb542018-12-19 23:35:08 +0000535 State = State->add<TaintArgsOnPostVisit>(i);
Anna Zaksb3fa8d72012-01-12 02:22:34 +0000536 return State;
537 }
538
Craig Topper0dbb7832014-05-27 02:45:47 +0000539 return nullptr;
Anna Zaks3b0ab202011-12-17 00:26:34 +0000540}
541
Anna Zaks3b754b22012-01-20 00:11:19 +0000542// If argument 0(protocol domain) is network, the return value should get taint.
Ted Kremenek49b1e382012-01-26 21:29:00 +0000543ProgramStateRef GenericTaintChecker::postSocket(const CallExpr *CE,
Anna Zaksb508d292012-04-10 23:41:11 +0000544 CheckerContext &C) const {
Ted Kremenek49b1e382012-01-26 21:29:00 +0000545 ProgramStateRef State = C.getState();
Anna Zaksb508d292012-04-10 23:41:11 +0000546 if (CE->getNumArgs() < 3)
547 return State;
Anna Zaks3b754b22012-01-20 00:11:19 +0000548
549 SourceLocation DomLoc = CE->getArg(0)->getExprLoc();
550 StringRef DomName = C.getMacroNameOrSpelling(DomLoc);
551 // White list the internal communication protocols.
552 if (DomName.equals("AF_SYSTEM") || DomName.equals("AF_LOCAL") ||
553 DomName.equals("AF_UNIX") || DomName.equals("AF_RESERVED_36"))
554 return State;
555 State = State->addTaint(CE, C.getLocationContext());
556 return State;
557}
558
Ted Kremenek49b1e382012-01-26 21:29:00 +0000559ProgramStateRef GenericTaintChecker::postScanf(const CallExpr *CE,
Artem Dergachevb68cb542018-12-19 23:35:08 +0000560 CheckerContext &C) const {
Ted Kremenek49b1e382012-01-26 21:29:00 +0000561 ProgramStateRef State = C.getState();
Anna Zaksb508d292012-04-10 23:41:11 +0000562 if (CE->getNumArgs() < 2)
563 return State;
564
Anna Zaks5c5bf9b2011-11-16 19:58:13 +0000565 // All arguments except for the very first one should get taint.
566 for (unsigned int i = 1; i < CE->getNumArgs(); ++i) {
567 // The arguments are pointer arguments. The data they are pointing at is
568 // tainted after the call.
Artem Dergachevb68cb542018-12-19 23:35:08 +0000569 const Expr *Arg = CE->getArg(i);
Artem Dergacheveed7a312017-05-29 15:42:56 +0000570 Optional<SVal> V = getPointedToSVal(C, Arg);
571 if (V)
572 State = State->addTaint(*V);
Anna Zakseefc0e92011-12-14 00:56:02 +0000573 }
Anna Zaks3b0ab202011-12-17 00:26:34 +0000574 return State;
Anna Zaks5c5bf9b2011-11-16 19:58:13 +0000575}
576
Ted Kremenek49b1e382012-01-26 21:29:00 +0000577ProgramStateRef GenericTaintChecker::postRetTaint(const CallExpr *CE,
Anna Zaksb508d292012-04-10 23:41:11 +0000578 CheckerContext &C) const {
Ted Kremenek632e3b72012-01-06 22:09:28 +0000579 return C.getState()->addTaint(CE, C.getLocationContext());
Anna Zaks5c5bf9b2011-11-16 19:58:13 +0000580}
581
Anna Zaksbf740512012-01-24 19:32:25 +0000582bool GenericTaintChecker::isStdin(const Expr *E, CheckerContext &C) {
Ted Kremenek49b1e382012-01-26 21:29:00 +0000583 ProgramStateRef State = C.getState();
George Karpenkovd703ec92018-01-17 20:27:29 +0000584 SVal Val = C.getSVal(E);
Anna Zaks099fe3f2011-12-14 00:56:18 +0000585
Anna Zakse48ee502011-12-16 18:28:50 +0000586 // stdin is a pointer, so it would be a region.
587 const MemRegion *MemReg = Val.getAsRegion();
588
589 // The region should be symbolic, we do not know it's value.
590 const SymbolicRegion *SymReg = dyn_cast_or_null<SymbolicRegion>(MemReg);
591 if (!SymReg)
Anna Zaks099fe3f2011-12-14 00:56:18 +0000592 return false;
593
Anna Zakse48ee502011-12-16 18:28:50 +0000594 // Get it's symbol and find the declaration region it's pointing to.
Artem Dergachevb68cb542018-12-19 23:35:08 +0000595 const SymbolRegionValue *Sm =
596 dyn_cast<SymbolRegionValue>(SymReg->getSymbol());
Anna Zakse48ee502011-12-16 18:28:50 +0000597 if (!Sm)
598 return false;
599 const DeclRegion *DeclReg = dyn_cast_or_null<DeclRegion>(Sm->getRegion());
600 if (!DeclReg)
601 return false;
Anna Zaks099fe3f2011-12-14 00:56:18 +0000602
Anna Zakse48ee502011-12-16 18:28:50 +0000603 // This region corresponds to a declaration, find out if it's a global/extern
604 // variable named stdin with the proper type.
605 if (const VarDecl *D = dyn_cast_or_null<VarDecl>(DeclReg->getDecl())) {
606 D = D->getCanonicalDecl();
607 if ((D->getName().find("stdin") != StringRef::npos) && D->isExternC())
Artem Dergachevb68cb542018-12-19 23:35:08 +0000608 if (const PointerType *PtrTy =
Anna Zakse48ee502011-12-16 18:28:50 +0000609 dyn_cast<PointerType>(D->getType().getTypePtr()))
Artem Dergachevb68cb542018-12-19 23:35:08 +0000610 if (PtrTy->getPointeeType().getCanonicalType() ==
611 C.getASTContext().getFILEType().getCanonicalType())
612 return true;
Anna Zakse48ee502011-12-16 18:28:50 +0000613 }
Anna Zaks099fe3f2011-12-14 00:56:18 +0000614 return false;
615}
616
Anna Zaks126a2ef2012-01-07 02:33:10 +0000617static bool getPrintfFormatArgumentNum(const CallExpr *CE,
618 const CheckerContext &C,
619 unsigned int &ArgNum) {
620 // Find if the function contains a format string argument.
621 // Handles: fprintf, printf, sprintf, snprintf, vfprintf, vprintf, vsprintf,
622 // vsnprintf, syslog, custom annotated functions.
623 const FunctionDecl *FDecl = C.getCalleeDecl(CE);
624 if (!FDecl)
625 return false;
Aaron Ballmanbe22bcb2014-03-10 17:08:28 +0000626 for (const auto *Format : FDecl->specific_attrs<FormatAttr>()) {
Anna Zaks126a2ef2012-01-07 02:33:10 +0000627 ArgNum = Format->getFormatIdx() - 1;
Artem Dergachevb68cb542018-12-19 23:35:08 +0000628 if ((Format->getType()->getName() == "printf") && CE->getNumArgs() > ArgNum)
Anna Zaks126a2ef2012-01-07 02:33:10 +0000629 return true;
630 }
631
632 // Or if a function is named setproctitle (this is a heuristic).
633 if (C.getCalleeName(CE).find("setproctitle") != StringRef::npos) {
634 ArgNum = 0;
635 return true;
636 }
637
638 return false;
639}
640
Anna Zaks0244cd72012-01-14 02:48:40 +0000641bool GenericTaintChecker::generateReportIfTainted(const Expr *E,
642 const char Msg[],
643 CheckerContext &C) const {
644 assert(E);
645
646 // Check for taint.
Ted Kremenek49b1e382012-01-26 21:29:00 +0000647 ProgramStateRef State = C.getState();
Artem Dergacheveed7a312017-05-29 15:42:56 +0000648 Optional<SVal> PointedToSVal = getPointedToSVal(C, E);
Anna Zaksd4e43ae2017-03-09 00:01:07 +0000649 SVal TaintedSVal;
Artem Dergacheveed7a312017-05-29 15:42:56 +0000650 if (PointedToSVal && State->isTainted(*PointedToSVal))
651 TaintedSVal = *PointedToSVal;
Anna Zaksd4e43ae2017-03-09 00:01:07 +0000652 else if (State->isTainted(E, C.getLocationContext()))
653 TaintedSVal = C.getSVal(E);
654 else
Anna Zaks0244cd72012-01-14 02:48:40 +0000655 return false;
656
657 // Generate diagnostic.
Devin Coughline39bd402015-09-16 22:03:05 +0000658 if (ExplodedNode *N = C.generateNonFatalErrorNode()) {
Anna Zaks0244cd72012-01-14 02:48:40 +0000659 initBugType();
Aaron Ballman8d3a7a52015-06-23 13:15:32 +0000660 auto report = llvm::make_unique<BugReport>(*BT, Msg, N);
Anna Zaks0244cd72012-01-14 02:48:40 +0000661 report->addRange(E->getSourceRange());
Anna Zaksd4e43ae2017-03-09 00:01:07 +0000662 report->addVisitor(llvm::make_unique<TaintBugVisitor>(TaintedSVal));
Aaron Ballman8d3a7a52015-06-23 13:15:32 +0000663 C.emitReport(std::move(report));
Anna Zaks0244cd72012-01-14 02:48:40 +0000664 return true;
665 }
666 return false;
667}
668
Artem Dergachevb68cb542018-12-19 23:35:08 +0000669bool GenericTaintChecker::checkUncontrolledFormatString(
670 const CallExpr *CE, CheckerContext &C) const {
Anna Zaks126a2ef2012-01-07 02:33:10 +0000671 // Check if the function contains a format string argument.
672 unsigned int ArgNum = 0;
673 if (!getPrintfFormatArgumentNum(CE, C, ArgNum))
674 return false;
675
Artem Dergachevb68cb542018-12-19 23:35:08 +0000676 // If either the format string content or the pointer itself are tainted,
677 // warn.
Alexander Kornienko9c104902015-12-28 13:06:58 +0000678 return generateReportIfTainted(CE->getArg(ArgNum),
679 MsgUncontrolledFormatString, C);
Anna Zaks0244cd72012-01-14 02:48:40 +0000680}
681
Artem Dergachevb68cb542018-12-19 23:35:08 +0000682bool GenericTaintChecker::checkSystemCall(const CallExpr *CE, StringRef Name,
Anna Zaks0244cd72012-01-14 02:48:40 +0000683 CheckerContext &C) const {
Ted Kremenek3a0678e2015-09-08 03:50:52 +0000684 // TODO: It might make sense to run this check on demand. In some cases,
685 // we should check if the environment has been cleansed here. We also might
Anna Zaksbf740512012-01-24 19:32:25 +0000686 // need to know if the user was reset before these calls(seteuid).
Anna Zaks0244cd72012-01-14 02:48:40 +0000687 unsigned ArgNum = llvm::StringSwitch<unsigned>(Name)
Artem Dergachevb68cb542018-12-19 23:35:08 +0000688 .Case("system", 0)
689 .Case("popen", 0)
690 .Case("execl", 0)
691 .Case("execle", 0)
692 .Case("execlp", 0)
693 .Case("execv", 0)
694 .Case("execvp", 0)
695 .Case("execvP", 0)
696 .Case("execve", 0)
697 .Case("dlopen", 0)
698 .Default(UINT_MAX);
Anna Zaks0244cd72012-01-14 02:48:40 +0000699
Anna Zaksb508d292012-04-10 23:41:11 +0000700 if (ArgNum == UINT_MAX || CE->getNumArgs() < (ArgNum + 1))
Anna Zaks0244cd72012-01-14 02:48:40 +0000701 return false;
702
Alexander Kornienko9c104902015-12-28 13:06:58 +0000703 return generateReportIfTainted(CE->getArg(ArgNum), MsgSanitizeSystemArgs, C);
Anna Zaks126a2ef2012-01-07 02:33:10 +0000704}
705
Anna Zaks560dbe92012-01-18 02:45:11 +0000706// TODO: Should this check be a part of the CString checker?
707// If yes, should taint be a global setting?
708bool GenericTaintChecker::checkTaintedBufferSize(const CallExpr *CE,
709 const FunctionDecl *FDecl,
710 CheckerContext &C) const {
711 // If the function has a buffer size argument, set ArgNum.
712 unsigned ArgNum = InvalidArgIndex;
713 unsigned BId = 0;
Artem Dergachevb68cb542018-12-19 23:35:08 +0000714 if ((BId = FDecl->getMemoryFunctionKind()))
715 switch (BId) {
Anna Zaks560dbe92012-01-18 02:45:11 +0000716 case Builtin::BImemcpy:
717 case Builtin::BImemmove:
718 case Builtin::BIstrncpy:
719 ArgNum = 2;
720 break;
721 case Builtin::BIstrndup:
722 ArgNum = 1;
723 break;
724 default:
725 break;
726 };
727
728 if (ArgNum == InvalidArgIndex) {
729 if (C.isCLibraryFunction(FDecl, "malloc") ||
730 C.isCLibraryFunction(FDecl, "calloc") ||
731 C.isCLibraryFunction(FDecl, "alloca"))
732 ArgNum = 0;
733 else if (C.isCLibraryFunction(FDecl, "memccpy"))
734 ArgNum = 3;
735 else if (C.isCLibraryFunction(FDecl, "realloc"))
736 ArgNum = 1;
737 else if (C.isCLibraryFunction(FDecl, "bcopy"))
738 ArgNum = 2;
739 }
740
Alexander Kornienko9c104902015-12-28 13:06:58 +0000741 return ArgNum != InvalidArgIndex && CE->getNumArgs() > ArgNum &&
742 generateReportIfTainted(CE->getArg(ArgNum), MsgTaintedBufferSize, C);
Anna Zaks560dbe92012-01-18 02:45:11 +0000743}
744
Anna Zaks5c5bf9b2011-11-16 19:58:13 +0000745void ento::registerGenericTaintChecker(CheckerManager &mgr) {
746 mgr.registerChecker<GenericTaintChecker>();
747}