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