xref: /freebsd/contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/GenericTaintChecker.cpp (revision 0b57cec536236d46e3dba9bd041533462f33dbb7)
1*0b57cec5SDimitry Andric //== GenericTaintChecker.cpp ----------------------------------- -*- C++ -*--=//
2*0b57cec5SDimitry Andric //
3*0b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*0b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5*0b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6*0b57cec5SDimitry Andric //
7*0b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
8*0b57cec5SDimitry Andric //
9*0b57cec5SDimitry Andric // This checker defines the attack surface for generic taint propagation.
10*0b57cec5SDimitry Andric //
11*0b57cec5SDimitry Andric // The taint information produced by it might be useful to other checkers. For
12*0b57cec5SDimitry Andric // example, checkers should report errors which involve tainted data more
13*0b57cec5SDimitry Andric // aggressively, even if the involved symbols are under constrained.
14*0b57cec5SDimitry Andric //
15*0b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
16*0b57cec5SDimitry Andric 
17*0b57cec5SDimitry Andric #include "Taint.h"
18*0b57cec5SDimitry Andric #include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h"
19*0b57cec5SDimitry Andric #include "clang/AST/Attr.h"
20*0b57cec5SDimitry Andric #include "clang/Basic/Builtins.h"
21*0b57cec5SDimitry Andric #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
22*0b57cec5SDimitry Andric #include "clang/StaticAnalyzer/Core/Checker.h"
23*0b57cec5SDimitry Andric #include "clang/StaticAnalyzer/Core/CheckerManager.h"
24*0b57cec5SDimitry Andric #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
25*0b57cec5SDimitry Andric #include "clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h"
26*0b57cec5SDimitry Andric #include <climits>
27*0b57cec5SDimitry Andric #include <initializer_list>
28*0b57cec5SDimitry Andric #include <utility>
29*0b57cec5SDimitry Andric 
30*0b57cec5SDimitry Andric using namespace clang;
31*0b57cec5SDimitry Andric using namespace ento;
32*0b57cec5SDimitry Andric using namespace taint;
33*0b57cec5SDimitry Andric 
34*0b57cec5SDimitry Andric namespace {
35*0b57cec5SDimitry Andric class GenericTaintChecker
36*0b57cec5SDimitry Andric     : public Checker<check::PostStmt<CallExpr>, check::PreStmt<CallExpr>> {
37*0b57cec5SDimitry Andric public:
38*0b57cec5SDimitry Andric   static void *getTag() {
39*0b57cec5SDimitry Andric     static int Tag;
40*0b57cec5SDimitry Andric     return &Tag;
41*0b57cec5SDimitry Andric   }
42*0b57cec5SDimitry Andric 
43*0b57cec5SDimitry Andric   void checkPostStmt(const CallExpr *CE, CheckerContext &C) const;
44*0b57cec5SDimitry Andric 
45*0b57cec5SDimitry Andric   void checkPreStmt(const CallExpr *CE, CheckerContext &C) const;
46*0b57cec5SDimitry Andric 
47*0b57cec5SDimitry Andric   void printState(raw_ostream &Out, ProgramStateRef State,
48*0b57cec5SDimitry Andric                   const char *NL, const char *Sep) const override;
49*0b57cec5SDimitry Andric 
50*0b57cec5SDimitry Andric private:
51*0b57cec5SDimitry Andric   static const unsigned InvalidArgIndex = UINT_MAX;
52*0b57cec5SDimitry Andric   /// Denotes the return vale.
53*0b57cec5SDimitry Andric   static const unsigned ReturnValueIndex = UINT_MAX - 1;
54*0b57cec5SDimitry Andric 
55*0b57cec5SDimitry Andric   mutable std::unique_ptr<BugType> BT;
56*0b57cec5SDimitry Andric   void initBugType() const {
57*0b57cec5SDimitry Andric     if (!BT)
58*0b57cec5SDimitry Andric       BT.reset(new BugType(this, "Use of Untrusted Data", "Untrusted Data"));
59*0b57cec5SDimitry Andric   }
60*0b57cec5SDimitry Andric 
61*0b57cec5SDimitry Andric   /// Catch taint related bugs. Check if tainted data is passed to a
62*0b57cec5SDimitry Andric   /// system call etc.
63*0b57cec5SDimitry Andric   bool checkPre(const CallExpr *CE, CheckerContext &C) const;
64*0b57cec5SDimitry Andric 
65*0b57cec5SDimitry Andric   /// Add taint sources on a pre-visit.
66*0b57cec5SDimitry Andric   void addSourcesPre(const CallExpr *CE, CheckerContext &C) const;
67*0b57cec5SDimitry Andric 
68*0b57cec5SDimitry Andric   /// Propagate taint generated at pre-visit.
69*0b57cec5SDimitry Andric   bool propagateFromPre(const CallExpr *CE, CheckerContext &C) const;
70*0b57cec5SDimitry Andric 
71*0b57cec5SDimitry Andric   /// Check if the region the expression evaluates to is the standard input,
72*0b57cec5SDimitry Andric   /// and thus, is tainted.
73*0b57cec5SDimitry Andric   static bool isStdin(const Expr *E, CheckerContext &C);
74*0b57cec5SDimitry Andric 
75*0b57cec5SDimitry Andric   /// Given a pointer argument, return the value it points to.
76*0b57cec5SDimitry Andric   static Optional<SVal> getPointedToSVal(CheckerContext &C, const Expr *Arg);
77*0b57cec5SDimitry Andric 
78*0b57cec5SDimitry Andric   /// Check for CWE-134: Uncontrolled Format String.
79*0b57cec5SDimitry Andric   static const char MsgUncontrolledFormatString[];
80*0b57cec5SDimitry Andric   bool checkUncontrolledFormatString(const CallExpr *CE,
81*0b57cec5SDimitry Andric                                      CheckerContext &C) const;
82*0b57cec5SDimitry Andric 
83*0b57cec5SDimitry Andric   /// Check for:
84*0b57cec5SDimitry Andric   /// CERT/STR02-C. "Sanitize data passed to complex subsystems"
85*0b57cec5SDimitry Andric   /// CWE-78, "Failure to Sanitize Data into an OS Command"
86*0b57cec5SDimitry Andric   static const char MsgSanitizeSystemArgs[];
87*0b57cec5SDimitry Andric   bool checkSystemCall(const CallExpr *CE, StringRef Name,
88*0b57cec5SDimitry Andric                        CheckerContext &C) const;
89*0b57cec5SDimitry Andric 
90*0b57cec5SDimitry Andric   /// Check if tainted data is used as a buffer size ins strn.. functions,
91*0b57cec5SDimitry Andric   /// and allocators.
92*0b57cec5SDimitry Andric   static const char MsgTaintedBufferSize[];
93*0b57cec5SDimitry Andric   bool checkTaintedBufferSize(const CallExpr *CE, const FunctionDecl *FDecl,
94*0b57cec5SDimitry Andric                               CheckerContext &C) const;
95*0b57cec5SDimitry Andric 
96*0b57cec5SDimitry Andric   /// Generate a report if the expression is tainted or points to tainted data.
97*0b57cec5SDimitry Andric   bool generateReportIfTainted(const Expr *E, const char Msg[],
98*0b57cec5SDimitry Andric                                CheckerContext &C) const;
99*0b57cec5SDimitry Andric 
100*0b57cec5SDimitry Andric   using ArgVector = SmallVector<unsigned, 2>;
101*0b57cec5SDimitry Andric 
102*0b57cec5SDimitry Andric   /// A struct used to specify taint propagation rules for a function.
103*0b57cec5SDimitry Andric   ///
104*0b57cec5SDimitry Andric   /// If any of the possible taint source arguments is tainted, all of the
105*0b57cec5SDimitry Andric   /// destination arguments should also be tainted. Use InvalidArgIndex in the
106*0b57cec5SDimitry Andric   /// src list to specify that all of the arguments can introduce taint. Use
107*0b57cec5SDimitry Andric   /// InvalidArgIndex in the dst arguments to signify that all the non-const
108*0b57cec5SDimitry Andric   /// pointer and reference arguments might be tainted on return. If
109*0b57cec5SDimitry Andric   /// ReturnValueIndex is added to the dst list, the return value will be
110*0b57cec5SDimitry Andric   /// tainted.
111*0b57cec5SDimitry Andric   struct TaintPropagationRule {
112*0b57cec5SDimitry Andric     enum class VariadicType { None, Src, Dst };
113*0b57cec5SDimitry Andric 
114*0b57cec5SDimitry Andric     using PropagationFuncType = bool (*)(bool IsTainted, const CallExpr *,
115*0b57cec5SDimitry Andric                                          CheckerContext &C);
116*0b57cec5SDimitry Andric 
117*0b57cec5SDimitry Andric     /// List of arguments which can be taint sources and should be checked.
118*0b57cec5SDimitry Andric     ArgVector SrcArgs;
119*0b57cec5SDimitry Andric     /// List of arguments which should be tainted on function return.
120*0b57cec5SDimitry Andric     ArgVector DstArgs;
121*0b57cec5SDimitry Andric     /// Index for the first variadic parameter if exist.
122*0b57cec5SDimitry Andric     unsigned VariadicIndex;
123*0b57cec5SDimitry Andric     /// Show when a function has variadic parameters. If it has, it marks all
124*0b57cec5SDimitry Andric     /// of them as source or destination.
125*0b57cec5SDimitry Andric     VariadicType VarType;
126*0b57cec5SDimitry Andric     /// Special function for tainted source determination. If defined, it can
127*0b57cec5SDimitry Andric     /// override the default behavior.
128*0b57cec5SDimitry Andric     PropagationFuncType PropagationFunc;
129*0b57cec5SDimitry Andric 
130*0b57cec5SDimitry Andric     TaintPropagationRule()
131*0b57cec5SDimitry Andric         : VariadicIndex(InvalidArgIndex), VarType(VariadicType::None),
132*0b57cec5SDimitry Andric           PropagationFunc(nullptr) {}
133*0b57cec5SDimitry Andric 
134*0b57cec5SDimitry Andric     TaintPropagationRule(std::initializer_list<unsigned> &&Src,
135*0b57cec5SDimitry Andric                          std::initializer_list<unsigned> &&Dst,
136*0b57cec5SDimitry Andric                          VariadicType Var = VariadicType::None,
137*0b57cec5SDimitry Andric                          unsigned VarIndex = InvalidArgIndex,
138*0b57cec5SDimitry Andric                          PropagationFuncType Func = nullptr)
139*0b57cec5SDimitry Andric         : SrcArgs(std::move(Src)), DstArgs(std::move(Dst)),
140*0b57cec5SDimitry Andric           VariadicIndex(VarIndex), VarType(Var), PropagationFunc(Func) {}
141*0b57cec5SDimitry Andric 
142*0b57cec5SDimitry Andric     /// Get the propagation rule for a given function.
143*0b57cec5SDimitry Andric     static TaintPropagationRule
144*0b57cec5SDimitry Andric     getTaintPropagationRule(const FunctionDecl *FDecl, StringRef Name,
145*0b57cec5SDimitry Andric                             CheckerContext &C);
146*0b57cec5SDimitry Andric 
147*0b57cec5SDimitry Andric     void addSrcArg(unsigned A) { SrcArgs.push_back(A); }
148*0b57cec5SDimitry Andric     void addDstArg(unsigned A) { DstArgs.push_back(A); }
149*0b57cec5SDimitry Andric 
150*0b57cec5SDimitry Andric     bool isNull() const {
151*0b57cec5SDimitry Andric       return SrcArgs.empty() && DstArgs.empty() &&
152*0b57cec5SDimitry Andric              VariadicType::None == VarType;
153*0b57cec5SDimitry Andric     }
154*0b57cec5SDimitry Andric 
155*0b57cec5SDimitry Andric     bool isDestinationArgument(unsigned ArgNum) const {
156*0b57cec5SDimitry Andric       return (llvm::find(DstArgs, ArgNum) != DstArgs.end());
157*0b57cec5SDimitry Andric     }
158*0b57cec5SDimitry Andric 
159*0b57cec5SDimitry Andric     static bool isTaintedOrPointsToTainted(const Expr *E, ProgramStateRef State,
160*0b57cec5SDimitry Andric                                            CheckerContext &C) {
161*0b57cec5SDimitry Andric       if (isTainted(State, E, C.getLocationContext()) || isStdin(E, C))
162*0b57cec5SDimitry Andric         return true;
163*0b57cec5SDimitry Andric 
164*0b57cec5SDimitry Andric       if (!E->getType().getTypePtr()->isPointerType())
165*0b57cec5SDimitry Andric         return false;
166*0b57cec5SDimitry Andric 
167*0b57cec5SDimitry Andric       Optional<SVal> V = getPointedToSVal(C, E);
168*0b57cec5SDimitry Andric       return (V && isTainted(State, *V));
169*0b57cec5SDimitry Andric     }
170*0b57cec5SDimitry Andric 
171*0b57cec5SDimitry Andric     /// Pre-process a function which propagates taint according to the
172*0b57cec5SDimitry Andric     /// taint rule.
173*0b57cec5SDimitry Andric     ProgramStateRef process(const CallExpr *CE, CheckerContext &C) const;
174*0b57cec5SDimitry Andric 
175*0b57cec5SDimitry Andric     // Functions for custom taintedness propagation.
176*0b57cec5SDimitry Andric     static bool postSocket(bool IsTainted, const CallExpr *CE,
177*0b57cec5SDimitry Andric                            CheckerContext &C);
178*0b57cec5SDimitry Andric   };
179*0b57cec5SDimitry Andric };
180*0b57cec5SDimitry Andric 
181*0b57cec5SDimitry Andric const unsigned GenericTaintChecker::ReturnValueIndex;
182*0b57cec5SDimitry Andric const unsigned GenericTaintChecker::InvalidArgIndex;
183*0b57cec5SDimitry Andric 
184*0b57cec5SDimitry Andric const char GenericTaintChecker::MsgUncontrolledFormatString[] =
185*0b57cec5SDimitry Andric     "Untrusted data is used as a format string "
186*0b57cec5SDimitry Andric     "(CWE-134: Uncontrolled Format String)";
187*0b57cec5SDimitry Andric 
188*0b57cec5SDimitry Andric const char GenericTaintChecker::MsgSanitizeSystemArgs[] =
189*0b57cec5SDimitry Andric     "Untrusted data is passed to a system call "
190*0b57cec5SDimitry Andric     "(CERT/STR02-C. Sanitize data passed to complex subsystems)";
191*0b57cec5SDimitry Andric 
192*0b57cec5SDimitry Andric const char GenericTaintChecker::MsgTaintedBufferSize[] =
193*0b57cec5SDimitry Andric     "Untrusted data is used to specify the buffer size "
194*0b57cec5SDimitry Andric     "(CERT/STR31-C. Guarantee that storage for strings has sufficient space "
195*0b57cec5SDimitry Andric     "for character data and the null terminator)";
196*0b57cec5SDimitry Andric 
197*0b57cec5SDimitry Andric } // end of anonymous namespace
198*0b57cec5SDimitry Andric 
199*0b57cec5SDimitry Andric /// A set which is used to pass information from call pre-visit instruction
200*0b57cec5SDimitry Andric /// to the call post-visit. The values are unsigned integers, which are either
201*0b57cec5SDimitry Andric /// ReturnValueIndex, or indexes of the pointer/reference argument, which
202*0b57cec5SDimitry Andric /// points to data, which should be tainted on return.
203*0b57cec5SDimitry Andric REGISTER_SET_WITH_PROGRAMSTATE(TaintArgsOnPostVisit, unsigned)
204*0b57cec5SDimitry Andric 
205*0b57cec5SDimitry Andric GenericTaintChecker::TaintPropagationRule
206*0b57cec5SDimitry Andric GenericTaintChecker::TaintPropagationRule::getTaintPropagationRule(
207*0b57cec5SDimitry Andric     const FunctionDecl *FDecl, StringRef Name, CheckerContext &C) {
208*0b57cec5SDimitry Andric   // TODO: Currently, we might lose precision here: we always mark a return
209*0b57cec5SDimitry Andric   // value as tainted even if it's just a pointer, pointing to tainted data.
210*0b57cec5SDimitry Andric 
211*0b57cec5SDimitry Andric   // Check for exact name match for functions without builtin substitutes.
212*0b57cec5SDimitry Andric   TaintPropagationRule Rule =
213*0b57cec5SDimitry Andric       llvm::StringSwitch<TaintPropagationRule>(Name)
214*0b57cec5SDimitry Andric           // Source functions
215*0b57cec5SDimitry Andric           // TODO: Add support for vfscanf & family.
216*0b57cec5SDimitry Andric           .Case("fdopen", TaintPropagationRule({}, {ReturnValueIndex}))
217*0b57cec5SDimitry Andric           .Case("fopen", TaintPropagationRule({}, {ReturnValueIndex}))
218*0b57cec5SDimitry Andric           .Case("freopen", TaintPropagationRule({}, {ReturnValueIndex}))
219*0b57cec5SDimitry Andric           .Case("getch", TaintPropagationRule({}, {ReturnValueIndex}))
220*0b57cec5SDimitry Andric           .Case("getchar", TaintPropagationRule({}, {ReturnValueIndex}))
221*0b57cec5SDimitry Andric           .Case("getchar_unlocked", TaintPropagationRule({}, {ReturnValueIndex}))
222*0b57cec5SDimitry Andric           .Case("getenv", TaintPropagationRule({}, {ReturnValueIndex}))
223*0b57cec5SDimitry Andric           .Case("gets", TaintPropagationRule({}, {0, ReturnValueIndex}))
224*0b57cec5SDimitry Andric           .Case("scanf", TaintPropagationRule({}, {}, VariadicType::Dst, 1))
225*0b57cec5SDimitry Andric           .Case("socket",
226*0b57cec5SDimitry Andric                 TaintPropagationRule({}, {ReturnValueIndex}, VariadicType::None,
227*0b57cec5SDimitry Andric                                      InvalidArgIndex,
228*0b57cec5SDimitry Andric                                      &TaintPropagationRule::postSocket))
229*0b57cec5SDimitry Andric           .Case("wgetch", TaintPropagationRule({}, {ReturnValueIndex}))
230*0b57cec5SDimitry Andric           // Propagating functions
231*0b57cec5SDimitry Andric           .Case("atoi", TaintPropagationRule({0}, {ReturnValueIndex}))
232*0b57cec5SDimitry Andric           .Case("atol", TaintPropagationRule({0}, {ReturnValueIndex}))
233*0b57cec5SDimitry Andric           .Case("atoll", TaintPropagationRule({0}, {ReturnValueIndex}))
234*0b57cec5SDimitry Andric           .Case("fgetc", TaintPropagationRule({0}, {ReturnValueIndex}))
235*0b57cec5SDimitry Andric           .Case("fgetln", TaintPropagationRule({0}, {ReturnValueIndex}))
236*0b57cec5SDimitry Andric           .Case("fgets", TaintPropagationRule({2}, {0, ReturnValueIndex}))
237*0b57cec5SDimitry Andric           .Case("fscanf", TaintPropagationRule({0}, {}, VariadicType::Dst, 2))
238*0b57cec5SDimitry Andric           .Case("getc", TaintPropagationRule({0}, {ReturnValueIndex}))
239*0b57cec5SDimitry Andric           .Case("getc_unlocked", TaintPropagationRule({0}, {ReturnValueIndex}))
240*0b57cec5SDimitry Andric           .Case("getdelim", TaintPropagationRule({3}, {0}))
241*0b57cec5SDimitry Andric           .Case("getline", TaintPropagationRule({2}, {0}))
242*0b57cec5SDimitry Andric           .Case("getw", TaintPropagationRule({0}, {ReturnValueIndex}))
243*0b57cec5SDimitry Andric           .Case("pread",
244*0b57cec5SDimitry Andric                 TaintPropagationRule({0, 1, 2, 3}, {1, ReturnValueIndex}))
245*0b57cec5SDimitry Andric           .Case("read", TaintPropagationRule({0, 2}, {1, ReturnValueIndex}))
246*0b57cec5SDimitry Andric           .Case("strchr", TaintPropagationRule({0}, {ReturnValueIndex}))
247*0b57cec5SDimitry Andric           .Case("strrchr", TaintPropagationRule({0}, {ReturnValueIndex}))
248*0b57cec5SDimitry Andric           .Case("tolower", TaintPropagationRule({0}, {ReturnValueIndex}))
249*0b57cec5SDimitry Andric           .Case("toupper", TaintPropagationRule({0}, {ReturnValueIndex}))
250*0b57cec5SDimitry Andric           .Default(TaintPropagationRule());
251*0b57cec5SDimitry Andric 
252*0b57cec5SDimitry Andric   if (!Rule.isNull())
253*0b57cec5SDimitry Andric     return Rule;
254*0b57cec5SDimitry Andric 
255*0b57cec5SDimitry Andric   // Check if it's one of the memory setting/copying functions.
256*0b57cec5SDimitry Andric   // This check is specialized but faster then calling isCLibraryFunction.
257*0b57cec5SDimitry Andric   unsigned BId = 0;
258*0b57cec5SDimitry Andric   if ((BId = FDecl->getMemoryFunctionKind()))
259*0b57cec5SDimitry Andric     switch (BId) {
260*0b57cec5SDimitry Andric     case Builtin::BImemcpy:
261*0b57cec5SDimitry Andric     case Builtin::BImemmove:
262*0b57cec5SDimitry Andric     case Builtin::BIstrncpy:
263*0b57cec5SDimitry Andric     case Builtin::BIstrncat:
264*0b57cec5SDimitry Andric       return TaintPropagationRule({1, 2}, {0, ReturnValueIndex});
265*0b57cec5SDimitry Andric     case Builtin::BIstrlcpy:
266*0b57cec5SDimitry Andric     case Builtin::BIstrlcat:
267*0b57cec5SDimitry Andric       return TaintPropagationRule({1, 2}, {0});
268*0b57cec5SDimitry Andric     case Builtin::BIstrndup:
269*0b57cec5SDimitry Andric       return TaintPropagationRule({0, 1}, {ReturnValueIndex});
270*0b57cec5SDimitry Andric 
271*0b57cec5SDimitry Andric     default:
272*0b57cec5SDimitry Andric       break;
273*0b57cec5SDimitry Andric     };
274*0b57cec5SDimitry Andric 
275*0b57cec5SDimitry Andric   // Process all other functions which could be defined as builtins.
276*0b57cec5SDimitry Andric   if (Rule.isNull()) {
277*0b57cec5SDimitry Andric     if (C.isCLibraryFunction(FDecl, "snprintf"))
278*0b57cec5SDimitry Andric       return TaintPropagationRule({1}, {0, ReturnValueIndex}, VariadicType::Src,
279*0b57cec5SDimitry Andric                                   3);
280*0b57cec5SDimitry Andric     else if (C.isCLibraryFunction(FDecl, "sprintf"))
281*0b57cec5SDimitry Andric       return TaintPropagationRule({}, {0, ReturnValueIndex}, VariadicType::Src,
282*0b57cec5SDimitry Andric                                   2);
283*0b57cec5SDimitry Andric     else if (C.isCLibraryFunction(FDecl, "strcpy") ||
284*0b57cec5SDimitry Andric              C.isCLibraryFunction(FDecl, "stpcpy") ||
285*0b57cec5SDimitry Andric              C.isCLibraryFunction(FDecl, "strcat"))
286*0b57cec5SDimitry Andric       return TaintPropagationRule({1}, {0, ReturnValueIndex});
287*0b57cec5SDimitry Andric     else if (C.isCLibraryFunction(FDecl, "bcopy"))
288*0b57cec5SDimitry Andric       return TaintPropagationRule({0, 2}, {1});
289*0b57cec5SDimitry Andric     else if (C.isCLibraryFunction(FDecl, "strdup") ||
290*0b57cec5SDimitry Andric              C.isCLibraryFunction(FDecl, "strdupa"))
291*0b57cec5SDimitry Andric       return TaintPropagationRule({0}, {ReturnValueIndex});
292*0b57cec5SDimitry Andric     else if (C.isCLibraryFunction(FDecl, "wcsdup"))
293*0b57cec5SDimitry Andric       return TaintPropagationRule({0}, {ReturnValueIndex});
294*0b57cec5SDimitry Andric   }
295*0b57cec5SDimitry Andric 
296*0b57cec5SDimitry Andric   // Skipping the following functions, since they might be used for cleansing
297*0b57cec5SDimitry Andric   // or smart memory copy:
298*0b57cec5SDimitry Andric   // - memccpy - copying until hitting a special character.
299*0b57cec5SDimitry Andric 
300*0b57cec5SDimitry Andric   return TaintPropagationRule();
301*0b57cec5SDimitry Andric }
302*0b57cec5SDimitry Andric 
303*0b57cec5SDimitry Andric void GenericTaintChecker::checkPreStmt(const CallExpr *CE,
304*0b57cec5SDimitry Andric                                        CheckerContext &C) const {
305*0b57cec5SDimitry Andric   // Check for taintedness related errors first: system call, uncontrolled
306*0b57cec5SDimitry Andric   // format string, tainted buffer size.
307*0b57cec5SDimitry Andric   if (checkPre(CE, C))
308*0b57cec5SDimitry Andric     return;
309*0b57cec5SDimitry Andric 
310*0b57cec5SDimitry Andric   // Marks the function's arguments and/or return value tainted if it present in
311*0b57cec5SDimitry Andric   // the list.
312*0b57cec5SDimitry Andric   addSourcesPre(CE, C);
313*0b57cec5SDimitry Andric }
314*0b57cec5SDimitry Andric 
315*0b57cec5SDimitry Andric void GenericTaintChecker::checkPostStmt(const CallExpr *CE,
316*0b57cec5SDimitry Andric                                         CheckerContext &C) const {
317*0b57cec5SDimitry Andric   // Set the marked values as tainted. The return value only accessible from
318*0b57cec5SDimitry Andric   // checkPostStmt.
319*0b57cec5SDimitry Andric   propagateFromPre(CE, C);
320*0b57cec5SDimitry Andric }
321*0b57cec5SDimitry Andric 
322*0b57cec5SDimitry Andric void GenericTaintChecker::printState(raw_ostream &Out, ProgramStateRef State,
323*0b57cec5SDimitry Andric                                      const char *NL, const char *Sep) const {
324*0b57cec5SDimitry Andric   printTaint(State, Out, NL, Sep);
325*0b57cec5SDimitry Andric }
326*0b57cec5SDimitry Andric 
327*0b57cec5SDimitry Andric void GenericTaintChecker::addSourcesPre(const CallExpr *CE,
328*0b57cec5SDimitry Andric                                         CheckerContext &C) const {
329*0b57cec5SDimitry Andric   ProgramStateRef State = nullptr;
330*0b57cec5SDimitry Andric   const FunctionDecl *FDecl = C.getCalleeDecl(CE);
331*0b57cec5SDimitry Andric   if (!FDecl || FDecl->getKind() != Decl::Function)
332*0b57cec5SDimitry Andric     return;
333*0b57cec5SDimitry Andric 
334*0b57cec5SDimitry Andric   StringRef Name = C.getCalleeName(FDecl);
335*0b57cec5SDimitry Andric   if (Name.empty())
336*0b57cec5SDimitry Andric     return;
337*0b57cec5SDimitry Andric 
338*0b57cec5SDimitry Andric   // First, try generating a propagation rule for this function.
339*0b57cec5SDimitry Andric   TaintPropagationRule Rule =
340*0b57cec5SDimitry Andric       TaintPropagationRule::getTaintPropagationRule(FDecl, Name, C);
341*0b57cec5SDimitry Andric   if (!Rule.isNull()) {
342*0b57cec5SDimitry Andric     State = Rule.process(CE, C);
343*0b57cec5SDimitry Andric     if (!State)
344*0b57cec5SDimitry Andric       return;
345*0b57cec5SDimitry Andric     C.addTransition(State);
346*0b57cec5SDimitry Andric     return;
347*0b57cec5SDimitry Andric   }
348*0b57cec5SDimitry Andric 
349*0b57cec5SDimitry Andric   if (!State)
350*0b57cec5SDimitry Andric     return;
351*0b57cec5SDimitry Andric   C.addTransition(State);
352*0b57cec5SDimitry Andric }
353*0b57cec5SDimitry Andric 
354*0b57cec5SDimitry Andric bool GenericTaintChecker::propagateFromPre(const CallExpr *CE,
355*0b57cec5SDimitry Andric                                            CheckerContext &C) const {
356*0b57cec5SDimitry Andric   ProgramStateRef State = C.getState();
357*0b57cec5SDimitry Andric 
358*0b57cec5SDimitry Andric   // Depending on what was tainted at pre-visit, we determined a set of
359*0b57cec5SDimitry Andric   // arguments which should be tainted after the function returns. These are
360*0b57cec5SDimitry Andric   // stored in the state as TaintArgsOnPostVisit set.
361*0b57cec5SDimitry Andric   TaintArgsOnPostVisitTy TaintArgs = State->get<TaintArgsOnPostVisit>();
362*0b57cec5SDimitry Andric   if (TaintArgs.isEmpty())
363*0b57cec5SDimitry Andric     return false;
364*0b57cec5SDimitry Andric 
365*0b57cec5SDimitry Andric   for (unsigned ArgNum : TaintArgs) {
366*0b57cec5SDimitry Andric     // Special handling for the tainted return value.
367*0b57cec5SDimitry Andric     if (ArgNum == ReturnValueIndex) {
368*0b57cec5SDimitry Andric       State = addTaint(State, CE, C.getLocationContext());
369*0b57cec5SDimitry Andric       continue;
370*0b57cec5SDimitry Andric     }
371*0b57cec5SDimitry Andric 
372*0b57cec5SDimitry Andric     // The arguments are pointer arguments. The data they are pointing at is
373*0b57cec5SDimitry Andric     // tainted after the call.
374*0b57cec5SDimitry Andric     if (CE->getNumArgs() < (ArgNum + 1))
375*0b57cec5SDimitry Andric       return false;
376*0b57cec5SDimitry Andric     const Expr *Arg = CE->getArg(ArgNum);
377*0b57cec5SDimitry Andric     Optional<SVal> V = getPointedToSVal(C, Arg);
378*0b57cec5SDimitry Andric     if (V)
379*0b57cec5SDimitry Andric       State = addTaint(State, *V);
380*0b57cec5SDimitry Andric   }
381*0b57cec5SDimitry Andric 
382*0b57cec5SDimitry Andric   // Clear up the taint info from the state.
383*0b57cec5SDimitry Andric   State = State->remove<TaintArgsOnPostVisit>();
384*0b57cec5SDimitry Andric 
385*0b57cec5SDimitry Andric   if (State != C.getState()) {
386*0b57cec5SDimitry Andric     C.addTransition(State);
387*0b57cec5SDimitry Andric     return true;
388*0b57cec5SDimitry Andric   }
389*0b57cec5SDimitry Andric   return false;
390*0b57cec5SDimitry Andric }
391*0b57cec5SDimitry Andric 
392*0b57cec5SDimitry Andric bool GenericTaintChecker::checkPre(const CallExpr *CE,
393*0b57cec5SDimitry Andric                                    CheckerContext &C) const {
394*0b57cec5SDimitry Andric 
395*0b57cec5SDimitry Andric   if (checkUncontrolledFormatString(CE, C))
396*0b57cec5SDimitry Andric     return true;
397*0b57cec5SDimitry Andric 
398*0b57cec5SDimitry Andric   const FunctionDecl *FDecl = C.getCalleeDecl(CE);
399*0b57cec5SDimitry Andric   if (!FDecl || FDecl->getKind() != Decl::Function)
400*0b57cec5SDimitry Andric     return false;
401*0b57cec5SDimitry Andric 
402*0b57cec5SDimitry Andric   StringRef Name = C.getCalleeName(FDecl);
403*0b57cec5SDimitry Andric   if (Name.empty())
404*0b57cec5SDimitry Andric     return false;
405*0b57cec5SDimitry Andric 
406*0b57cec5SDimitry Andric   if (checkSystemCall(CE, Name, C))
407*0b57cec5SDimitry Andric     return true;
408*0b57cec5SDimitry Andric 
409*0b57cec5SDimitry Andric   if (checkTaintedBufferSize(CE, FDecl, C))
410*0b57cec5SDimitry Andric     return true;
411*0b57cec5SDimitry Andric 
412*0b57cec5SDimitry Andric   return false;
413*0b57cec5SDimitry Andric }
414*0b57cec5SDimitry Andric 
415*0b57cec5SDimitry Andric Optional<SVal> GenericTaintChecker::getPointedToSVal(CheckerContext &C,
416*0b57cec5SDimitry Andric                                                      const Expr *Arg) {
417*0b57cec5SDimitry Andric   ProgramStateRef State = C.getState();
418*0b57cec5SDimitry Andric   SVal AddrVal = C.getSVal(Arg->IgnoreParens());
419*0b57cec5SDimitry Andric   if (AddrVal.isUnknownOrUndef())
420*0b57cec5SDimitry Andric     return None;
421*0b57cec5SDimitry Andric 
422*0b57cec5SDimitry Andric   Optional<Loc> AddrLoc = AddrVal.getAs<Loc>();
423*0b57cec5SDimitry Andric   if (!AddrLoc)
424*0b57cec5SDimitry Andric     return None;
425*0b57cec5SDimitry Andric 
426*0b57cec5SDimitry Andric   QualType ArgTy = Arg->getType().getCanonicalType();
427*0b57cec5SDimitry Andric   if (!ArgTy->isPointerType())
428*0b57cec5SDimitry Andric     return None;
429*0b57cec5SDimitry Andric 
430*0b57cec5SDimitry Andric   QualType ValTy = ArgTy->getPointeeType();
431*0b57cec5SDimitry Andric 
432*0b57cec5SDimitry Andric   // Do not dereference void pointers. Treat them as byte pointers instead.
433*0b57cec5SDimitry Andric   // FIXME: we might want to consider more than just the first byte.
434*0b57cec5SDimitry Andric   if (ValTy->isVoidType())
435*0b57cec5SDimitry Andric     ValTy = C.getASTContext().CharTy;
436*0b57cec5SDimitry Andric 
437*0b57cec5SDimitry Andric   return State->getSVal(*AddrLoc, ValTy);
438*0b57cec5SDimitry Andric }
439*0b57cec5SDimitry Andric 
440*0b57cec5SDimitry Andric ProgramStateRef
441*0b57cec5SDimitry Andric GenericTaintChecker::TaintPropagationRule::process(const CallExpr *CE,
442*0b57cec5SDimitry Andric                                                    CheckerContext &C) const {
443*0b57cec5SDimitry Andric   ProgramStateRef State = C.getState();
444*0b57cec5SDimitry Andric 
445*0b57cec5SDimitry Andric   // Check for taint in arguments.
446*0b57cec5SDimitry Andric   bool IsTainted = true;
447*0b57cec5SDimitry Andric   for (unsigned ArgNum : SrcArgs) {
448*0b57cec5SDimitry Andric     if (ArgNum >= CE->getNumArgs())
449*0b57cec5SDimitry Andric       return State;
450*0b57cec5SDimitry Andric     if ((IsTainted = isTaintedOrPointsToTainted(CE->getArg(ArgNum), State, C)))
451*0b57cec5SDimitry Andric       break;
452*0b57cec5SDimitry Andric   }
453*0b57cec5SDimitry Andric 
454*0b57cec5SDimitry Andric   // Check for taint in variadic arguments.
455*0b57cec5SDimitry Andric   if (!IsTainted && VariadicType::Src == VarType) {
456*0b57cec5SDimitry Andric     // Check if any of the arguments is tainted
457*0b57cec5SDimitry Andric     for (unsigned int i = VariadicIndex; i < CE->getNumArgs(); ++i) {
458*0b57cec5SDimitry Andric       if ((IsTainted = isTaintedOrPointsToTainted(CE->getArg(i), State, C)))
459*0b57cec5SDimitry Andric         break;
460*0b57cec5SDimitry Andric     }
461*0b57cec5SDimitry Andric   }
462*0b57cec5SDimitry Andric 
463*0b57cec5SDimitry Andric   if (PropagationFunc)
464*0b57cec5SDimitry Andric     IsTainted = PropagationFunc(IsTainted, CE, C);
465*0b57cec5SDimitry Andric 
466*0b57cec5SDimitry Andric   if (!IsTainted)
467*0b57cec5SDimitry Andric     return State;
468*0b57cec5SDimitry Andric 
469*0b57cec5SDimitry Andric   // Mark the arguments which should be tainted after the function returns.
470*0b57cec5SDimitry Andric   for (unsigned ArgNum : DstArgs) {
471*0b57cec5SDimitry Andric     // Should mark the return value?
472*0b57cec5SDimitry Andric     if (ArgNum == ReturnValueIndex) {
473*0b57cec5SDimitry Andric       State = State->add<TaintArgsOnPostVisit>(ReturnValueIndex);
474*0b57cec5SDimitry Andric       continue;
475*0b57cec5SDimitry Andric     }
476*0b57cec5SDimitry Andric 
477*0b57cec5SDimitry Andric     // Mark the given argument.
478*0b57cec5SDimitry Andric     assert(ArgNum < CE->getNumArgs());
479*0b57cec5SDimitry Andric     State = State->add<TaintArgsOnPostVisit>(ArgNum);
480*0b57cec5SDimitry Andric   }
481*0b57cec5SDimitry Andric 
482*0b57cec5SDimitry Andric   // Mark all variadic arguments tainted if present.
483*0b57cec5SDimitry Andric   if (VariadicType::Dst == VarType) {
484*0b57cec5SDimitry Andric     // For all pointer and references that were passed in:
485*0b57cec5SDimitry Andric     //   If they are not pointing to const data, mark data as tainted.
486*0b57cec5SDimitry Andric     //   TODO: So far we are just going one level down; ideally we'd need to
487*0b57cec5SDimitry Andric     //         recurse here.
488*0b57cec5SDimitry Andric     for (unsigned int i = VariadicIndex; i < CE->getNumArgs(); ++i) {
489*0b57cec5SDimitry Andric       const Expr *Arg = CE->getArg(i);
490*0b57cec5SDimitry Andric       // Process pointer argument.
491*0b57cec5SDimitry Andric       const Type *ArgTy = Arg->getType().getTypePtr();
492*0b57cec5SDimitry Andric       QualType PType = ArgTy->getPointeeType();
493*0b57cec5SDimitry Andric       if ((!PType.isNull() && !PType.isConstQualified()) ||
494*0b57cec5SDimitry Andric           (ArgTy->isReferenceType() && !Arg->getType().isConstQualified()))
495*0b57cec5SDimitry Andric         State = State->add<TaintArgsOnPostVisit>(i);
496*0b57cec5SDimitry Andric     }
497*0b57cec5SDimitry Andric   }
498*0b57cec5SDimitry Andric 
499*0b57cec5SDimitry Andric   return State;
500*0b57cec5SDimitry Andric }
501*0b57cec5SDimitry Andric 
502*0b57cec5SDimitry Andric // If argument 0(protocol domain) is network, the return value should get taint.
503*0b57cec5SDimitry Andric bool GenericTaintChecker::TaintPropagationRule::postSocket(bool /*IsTainted*/,
504*0b57cec5SDimitry Andric                                                            const CallExpr *CE,
505*0b57cec5SDimitry Andric                                                            CheckerContext &C) {
506*0b57cec5SDimitry Andric   SourceLocation DomLoc = CE->getArg(0)->getExprLoc();
507*0b57cec5SDimitry Andric   StringRef DomName = C.getMacroNameOrSpelling(DomLoc);
508*0b57cec5SDimitry Andric   // White list the internal communication protocols.
509*0b57cec5SDimitry Andric   if (DomName.equals("AF_SYSTEM") || DomName.equals("AF_LOCAL") ||
510*0b57cec5SDimitry Andric       DomName.equals("AF_UNIX") || DomName.equals("AF_RESERVED_36"))
511*0b57cec5SDimitry Andric     return false;
512*0b57cec5SDimitry Andric 
513*0b57cec5SDimitry Andric   return true;
514*0b57cec5SDimitry Andric }
515*0b57cec5SDimitry Andric 
516*0b57cec5SDimitry Andric bool GenericTaintChecker::isStdin(const Expr *E, CheckerContext &C) {
517*0b57cec5SDimitry Andric   ProgramStateRef State = C.getState();
518*0b57cec5SDimitry Andric   SVal Val = C.getSVal(E);
519*0b57cec5SDimitry Andric 
520*0b57cec5SDimitry Andric   // stdin is a pointer, so it would be a region.
521*0b57cec5SDimitry Andric   const MemRegion *MemReg = Val.getAsRegion();
522*0b57cec5SDimitry Andric 
523*0b57cec5SDimitry Andric   // The region should be symbolic, we do not know it's value.
524*0b57cec5SDimitry Andric   const SymbolicRegion *SymReg = dyn_cast_or_null<SymbolicRegion>(MemReg);
525*0b57cec5SDimitry Andric   if (!SymReg)
526*0b57cec5SDimitry Andric     return false;
527*0b57cec5SDimitry Andric 
528*0b57cec5SDimitry Andric   // Get it's symbol and find the declaration region it's pointing to.
529*0b57cec5SDimitry Andric   const SymbolRegionValue *Sm =
530*0b57cec5SDimitry Andric       dyn_cast<SymbolRegionValue>(SymReg->getSymbol());
531*0b57cec5SDimitry Andric   if (!Sm)
532*0b57cec5SDimitry Andric     return false;
533*0b57cec5SDimitry Andric   const DeclRegion *DeclReg = dyn_cast_or_null<DeclRegion>(Sm->getRegion());
534*0b57cec5SDimitry Andric   if (!DeclReg)
535*0b57cec5SDimitry Andric     return false;
536*0b57cec5SDimitry Andric 
537*0b57cec5SDimitry Andric   // This region corresponds to a declaration, find out if it's a global/extern
538*0b57cec5SDimitry Andric   // variable named stdin with the proper type.
539*0b57cec5SDimitry Andric   if (const auto *D = dyn_cast_or_null<VarDecl>(DeclReg->getDecl())) {
540*0b57cec5SDimitry Andric     D = D->getCanonicalDecl();
541*0b57cec5SDimitry Andric     if ((D->getName().find("stdin") != StringRef::npos) && D->isExternC()) {
542*0b57cec5SDimitry Andric       const auto *PtrTy = dyn_cast<PointerType>(D->getType().getTypePtr());
543*0b57cec5SDimitry Andric       if (PtrTy && PtrTy->getPointeeType().getCanonicalType() ==
544*0b57cec5SDimitry Andric                        C.getASTContext().getFILEType().getCanonicalType())
545*0b57cec5SDimitry Andric         return true;
546*0b57cec5SDimitry Andric     }
547*0b57cec5SDimitry Andric   }
548*0b57cec5SDimitry Andric   return false;
549*0b57cec5SDimitry Andric }
550*0b57cec5SDimitry Andric 
551*0b57cec5SDimitry Andric static bool getPrintfFormatArgumentNum(const CallExpr *CE,
552*0b57cec5SDimitry Andric                                        const CheckerContext &C,
553*0b57cec5SDimitry Andric                                        unsigned int &ArgNum) {
554*0b57cec5SDimitry Andric   // Find if the function contains a format string argument.
555*0b57cec5SDimitry Andric   // Handles: fprintf, printf, sprintf, snprintf, vfprintf, vprintf, vsprintf,
556*0b57cec5SDimitry Andric   // vsnprintf, syslog, custom annotated functions.
557*0b57cec5SDimitry Andric   const FunctionDecl *FDecl = C.getCalleeDecl(CE);
558*0b57cec5SDimitry Andric   if (!FDecl)
559*0b57cec5SDimitry Andric     return false;
560*0b57cec5SDimitry Andric   for (const auto *Format : FDecl->specific_attrs<FormatAttr>()) {
561*0b57cec5SDimitry Andric     ArgNum = Format->getFormatIdx() - 1;
562*0b57cec5SDimitry Andric     if ((Format->getType()->getName() == "printf") && CE->getNumArgs() > ArgNum)
563*0b57cec5SDimitry Andric       return true;
564*0b57cec5SDimitry Andric   }
565*0b57cec5SDimitry Andric 
566*0b57cec5SDimitry Andric   // Or if a function is named setproctitle (this is a heuristic).
567*0b57cec5SDimitry Andric   if (C.getCalleeName(CE).find("setproctitle") != StringRef::npos) {
568*0b57cec5SDimitry Andric     ArgNum = 0;
569*0b57cec5SDimitry Andric     return true;
570*0b57cec5SDimitry Andric   }
571*0b57cec5SDimitry Andric 
572*0b57cec5SDimitry Andric   return false;
573*0b57cec5SDimitry Andric }
574*0b57cec5SDimitry Andric 
575*0b57cec5SDimitry Andric bool GenericTaintChecker::generateReportIfTainted(const Expr *E,
576*0b57cec5SDimitry Andric                                                   const char Msg[],
577*0b57cec5SDimitry Andric                                                   CheckerContext &C) const {
578*0b57cec5SDimitry Andric   assert(E);
579*0b57cec5SDimitry Andric 
580*0b57cec5SDimitry Andric   // Check for taint.
581*0b57cec5SDimitry Andric   ProgramStateRef State = C.getState();
582*0b57cec5SDimitry Andric   Optional<SVal> PointedToSVal = getPointedToSVal(C, E);
583*0b57cec5SDimitry Andric   SVal TaintedSVal;
584*0b57cec5SDimitry Andric   if (PointedToSVal && isTainted(State, *PointedToSVal))
585*0b57cec5SDimitry Andric     TaintedSVal = *PointedToSVal;
586*0b57cec5SDimitry Andric   else if (isTainted(State, E, C.getLocationContext()))
587*0b57cec5SDimitry Andric     TaintedSVal = C.getSVal(E);
588*0b57cec5SDimitry Andric   else
589*0b57cec5SDimitry Andric     return false;
590*0b57cec5SDimitry Andric 
591*0b57cec5SDimitry Andric   // Generate diagnostic.
592*0b57cec5SDimitry Andric   if (ExplodedNode *N = C.generateNonFatalErrorNode()) {
593*0b57cec5SDimitry Andric     initBugType();
594*0b57cec5SDimitry Andric     auto report = llvm::make_unique<BugReport>(*BT, Msg, N);
595*0b57cec5SDimitry Andric     report->addRange(E->getSourceRange());
596*0b57cec5SDimitry Andric     report->addVisitor(llvm::make_unique<TaintBugVisitor>(TaintedSVal));
597*0b57cec5SDimitry Andric     C.emitReport(std::move(report));
598*0b57cec5SDimitry Andric     return true;
599*0b57cec5SDimitry Andric   }
600*0b57cec5SDimitry Andric   return false;
601*0b57cec5SDimitry Andric }
602*0b57cec5SDimitry Andric 
603*0b57cec5SDimitry Andric bool GenericTaintChecker::checkUncontrolledFormatString(
604*0b57cec5SDimitry Andric     const CallExpr *CE, CheckerContext &C) const {
605*0b57cec5SDimitry Andric   // Check if the function contains a format string argument.
606*0b57cec5SDimitry Andric   unsigned int ArgNum = 0;
607*0b57cec5SDimitry Andric   if (!getPrintfFormatArgumentNum(CE, C, ArgNum))
608*0b57cec5SDimitry Andric     return false;
609*0b57cec5SDimitry Andric 
610*0b57cec5SDimitry Andric   // If either the format string content or the pointer itself are tainted,
611*0b57cec5SDimitry Andric   // warn.
612*0b57cec5SDimitry Andric   return generateReportIfTainted(CE->getArg(ArgNum),
613*0b57cec5SDimitry Andric                                  MsgUncontrolledFormatString, C);
614*0b57cec5SDimitry Andric }
615*0b57cec5SDimitry Andric 
616*0b57cec5SDimitry Andric bool GenericTaintChecker::checkSystemCall(const CallExpr *CE, StringRef Name,
617*0b57cec5SDimitry Andric                                           CheckerContext &C) const {
618*0b57cec5SDimitry Andric   // TODO: It might make sense to run this check on demand. In some cases,
619*0b57cec5SDimitry Andric   // we should check if the environment has been cleansed here. We also might
620*0b57cec5SDimitry Andric   // need to know if the user was reset before these calls(seteuid).
621*0b57cec5SDimitry Andric   unsigned ArgNum = llvm::StringSwitch<unsigned>(Name)
622*0b57cec5SDimitry Andric                         .Case("system", 0)
623*0b57cec5SDimitry Andric                         .Case("popen", 0)
624*0b57cec5SDimitry Andric                         .Case("execl", 0)
625*0b57cec5SDimitry Andric                         .Case("execle", 0)
626*0b57cec5SDimitry Andric                         .Case("execlp", 0)
627*0b57cec5SDimitry Andric                         .Case("execv", 0)
628*0b57cec5SDimitry Andric                         .Case("execvp", 0)
629*0b57cec5SDimitry Andric                         .Case("execvP", 0)
630*0b57cec5SDimitry Andric                         .Case("execve", 0)
631*0b57cec5SDimitry Andric                         .Case("dlopen", 0)
632*0b57cec5SDimitry Andric                         .Default(UINT_MAX);
633*0b57cec5SDimitry Andric 
634*0b57cec5SDimitry Andric   if (ArgNum == UINT_MAX || CE->getNumArgs() < (ArgNum + 1))
635*0b57cec5SDimitry Andric     return false;
636*0b57cec5SDimitry Andric 
637*0b57cec5SDimitry Andric   return generateReportIfTainted(CE->getArg(ArgNum), MsgSanitizeSystemArgs, C);
638*0b57cec5SDimitry Andric }
639*0b57cec5SDimitry Andric 
640*0b57cec5SDimitry Andric // TODO: Should this check be a part of the CString checker?
641*0b57cec5SDimitry Andric // If yes, should taint be a global setting?
642*0b57cec5SDimitry Andric bool GenericTaintChecker::checkTaintedBufferSize(const CallExpr *CE,
643*0b57cec5SDimitry Andric                                                  const FunctionDecl *FDecl,
644*0b57cec5SDimitry Andric                                                  CheckerContext &C) const {
645*0b57cec5SDimitry Andric   // If the function has a buffer size argument, set ArgNum.
646*0b57cec5SDimitry Andric   unsigned ArgNum = InvalidArgIndex;
647*0b57cec5SDimitry Andric   unsigned BId = 0;
648*0b57cec5SDimitry Andric   if ((BId = FDecl->getMemoryFunctionKind()))
649*0b57cec5SDimitry Andric     switch (BId) {
650*0b57cec5SDimitry Andric     case Builtin::BImemcpy:
651*0b57cec5SDimitry Andric     case Builtin::BImemmove:
652*0b57cec5SDimitry Andric     case Builtin::BIstrncpy:
653*0b57cec5SDimitry Andric       ArgNum = 2;
654*0b57cec5SDimitry Andric       break;
655*0b57cec5SDimitry Andric     case Builtin::BIstrndup:
656*0b57cec5SDimitry Andric       ArgNum = 1;
657*0b57cec5SDimitry Andric       break;
658*0b57cec5SDimitry Andric     default:
659*0b57cec5SDimitry Andric       break;
660*0b57cec5SDimitry Andric     };
661*0b57cec5SDimitry Andric 
662*0b57cec5SDimitry Andric   if (ArgNum == InvalidArgIndex) {
663*0b57cec5SDimitry Andric     if (C.isCLibraryFunction(FDecl, "malloc") ||
664*0b57cec5SDimitry Andric         C.isCLibraryFunction(FDecl, "calloc") ||
665*0b57cec5SDimitry Andric         C.isCLibraryFunction(FDecl, "alloca"))
666*0b57cec5SDimitry Andric       ArgNum = 0;
667*0b57cec5SDimitry Andric     else if (C.isCLibraryFunction(FDecl, "memccpy"))
668*0b57cec5SDimitry Andric       ArgNum = 3;
669*0b57cec5SDimitry Andric     else if (C.isCLibraryFunction(FDecl, "realloc"))
670*0b57cec5SDimitry Andric       ArgNum = 1;
671*0b57cec5SDimitry Andric     else if (C.isCLibraryFunction(FDecl, "bcopy"))
672*0b57cec5SDimitry Andric       ArgNum = 2;
673*0b57cec5SDimitry Andric   }
674*0b57cec5SDimitry Andric 
675*0b57cec5SDimitry Andric   return ArgNum != InvalidArgIndex && CE->getNumArgs() > ArgNum &&
676*0b57cec5SDimitry Andric          generateReportIfTainted(CE->getArg(ArgNum), MsgTaintedBufferSize, C);
677*0b57cec5SDimitry Andric }
678*0b57cec5SDimitry Andric 
679*0b57cec5SDimitry Andric void ento::registerGenericTaintChecker(CheckerManager &mgr) {
680*0b57cec5SDimitry Andric   mgr.registerChecker<GenericTaintChecker>();
681*0b57cec5SDimitry Andric }
682*0b57cec5SDimitry Andric 
683*0b57cec5SDimitry Andric bool ento::shouldRegisterGenericTaintChecker(const LangOptions &LO) {
684*0b57cec5SDimitry Andric   return true;
685*0b57cec5SDimitry Andric }
686