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