Home | History | Annotate | Download | only in Checkers
      1 //==- CheckSecuritySyntaxOnly.cpp - Basic security checks --------*- 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 file defines a set of flow-insensitive security checks.
     11 //
     12 //===----------------------------------------------------------------------===//
     13 
     14 #include "ClangSACheckers.h"
     15 #include "clang/Analysis/AnalysisContext.h"
     16 #include "clang/AST/StmtVisitor.h"
     17 #include "clang/Basic/TargetInfo.h"
     18 #include "clang/StaticAnalyzer/Core/Checker.h"
     19 #include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h"
     20 #include "clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h"
     21 #include "llvm/ADT/SmallString.h"
     22 #include "llvm/ADT/StringSwitch.h"
     23 #include "llvm/Support/raw_ostream.h"
     24 
     25 using namespace clang;
     26 using namespace ento;
     27 
     28 static bool isArc4RandomAvailable(const ASTContext &Ctx) {
     29   const llvm::Triple &T = Ctx.getTargetInfo().getTriple();
     30   return T.getVendor() == llvm::Triple::Apple ||
     31          T.getOS() == llvm::Triple::FreeBSD ||
     32          T.getOS() == llvm::Triple::NetBSD ||
     33          T.getOS() == llvm::Triple::OpenBSD ||
     34          T.getOS() == llvm::Triple::DragonFly;
     35 }
     36 
     37 namespace {
     38 struct DefaultBool {
     39   bool val;
     40   DefaultBool() : val(false) {}
     41   operator bool() const { return val; }
     42   DefaultBool &operator=(bool b) { val = b; return *this; }
     43 };
     44 
     45 struct ChecksFilter {
     46   DefaultBool check_gets;
     47   DefaultBool check_getpw;
     48   DefaultBool check_mktemp;
     49   DefaultBool check_mkstemp;
     50   DefaultBool check_strcpy;
     51   DefaultBool check_rand;
     52   DefaultBool check_vfork;
     53   DefaultBool check_FloatLoopCounter;
     54   DefaultBool check_UncheckedReturn;
     55 };
     56 
     57 class WalkAST : public StmtVisitor<WalkAST> {
     58   BugReporter &BR;
     59   AnalysisDeclContext* AC;
     60   enum { num_setids = 6 };
     61   IdentifierInfo *II_setid[num_setids];
     62 
     63   const bool CheckRand;
     64   const ChecksFilter &filter;
     65 
     66 public:
     67   WalkAST(BugReporter &br, AnalysisDeclContext* ac,
     68           const ChecksFilter &f)
     69   : BR(br), AC(ac), II_setid(),
     70     CheckRand(isArc4RandomAvailable(BR.getContext())),
     71     filter(f) {}
     72 
     73   // Statement visitor methods.
     74   void VisitCallExpr(CallExpr *CE);
     75   void VisitForStmt(ForStmt *S);
     76   void VisitCompoundStmt (CompoundStmt *S);
     77   void VisitStmt(Stmt *S) { VisitChildren(S); }
     78 
     79   void VisitChildren(Stmt *S);
     80 
     81   // Helpers.
     82   bool checkCall_strCommon(const CallExpr *CE, const FunctionDecl *FD);
     83 
     84   typedef void (WalkAST::*FnCheck)(const CallExpr *,
     85 				   const FunctionDecl *);
     86 
     87   // Checker-specific methods.
     88   void checkLoopConditionForFloat(const ForStmt *FS);
     89   void checkCall_gets(const CallExpr *CE, const FunctionDecl *FD);
     90   void checkCall_getpw(const CallExpr *CE, const FunctionDecl *FD);
     91   void checkCall_mktemp(const CallExpr *CE, const FunctionDecl *FD);
     92   void checkCall_mkstemp(const CallExpr *CE, const FunctionDecl *FD);
     93   void checkCall_strcpy(const CallExpr *CE, const FunctionDecl *FD);
     94   void checkCall_strcat(const CallExpr *CE, const FunctionDecl *FD);
     95   void checkCall_rand(const CallExpr *CE, const FunctionDecl *FD);
     96   void checkCall_random(const CallExpr *CE, const FunctionDecl *FD);
     97   void checkCall_vfork(const CallExpr *CE, const FunctionDecl *FD);
     98   void checkUncheckedReturnValue(CallExpr *CE);
     99 };
    100 } // end anonymous namespace
    101 
    102 //===----------------------------------------------------------------------===//
    103 // AST walking.
    104 //===----------------------------------------------------------------------===//
    105 
    106 void WalkAST::VisitChildren(Stmt *S) {
    107   for (Stmt::child_iterator I = S->child_begin(), E = S->child_end(); I!=E; ++I)
    108     if (Stmt *child = *I)
    109       Visit(child);
    110 }
    111 
    112 void WalkAST::VisitCallExpr(CallExpr *CE) {
    113   // Get the callee.
    114   const FunctionDecl *FD = CE->getDirectCallee();
    115 
    116   if (!FD)
    117     return;
    118 
    119   // Get the name of the callee. If it's a builtin, strip off the prefix.
    120   IdentifierInfo *II = FD->getIdentifier();
    121   if (!II)   // if no identifier, not a simple C function
    122     return;
    123   StringRef Name = II->getName();
    124   if (Name.startswith("__builtin_"))
    125     Name = Name.substr(10);
    126 
    127   // Set the evaluation function by switching on the callee name.
    128   FnCheck evalFunction = llvm::StringSwitch<FnCheck>(Name)
    129     .Case("gets", &WalkAST::checkCall_gets)
    130     .Case("getpw", &WalkAST::checkCall_getpw)
    131     .Case("mktemp", &WalkAST::checkCall_mktemp)
    132     .Case("mkstemp", &WalkAST::checkCall_mkstemp)
    133     .Case("mkdtemp", &WalkAST::checkCall_mkstemp)
    134     .Case("mkstemps", &WalkAST::checkCall_mkstemp)
    135     .Cases("strcpy", "__strcpy_chk", &WalkAST::checkCall_strcpy)
    136     .Cases("strcat", "__strcat_chk", &WalkAST::checkCall_strcat)
    137     .Case("drand48", &WalkAST::checkCall_rand)
    138     .Case("erand48", &WalkAST::checkCall_rand)
    139     .Case("jrand48", &WalkAST::checkCall_rand)
    140     .Case("lrand48", &WalkAST::checkCall_rand)
    141     .Case("mrand48", &WalkAST::checkCall_rand)
    142     .Case("nrand48", &WalkAST::checkCall_rand)
    143     .Case("lcong48", &WalkAST::checkCall_rand)
    144     .Case("rand", &WalkAST::checkCall_rand)
    145     .Case("rand_r", &WalkAST::checkCall_rand)
    146     .Case("random", &WalkAST::checkCall_random)
    147     .Case("vfork", &WalkAST::checkCall_vfork)
    148     .Default(NULL);
    149 
    150   // If the callee isn't defined, it is not of security concern.
    151   // Check and evaluate the call.
    152   if (evalFunction)
    153     (this->*evalFunction)(CE, FD);
    154 
    155   // Recurse and check children.
    156   VisitChildren(CE);
    157 }
    158 
    159 void WalkAST::VisitCompoundStmt(CompoundStmt *S) {
    160   for (Stmt::child_iterator I = S->child_begin(), E = S->child_end(); I!=E; ++I)
    161     if (Stmt *child = *I) {
    162       if (CallExpr *CE = dyn_cast<CallExpr>(child))
    163         checkUncheckedReturnValue(CE);
    164       Visit(child);
    165     }
    166 }
    167 
    168 void WalkAST::VisitForStmt(ForStmt *FS) {
    169   checkLoopConditionForFloat(FS);
    170 
    171   // Recurse and check children.
    172   VisitChildren(FS);
    173 }
    174 
    175 //===----------------------------------------------------------------------===//
    176 // Check: floating poing variable used as loop counter.
    177 // Originally: <rdar://problem/6336718>
    178 // Implements: CERT security coding advisory FLP-30.
    179 //===----------------------------------------------------------------------===//
    180 
    181 static const DeclRefExpr*
    182 getIncrementedVar(const Expr *expr, const VarDecl *x, const VarDecl *y) {
    183   expr = expr->IgnoreParenCasts();
    184 
    185   if (const BinaryOperator *B = dyn_cast<BinaryOperator>(expr)) {
    186     if (!(B->isAssignmentOp() || B->isCompoundAssignmentOp() ||
    187           B->getOpcode() == BO_Comma))
    188       return NULL;
    189 
    190     if (const DeclRefExpr *lhs = getIncrementedVar(B->getLHS(), x, y))
    191       return lhs;
    192 
    193     if (const DeclRefExpr *rhs = getIncrementedVar(B->getRHS(), x, y))
    194       return rhs;
    195 
    196     return NULL;
    197   }
    198 
    199   if (const DeclRefExpr *DR = dyn_cast<DeclRefExpr>(expr)) {
    200     const NamedDecl *ND = DR->getDecl();
    201     return ND == x || ND == y ? DR : NULL;
    202   }
    203 
    204   if (const UnaryOperator *U = dyn_cast<UnaryOperator>(expr))
    205     return U->isIncrementDecrementOp()
    206       ? getIncrementedVar(U->getSubExpr(), x, y) : NULL;
    207 
    208   return NULL;
    209 }
    210 
    211 /// CheckLoopConditionForFloat - This check looks for 'for' statements that
    212 ///  use a floating point variable as a loop counter.
    213 ///  CERT: FLP30-C, FLP30-CPP.
    214 ///
    215 void WalkAST::checkLoopConditionForFloat(const ForStmt *FS) {
    216   if (!filter.check_FloatLoopCounter)
    217     return;
    218 
    219   // Does the loop have a condition?
    220   const Expr *condition = FS->getCond();
    221 
    222   if (!condition)
    223     return;
    224 
    225   // Does the loop have an increment?
    226   const Expr *increment = FS->getInc();
    227 
    228   if (!increment)
    229     return;
    230 
    231   // Strip away '()' and casts.
    232   condition = condition->IgnoreParenCasts();
    233   increment = increment->IgnoreParenCasts();
    234 
    235   // Is the loop condition a comparison?
    236   const BinaryOperator *B = dyn_cast<BinaryOperator>(condition);
    237 
    238   if (!B)
    239     return;
    240 
    241   // Is this a comparison?
    242   if (!(B->isRelationalOp() || B->isEqualityOp()))
    243     return;
    244 
    245   // Are we comparing variables?
    246   const DeclRefExpr *drLHS =
    247     dyn_cast<DeclRefExpr>(B->getLHS()->IgnoreParenLValueCasts());
    248   const DeclRefExpr *drRHS =
    249     dyn_cast<DeclRefExpr>(B->getRHS()->IgnoreParenLValueCasts());
    250 
    251   // Does at least one of the variables have a floating point type?
    252   drLHS = drLHS && drLHS->getType()->isRealFloatingType() ? drLHS : NULL;
    253   drRHS = drRHS && drRHS->getType()->isRealFloatingType() ? drRHS : NULL;
    254 
    255   if (!drLHS && !drRHS)
    256     return;
    257 
    258   const VarDecl *vdLHS = drLHS ? dyn_cast<VarDecl>(drLHS->getDecl()) : NULL;
    259   const VarDecl *vdRHS = drRHS ? dyn_cast<VarDecl>(drRHS->getDecl()) : NULL;
    260 
    261   if (!vdLHS && !vdRHS)
    262     return;
    263 
    264   // Does either variable appear in increment?
    265   const DeclRefExpr *drInc = getIncrementedVar(increment, vdLHS, vdRHS);
    266 
    267   if (!drInc)
    268     return;
    269 
    270   // Emit the error.  First figure out which DeclRefExpr in the condition
    271   // referenced the compared variable.
    272   const DeclRefExpr *drCond = vdLHS == drInc->getDecl() ? drLHS : drRHS;
    273 
    274   SmallVector<SourceRange, 2> ranges;
    275   SmallString<256> sbuf;
    276   llvm::raw_svector_ostream os(sbuf);
    277 
    278   os << "Variable '" << drCond->getDecl()->getName()
    279      << "' with floating point type '" << drCond->getType().getAsString()
    280      << "' should not be used as a loop counter";
    281 
    282   ranges.push_back(drCond->getSourceRange());
    283   ranges.push_back(drInc->getSourceRange());
    284 
    285   const char *bugType = "Floating point variable used as loop counter";
    286 
    287   PathDiagnosticLocation FSLoc =
    288     PathDiagnosticLocation::createBegin(FS, BR.getSourceManager(), AC);
    289   BR.EmitBasicReport(AC->getDecl(),
    290                      bugType, "Security", os.str(),
    291                      FSLoc, ranges.data(), ranges.size());
    292 }
    293 
    294 //===----------------------------------------------------------------------===//
    295 // Check: Any use of 'gets' is insecure.
    296 // Originally: <rdar://problem/6335715>
    297 // Implements (part of): 300-BSI (buildsecurityin.us-cert.gov)
    298 // CWE-242: Use of Inherently Dangerous Function
    299 //===----------------------------------------------------------------------===//
    300 
    301 void WalkAST::checkCall_gets(const CallExpr *CE, const FunctionDecl *FD) {
    302   if (!filter.check_gets)
    303     return;
    304 
    305   const FunctionProtoType *FPT
    306     = dyn_cast<FunctionProtoType>(FD->getType().IgnoreParens());
    307   if (!FPT)
    308     return;
    309 
    310   // Verify that the function takes a single argument.
    311   if (FPT->getNumArgs() != 1)
    312     return;
    313 
    314   // Is the argument a 'char*'?
    315   const PointerType *PT = dyn_cast<PointerType>(FPT->getArgType(0));
    316   if (!PT)
    317     return;
    318 
    319   if (PT->getPointeeType().getUnqualifiedType() != BR.getContext().CharTy)
    320     return;
    321 
    322   // Issue a warning.
    323   SourceRange R = CE->getCallee()->getSourceRange();
    324   PathDiagnosticLocation CELoc =
    325     PathDiagnosticLocation::createBegin(CE, BR.getSourceManager(), AC);
    326   BR.EmitBasicReport(AC->getDecl(),
    327                      "Potential buffer overflow in call to 'gets'",
    328                      "Security",
    329                      "Call to function 'gets' is extremely insecure as it can "
    330                      "always result in a buffer overflow",
    331                      CELoc, &R, 1);
    332 }
    333 
    334 //===----------------------------------------------------------------------===//
    335 // Check: Any use of 'getpwd' is insecure.
    336 // CWE-477: Use of Obsolete Functions
    337 //===----------------------------------------------------------------------===//
    338 
    339 void WalkAST::checkCall_getpw(const CallExpr *CE, const FunctionDecl *FD) {
    340   if (!filter.check_getpw)
    341     return;
    342 
    343   const FunctionProtoType *FPT
    344     = dyn_cast<FunctionProtoType>(FD->getType().IgnoreParens());
    345   if (!FPT)
    346     return;
    347 
    348   // Verify that the function takes two arguments.
    349   if (FPT->getNumArgs() != 2)
    350     return;
    351 
    352   // Verify the first argument type is integer.
    353   if (!FPT->getArgType(0)->isIntegerType())
    354     return;
    355 
    356   // Verify the second argument type is char*.
    357   const PointerType *PT = dyn_cast<PointerType>(FPT->getArgType(1));
    358   if (!PT)
    359     return;
    360 
    361   if (PT->getPointeeType().getUnqualifiedType() != BR.getContext().CharTy)
    362     return;
    363 
    364   // Issue a warning.
    365   SourceRange R = CE->getCallee()->getSourceRange();
    366   PathDiagnosticLocation CELoc =
    367     PathDiagnosticLocation::createBegin(CE, BR.getSourceManager(), AC);
    368   BR.EmitBasicReport(AC->getDecl(),
    369                      "Potential buffer overflow in call to 'getpw'",
    370                      "Security",
    371                      "The getpw() function is dangerous as it may overflow the "
    372                      "provided buffer. It is obsoleted by getpwuid().",
    373                      CELoc, &R, 1);
    374 }
    375 
    376 //===----------------------------------------------------------------------===//
    377 // Check: Any use of 'mktemp' is insecure.  It is obsoleted by mkstemp().
    378 // CWE-377: Insecure Temporary File
    379 //===----------------------------------------------------------------------===//
    380 
    381 void WalkAST::checkCall_mktemp(const CallExpr *CE, const FunctionDecl *FD) {
    382   if (!filter.check_mktemp) {
    383     // Fall back to the security check of looking for enough 'X's in the
    384     // format string, since that is a less severe warning.
    385     checkCall_mkstemp(CE, FD);
    386     return;
    387   }
    388 
    389   const FunctionProtoType *FPT
    390     = dyn_cast<FunctionProtoType>(FD->getType().IgnoreParens());
    391   if(!FPT)
    392     return;
    393 
    394   // Verify that the function takes a single argument.
    395   if (FPT->getNumArgs() != 1)
    396     return;
    397 
    398   // Verify that the argument is Pointer Type.
    399   const PointerType *PT = dyn_cast<PointerType>(FPT->getArgType(0));
    400   if (!PT)
    401     return;
    402 
    403   // Verify that the argument is a 'char*'.
    404   if (PT->getPointeeType().getUnqualifiedType() != BR.getContext().CharTy)
    405     return;
    406 
    407   // Issue a waring.
    408   SourceRange R = CE->getCallee()->getSourceRange();
    409   PathDiagnosticLocation CELoc =
    410     PathDiagnosticLocation::createBegin(CE, BR.getSourceManager(), AC);
    411   BR.EmitBasicReport(AC->getDecl(),
    412                      "Potential insecure temporary file in call 'mktemp'",
    413                      "Security",
    414                      "Call to function 'mktemp' is insecure as it always "
    415                      "creates or uses insecure temporary file.  Use 'mkstemp' "
    416                      "instead",
    417                      CELoc, &R, 1);
    418 }
    419 
    420 
    421 //===----------------------------------------------------------------------===//
    422 // Check: Use of 'mkstemp', 'mktemp', 'mkdtemp' should contain at least 6 X's.
    423 //===----------------------------------------------------------------------===//
    424 
    425 void WalkAST::checkCall_mkstemp(const CallExpr *CE, const FunctionDecl *FD) {
    426   if (!filter.check_mkstemp)
    427     return;
    428 
    429   StringRef Name = FD->getIdentifier()->getName();
    430   std::pair<signed, signed> ArgSuffix =
    431     llvm::StringSwitch<std::pair<signed, signed> >(Name)
    432       .Case("mktemp", std::make_pair(0,-1))
    433       .Case("mkstemp", std::make_pair(0,-1))
    434       .Case("mkdtemp", std::make_pair(0,-1))
    435       .Case("mkstemps", std::make_pair(0,1))
    436       .Default(std::make_pair(-1, -1));
    437 
    438   assert(ArgSuffix.first >= 0 && "Unsupported function");
    439 
    440   // Check if the number of arguments is consistent with out expectations.
    441   unsigned numArgs = CE->getNumArgs();
    442   if ((signed) numArgs <= ArgSuffix.first)
    443     return;
    444 
    445   const StringLiteral *strArg =
    446     dyn_cast<StringLiteral>(CE->getArg((unsigned)ArgSuffix.first)
    447                               ->IgnoreParenImpCasts());
    448 
    449   // Currently we only handle string literals.  It is possible to do better,
    450   // either by looking at references to const variables, or by doing real
    451   // flow analysis.
    452   if (!strArg || strArg->getCharByteWidth() != 1)
    453     return;
    454 
    455   // Count the number of X's, taking into account a possible cutoff suffix.
    456   StringRef str = strArg->getString();
    457   unsigned numX = 0;
    458   unsigned n = str.size();
    459 
    460   // Take into account the suffix.
    461   unsigned suffix = 0;
    462   if (ArgSuffix.second >= 0) {
    463     const Expr *suffixEx = CE->getArg((unsigned)ArgSuffix.second);
    464     llvm::APSInt Result;
    465     if (!suffixEx->EvaluateAsInt(Result, BR.getContext()))
    466       return;
    467     // FIXME: Issue a warning.
    468     if (Result.isNegative())
    469       return;
    470     suffix = (unsigned) Result.getZExtValue();
    471     n = (n > suffix) ? n - suffix : 0;
    472   }
    473 
    474   for (unsigned i = 0; i < n; ++i)
    475     if (str[i] == 'X') ++numX;
    476 
    477   if (numX >= 6)
    478     return;
    479 
    480   // Issue a warning.
    481   SourceRange R = strArg->getSourceRange();
    482   PathDiagnosticLocation CELoc =
    483     PathDiagnosticLocation::createBegin(CE, BR.getSourceManager(), AC);
    484   SmallString<512> buf;
    485   llvm::raw_svector_ostream out(buf);
    486   out << "Call to '" << Name << "' should have at least 6 'X's in the"
    487     " format string to be secure (" << numX << " 'X'";
    488   if (numX != 1)
    489     out << 's';
    490   out << " seen";
    491   if (suffix) {
    492     out << ", " << suffix << " character";
    493     if (suffix > 1)
    494       out << 's';
    495     out << " used as a suffix";
    496   }
    497   out << ')';
    498   BR.EmitBasicReport(AC->getDecl(),
    499                      "Insecure temporary file creation", "Security",
    500                      out.str(), CELoc, &R, 1);
    501 }
    502 
    503 //===----------------------------------------------------------------------===//
    504 // Check: Any use of 'strcpy' is insecure.
    505 //
    506 // CWE-119: Improper Restriction of Operations within
    507 // the Bounds of a Memory Buffer
    508 //===----------------------------------------------------------------------===//
    509 void WalkAST::checkCall_strcpy(const CallExpr *CE, const FunctionDecl *FD) {
    510   if (!filter.check_strcpy)
    511     return;
    512 
    513   if (!checkCall_strCommon(CE, FD))
    514     return;
    515 
    516   // Issue a warning.
    517   SourceRange R = CE->getCallee()->getSourceRange();
    518   PathDiagnosticLocation CELoc =
    519     PathDiagnosticLocation::createBegin(CE, BR.getSourceManager(), AC);
    520   BR.EmitBasicReport(AC->getDecl(),
    521                      "Potential insecure memory buffer bounds restriction in "
    522                      "call 'strcpy'",
    523                      "Security",
    524                      "Call to function 'strcpy' is insecure as it does not "
    525                      "provide bounding of the memory buffer. Replace "
    526                      "unbounded copy functions with analogous functions that "
    527                      "support length arguments such as 'strlcpy'. CWE-119.",
    528                      CELoc, &R, 1);
    529 }
    530 
    531 //===----------------------------------------------------------------------===//
    532 // Check: Any use of 'strcat' is insecure.
    533 //
    534 // CWE-119: Improper Restriction of Operations within
    535 // the Bounds of a Memory Buffer
    536 //===----------------------------------------------------------------------===//
    537 void WalkAST::checkCall_strcat(const CallExpr *CE, const FunctionDecl *FD) {
    538   if (!filter.check_strcpy)
    539     return;
    540 
    541   if (!checkCall_strCommon(CE, FD))
    542     return;
    543 
    544   // Issue a warning.
    545   SourceRange R = CE->getCallee()->getSourceRange();
    546   PathDiagnosticLocation CELoc =
    547     PathDiagnosticLocation::createBegin(CE, BR.getSourceManager(), AC);
    548   BR.EmitBasicReport(AC->getDecl(),
    549                      "Potential insecure memory buffer bounds restriction in "
    550                      "call 'strcat'",
    551                      "Security",
    552                      "Call to function 'strcat' is insecure as it does not "
    553                      "provide bounding of the memory buffer. Replace "
    554                      "unbounded copy functions with analogous functions that "
    555                      "support length arguments such as 'strlcat'. CWE-119.",
    556                      CELoc, &R, 1);
    557 }
    558 
    559 //===----------------------------------------------------------------------===//
    560 // Common check for str* functions with no bounds parameters.
    561 //===----------------------------------------------------------------------===//
    562 bool WalkAST::checkCall_strCommon(const CallExpr *CE, const FunctionDecl *FD) {
    563   const FunctionProtoType *FPT
    564     = dyn_cast<FunctionProtoType>(FD->getType().IgnoreParens());
    565   if (!FPT)
    566     return false;
    567 
    568   // Verify the function takes two arguments, three in the _chk version.
    569   int numArgs = FPT->getNumArgs();
    570   if (numArgs != 2 && numArgs != 3)
    571     return false;
    572 
    573   // Verify the type for both arguments.
    574   for (int i = 0; i < 2; i++) {
    575     // Verify that the arguments are pointers.
    576     const PointerType *PT = dyn_cast<PointerType>(FPT->getArgType(i));
    577     if (!PT)
    578       return false;
    579 
    580     // Verify that the argument is a 'char*'.
    581     if (PT->getPointeeType().getUnqualifiedType() != BR.getContext().CharTy)
    582       return false;
    583   }
    584 
    585   return true;
    586 }
    587 
    588 //===----------------------------------------------------------------------===//
    589 // Check: Linear congruent random number generators should not be used
    590 // Originally: <rdar://problem/63371000>
    591 // CWE-338: Use of cryptographically weak prng
    592 //===----------------------------------------------------------------------===//
    593 
    594 void WalkAST::checkCall_rand(const CallExpr *CE, const FunctionDecl *FD) {
    595   if (!filter.check_rand || !CheckRand)
    596     return;
    597 
    598   const FunctionProtoType *FTP
    599     = dyn_cast<FunctionProtoType>(FD->getType().IgnoreParens());
    600   if (!FTP)
    601     return;
    602 
    603   if (FTP->getNumArgs() == 1) {
    604     // Is the argument an 'unsigned short *'?
    605     // (Actually any integer type is allowed.)
    606     const PointerType *PT = dyn_cast<PointerType>(FTP->getArgType(0));
    607     if (!PT)
    608       return;
    609 
    610     if (! PT->getPointeeType()->isIntegerType())
    611       return;
    612   }
    613   else if (FTP->getNumArgs() != 0)
    614     return;
    615 
    616   // Issue a warning.
    617   SmallString<256> buf1;
    618   llvm::raw_svector_ostream os1(buf1);
    619   os1 << '\'' << *FD << "' is a poor random number generator";
    620 
    621   SmallString<256> buf2;
    622   llvm::raw_svector_ostream os2(buf2);
    623   os2 << "Function '" << *FD
    624       << "' is obsolete because it implements a poor random number generator."
    625       << "  Use 'arc4random' instead";
    626 
    627   SourceRange R = CE->getCallee()->getSourceRange();
    628   PathDiagnosticLocation CELoc =
    629     PathDiagnosticLocation::createBegin(CE, BR.getSourceManager(), AC);
    630   BR.EmitBasicReport(AC->getDecl(), os1.str(), "Security", os2.str(),
    631                      CELoc, &R, 1);
    632 }
    633 
    634 //===----------------------------------------------------------------------===//
    635 // Check: 'random' should not be used
    636 // Originally: <rdar://problem/63371000>
    637 //===----------------------------------------------------------------------===//
    638 
    639 void WalkAST::checkCall_random(const CallExpr *CE, const FunctionDecl *FD) {
    640   if (!CheckRand || !filter.check_rand)
    641     return;
    642 
    643   const FunctionProtoType *FTP
    644     = dyn_cast<FunctionProtoType>(FD->getType().IgnoreParens());
    645   if (!FTP)
    646     return;
    647 
    648   // Verify that the function takes no argument.
    649   if (FTP->getNumArgs() != 0)
    650     return;
    651 
    652   // Issue a warning.
    653   SourceRange R = CE->getCallee()->getSourceRange();
    654   PathDiagnosticLocation CELoc =
    655     PathDiagnosticLocation::createBegin(CE, BR.getSourceManager(), AC);
    656   BR.EmitBasicReport(AC->getDecl(),
    657                      "'random' is not a secure random number generator",
    658                      "Security",
    659                      "The 'random' function produces a sequence of values that "
    660                      "an adversary may be able to predict.  Use 'arc4random' "
    661                      "instead", CELoc, &R, 1);
    662 }
    663 
    664 //===----------------------------------------------------------------------===//
    665 // Check: 'vfork' should not be used.
    666 // POS33-C: Do not use vfork().
    667 //===----------------------------------------------------------------------===//
    668 
    669 void WalkAST::checkCall_vfork(const CallExpr *CE, const FunctionDecl *FD) {
    670   if (!filter.check_vfork)
    671     return;
    672 
    673   // All calls to vfork() are insecure, issue a warning.
    674   SourceRange R = CE->getCallee()->getSourceRange();
    675   PathDiagnosticLocation CELoc =
    676     PathDiagnosticLocation::createBegin(CE, BR.getSourceManager(), AC);
    677   BR.EmitBasicReport(AC->getDecl(),
    678                      "Potential insecure implementation-specific behavior in "
    679                      "call 'vfork'",
    680                      "Security",
    681                      "Call to function 'vfork' is insecure as it can lead to "
    682                      "denial of service situations in the parent process. "
    683                      "Replace calls to vfork with calls to the safer "
    684                      "'posix_spawn' function",
    685                      CELoc, &R, 1);
    686 }
    687 
    688 //===----------------------------------------------------------------------===//
    689 // Check: Should check whether privileges are dropped successfully.
    690 // Originally: <rdar://problem/6337132>
    691 //===----------------------------------------------------------------------===//
    692 
    693 void WalkAST::checkUncheckedReturnValue(CallExpr *CE) {
    694   if (!filter.check_UncheckedReturn)
    695     return;
    696 
    697   const FunctionDecl *FD = CE->getDirectCallee();
    698   if (!FD)
    699     return;
    700 
    701   if (II_setid[0] == NULL) {
    702     static const char * const identifiers[num_setids] = {
    703       "setuid", "setgid", "seteuid", "setegid",
    704       "setreuid", "setregid"
    705     };
    706 
    707     for (size_t i = 0; i < num_setids; i++)
    708       II_setid[i] = &BR.getContext().Idents.get(identifiers[i]);
    709   }
    710 
    711   const IdentifierInfo *id = FD->getIdentifier();
    712   size_t identifierid;
    713 
    714   for (identifierid = 0; identifierid < num_setids; identifierid++)
    715     if (id == II_setid[identifierid])
    716       break;
    717 
    718   if (identifierid >= num_setids)
    719     return;
    720 
    721   const FunctionProtoType *FTP
    722     = dyn_cast<FunctionProtoType>(FD->getType().IgnoreParens());
    723   if (!FTP)
    724     return;
    725 
    726   // Verify that the function takes one or two arguments (depending on
    727   //   the function).
    728   if (FTP->getNumArgs() != (identifierid < 4 ? 1 : 2))
    729     return;
    730 
    731   // The arguments must be integers.
    732   for (unsigned i = 0; i < FTP->getNumArgs(); i++)
    733     if (! FTP->getArgType(i)->isIntegerType())
    734       return;
    735 
    736   // Issue a warning.
    737   SmallString<256> buf1;
    738   llvm::raw_svector_ostream os1(buf1);
    739   os1 << "Return value is not checked in call to '" << *FD << '\'';
    740 
    741   SmallString<256> buf2;
    742   llvm::raw_svector_ostream os2(buf2);
    743   os2 << "The return value from the call to '" << *FD
    744       << "' is not checked.  If an error occurs in '" << *FD
    745       << "', the following code may execute with unexpected privileges";
    746 
    747   SourceRange R = CE->getCallee()->getSourceRange();
    748   PathDiagnosticLocation CELoc =
    749     PathDiagnosticLocation::createBegin(CE, BR.getSourceManager(), AC);
    750   BR.EmitBasicReport(AC->getDecl(), os1.str(), "Security", os2.str(),
    751                      CELoc, &R, 1);
    752 }
    753 
    754 //===----------------------------------------------------------------------===//
    755 // SecuritySyntaxChecker
    756 //===----------------------------------------------------------------------===//
    757 
    758 namespace {
    759 class SecuritySyntaxChecker : public Checker<check::ASTCodeBody> {
    760 public:
    761   ChecksFilter filter;
    762 
    763   void checkASTCodeBody(const Decl *D, AnalysisManager& mgr,
    764                         BugReporter &BR) const {
    765     WalkAST walker(BR, mgr.getAnalysisDeclContext(D), filter);
    766     walker.Visit(D->getBody());
    767   }
    768 };
    769 }
    770 
    771 #define REGISTER_CHECKER(name) \
    772 void ento::register##name(CheckerManager &mgr) {\
    773   mgr.registerChecker<SecuritySyntaxChecker>()->filter.check_##name = true;\
    774 }
    775 
    776 REGISTER_CHECKER(gets)
    777 REGISTER_CHECKER(getpw)
    778 REGISTER_CHECKER(mkstemp)
    779 REGISTER_CHECKER(mktemp)
    780 REGISTER_CHECKER(strcpy)
    781 REGISTER_CHECKER(rand)
    782 REGISTER_CHECKER(vfork)
    783 REGISTER_CHECKER(FloatLoopCounter)
    784 REGISTER_CHECKER(UncheckedReturn)
    785 
    786 
    787