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