clang API Documentation

CheckSecuritySyntaxOnly.cpp
Go to the documentation of this file.
00001 //==- CheckSecuritySyntaxOnly.cpp - Basic security checks --------*- C++ -*-==//
00002 //
00003 //                     The LLVM Compiler Infrastructure
00004 //
00005 // This file is distributed under the University of Illinois Open Source
00006 // License. See LICENSE.TXT for details.
00007 //
00008 //===----------------------------------------------------------------------===//
00009 //
00010 //  This file defines a set of flow-insensitive security checks.
00011 //
00012 //===----------------------------------------------------------------------===//
00013 
00014 #include "ClangSACheckers.h"
00015 #include "clang/AST/StmtVisitor.h"
00016 #include "clang/Analysis/AnalysisContext.h"
00017 #include "clang/Basic/TargetInfo.h"
00018 #include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h"
00019 #include "clang/StaticAnalyzer/Core/Checker.h"
00020 #include "clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h"
00021 #include "llvm/ADT/SmallString.h"
00022 #include "llvm/ADT/StringSwitch.h"
00023 #include "llvm/Support/raw_ostream.h"
00024 
00025 using namespace clang;
00026 using namespace ento;
00027 
00028 static bool isArc4RandomAvailable(const ASTContext &Ctx) {
00029   const llvm::Triple &T = Ctx.getTargetInfo().getTriple();
00030   return T.getVendor() == llvm::Triple::Apple ||
00031          T.getOS() == llvm::Triple::FreeBSD ||
00032          T.getOS() == llvm::Triple::NetBSD ||
00033          T.getOS() == llvm::Triple::OpenBSD ||
00034          T.getOS() == llvm::Triple::Bitrig ||
00035          T.getOS() == llvm::Triple::DragonFly;
00036 }
00037 
00038 namespace {
00039 struct ChecksFilter {
00040   DefaultBool check_gets;
00041   DefaultBool check_getpw;
00042   DefaultBool check_mktemp;
00043   DefaultBool check_mkstemp;
00044   DefaultBool check_strcpy;
00045   DefaultBool check_rand;
00046   DefaultBool check_vfork;
00047   DefaultBool check_FloatLoopCounter;
00048   DefaultBool check_UncheckedReturn;
00049 
00050   CheckName checkName_gets;
00051   CheckName checkName_getpw;
00052   CheckName checkName_mktemp;
00053   CheckName checkName_mkstemp;
00054   CheckName checkName_strcpy;
00055   CheckName checkName_rand;
00056   CheckName checkName_vfork;
00057   CheckName checkName_FloatLoopCounter;
00058   CheckName checkName_UncheckedReturn;
00059 };
00060 
00061 class WalkAST : public StmtVisitor<WalkAST> {
00062   BugReporter &BR;
00063   AnalysisDeclContext* AC;
00064   enum { num_setids = 6 };
00065   IdentifierInfo *II_setid[num_setids];
00066 
00067   const bool CheckRand;
00068   const ChecksFilter &filter;
00069 
00070 public:
00071   WalkAST(BugReporter &br, AnalysisDeclContext* ac,
00072           const ChecksFilter &f)
00073   : BR(br), AC(ac), II_setid(),
00074     CheckRand(isArc4RandomAvailable(BR.getContext())),
00075     filter(f) {}
00076 
00077   // Statement visitor methods.
00078   void VisitCallExpr(CallExpr *CE);
00079   void VisitForStmt(ForStmt *S);
00080   void VisitCompoundStmt (CompoundStmt *S);
00081   void VisitStmt(Stmt *S) { VisitChildren(S); }
00082 
00083   void VisitChildren(Stmt *S);
00084 
00085   // Helpers.
00086   bool checkCall_strCommon(const CallExpr *CE, const FunctionDecl *FD);
00087 
00088   typedef void (WalkAST::*FnCheck)(const CallExpr *,
00089            const FunctionDecl *);
00090 
00091   // Checker-specific methods.
00092   void checkLoopConditionForFloat(const ForStmt *FS);
00093   void checkCall_gets(const CallExpr *CE, const FunctionDecl *FD);
00094   void checkCall_getpw(const CallExpr *CE, const FunctionDecl *FD);
00095   void checkCall_mktemp(const CallExpr *CE, const FunctionDecl *FD);
00096   void checkCall_mkstemp(const CallExpr *CE, const FunctionDecl *FD);
00097   void checkCall_strcpy(const CallExpr *CE, const FunctionDecl *FD);
00098   void checkCall_strcat(const CallExpr *CE, const FunctionDecl *FD);
00099   void checkCall_rand(const CallExpr *CE, const FunctionDecl *FD);
00100   void checkCall_random(const CallExpr *CE, const FunctionDecl *FD);
00101   void checkCall_vfork(const CallExpr *CE, const FunctionDecl *FD);
00102   void checkUncheckedReturnValue(CallExpr *CE);
00103 };
00104 } // end anonymous namespace
00105 
00106 //===----------------------------------------------------------------------===//
00107 // AST walking.
00108 //===----------------------------------------------------------------------===//
00109 
00110 void WalkAST::VisitChildren(Stmt *S) {
00111   for (Stmt::child_iterator I = S->child_begin(), E = S->child_end(); I!=E; ++I)
00112     if (Stmt *child = *I)
00113       Visit(child);
00114 }
00115 
00116 void WalkAST::VisitCallExpr(CallExpr *CE) {
00117   // Get the callee.  
00118   const FunctionDecl *FD = CE->getDirectCallee();
00119 
00120   if (!FD)
00121     return;
00122 
00123   // Get the name of the callee. If it's a builtin, strip off the prefix.
00124   IdentifierInfo *II = FD->getIdentifier();
00125   if (!II)   // if no identifier, not a simple C function
00126     return;
00127   StringRef Name = II->getName();
00128   if (Name.startswith("__builtin_"))
00129     Name = Name.substr(10);
00130 
00131   // Set the evaluation function by switching on the callee name.
00132   FnCheck evalFunction = llvm::StringSwitch<FnCheck>(Name)
00133     .Case("gets", &WalkAST::checkCall_gets)
00134     .Case("getpw", &WalkAST::checkCall_getpw)
00135     .Case("mktemp", &WalkAST::checkCall_mktemp)
00136     .Case("mkstemp", &WalkAST::checkCall_mkstemp)
00137     .Case("mkdtemp", &WalkAST::checkCall_mkstemp)
00138     .Case("mkstemps", &WalkAST::checkCall_mkstemp)
00139     .Cases("strcpy", "__strcpy_chk", &WalkAST::checkCall_strcpy)
00140     .Cases("strcat", "__strcat_chk", &WalkAST::checkCall_strcat)
00141     .Case("drand48", &WalkAST::checkCall_rand)
00142     .Case("erand48", &WalkAST::checkCall_rand)
00143     .Case("jrand48", &WalkAST::checkCall_rand)
00144     .Case("lrand48", &WalkAST::checkCall_rand)
00145     .Case("mrand48", &WalkAST::checkCall_rand)
00146     .Case("nrand48", &WalkAST::checkCall_rand)
00147     .Case("lcong48", &WalkAST::checkCall_rand)
00148     .Case("rand", &WalkAST::checkCall_rand)
00149     .Case("rand_r", &WalkAST::checkCall_rand)
00150     .Case("random", &WalkAST::checkCall_random)
00151     .Case("vfork", &WalkAST::checkCall_vfork)
00152     .Default(nullptr);
00153 
00154   // If the callee isn't defined, it is not of security concern.
00155   // Check and evaluate the call.
00156   if (evalFunction)
00157     (this->*evalFunction)(CE, FD);
00158 
00159   // Recurse and check children.
00160   VisitChildren(CE);
00161 }
00162 
00163 void WalkAST::VisitCompoundStmt(CompoundStmt *S) {
00164   for (Stmt::child_iterator I = S->child_begin(), E = S->child_end(); I!=E; ++I)
00165     if (Stmt *child = *I) {
00166       if (CallExpr *CE = dyn_cast<CallExpr>(child))
00167         checkUncheckedReturnValue(CE);
00168       Visit(child);
00169     }
00170 }
00171 
00172 void WalkAST::VisitForStmt(ForStmt *FS) {
00173   checkLoopConditionForFloat(FS);
00174 
00175   // Recurse and check children.
00176   VisitChildren(FS);
00177 }
00178 
00179 //===----------------------------------------------------------------------===//
00180 // Check: floating poing variable used as loop counter.
00181 // Originally: <rdar://problem/6336718>
00182 // Implements: CERT security coding advisory FLP-30.
00183 //===----------------------------------------------------------------------===//
00184 
00185 static const DeclRefExpr*
00186 getIncrementedVar(const Expr *expr, const VarDecl *x, const VarDecl *y) {
00187   expr = expr->IgnoreParenCasts();
00188 
00189   if (const BinaryOperator *B = dyn_cast<BinaryOperator>(expr)) {
00190     if (!(B->isAssignmentOp() || B->isCompoundAssignmentOp() ||
00191           B->getOpcode() == BO_Comma))
00192       return nullptr;
00193 
00194     if (const DeclRefExpr *lhs = getIncrementedVar(B->getLHS(), x, y))
00195       return lhs;
00196 
00197     if (const DeclRefExpr *rhs = getIncrementedVar(B->getRHS(), x, y))
00198       return rhs;
00199 
00200     return nullptr;
00201   }
00202 
00203   if (const DeclRefExpr *DR = dyn_cast<DeclRefExpr>(expr)) {
00204     const NamedDecl *ND = DR->getDecl();
00205     return ND == x || ND == y ? DR : nullptr;
00206   }
00207 
00208   if (const UnaryOperator *U = dyn_cast<UnaryOperator>(expr))
00209     return U->isIncrementDecrementOp()
00210       ? getIncrementedVar(U->getSubExpr(), x, y) : nullptr;
00211 
00212   return nullptr;
00213 }
00214 
00215 /// CheckLoopConditionForFloat - This check looks for 'for' statements that
00216 ///  use a floating point variable as a loop counter.
00217 ///  CERT: FLP30-C, FLP30-CPP.
00218 ///
00219 void WalkAST::checkLoopConditionForFloat(const ForStmt *FS) {
00220   if (!filter.check_FloatLoopCounter)
00221     return;
00222 
00223   // Does the loop have a condition?
00224   const Expr *condition = FS->getCond();
00225 
00226   if (!condition)
00227     return;
00228 
00229   // Does the loop have an increment?
00230   const Expr *increment = FS->getInc();
00231 
00232   if (!increment)
00233     return;
00234 
00235   // Strip away '()' and casts.
00236   condition = condition->IgnoreParenCasts();
00237   increment = increment->IgnoreParenCasts();
00238 
00239   // Is the loop condition a comparison?
00240   const BinaryOperator *B = dyn_cast<BinaryOperator>(condition);
00241 
00242   if (!B)
00243     return;
00244 
00245   // Is this a comparison?
00246   if (!(B->isRelationalOp() || B->isEqualityOp()))
00247     return;
00248 
00249   // Are we comparing variables?
00250   const DeclRefExpr *drLHS =
00251     dyn_cast<DeclRefExpr>(B->getLHS()->IgnoreParenLValueCasts());
00252   const DeclRefExpr *drRHS =
00253     dyn_cast<DeclRefExpr>(B->getRHS()->IgnoreParenLValueCasts());
00254 
00255   // Does at least one of the variables have a floating point type?
00256   drLHS = drLHS && drLHS->getType()->isRealFloatingType() ? drLHS : nullptr;
00257   drRHS = drRHS && drRHS->getType()->isRealFloatingType() ? drRHS : nullptr;
00258 
00259   if (!drLHS && !drRHS)
00260     return;
00261 
00262   const VarDecl *vdLHS = drLHS ? dyn_cast<VarDecl>(drLHS->getDecl()) : nullptr;
00263   const VarDecl *vdRHS = drRHS ? dyn_cast<VarDecl>(drRHS->getDecl()) : nullptr;
00264 
00265   if (!vdLHS && !vdRHS)
00266     return;
00267 
00268   // Does either variable appear in increment?
00269   const DeclRefExpr *drInc = getIncrementedVar(increment, vdLHS, vdRHS);
00270 
00271   if (!drInc)
00272     return;
00273 
00274   // Emit the error.  First figure out which DeclRefExpr in the condition
00275   // referenced the compared variable.
00276   assert(drInc->getDecl());
00277   const DeclRefExpr *drCond = vdLHS == drInc->getDecl() ? drLHS : drRHS;
00278 
00279   SmallVector<SourceRange, 2> ranges;
00280   SmallString<256> sbuf;
00281   llvm::raw_svector_ostream os(sbuf);
00282 
00283   os << "Variable '" << drCond->getDecl()->getName()
00284      << "' with floating point type '" << drCond->getType().getAsString()
00285      << "' should not be used as a loop counter";
00286 
00287   ranges.push_back(drCond->getSourceRange());
00288   ranges.push_back(drInc->getSourceRange());
00289 
00290   const char *bugType = "Floating point variable used as loop counter";
00291 
00292   PathDiagnosticLocation FSLoc =
00293     PathDiagnosticLocation::createBegin(FS, BR.getSourceManager(), AC);
00294   BR.EmitBasicReport(AC->getDecl(), filter.checkName_FloatLoopCounter,
00295                      bugType, "Security", os.str(),
00296                      FSLoc, ranges);
00297 }
00298 
00299 //===----------------------------------------------------------------------===//
00300 // Check: Any use of 'gets' is insecure.
00301 // Originally: <rdar://problem/6335715>
00302 // Implements (part of): 300-BSI (buildsecurityin.us-cert.gov)
00303 // CWE-242: Use of Inherently Dangerous Function
00304 //===----------------------------------------------------------------------===//
00305 
00306 void WalkAST::checkCall_gets(const CallExpr *CE, const FunctionDecl *FD) {
00307   if (!filter.check_gets)
00308     return;
00309   
00310   const FunctionProtoType *FPT = FD->getType()->getAs<FunctionProtoType>();
00311   if (!FPT)
00312     return;
00313 
00314   // Verify that the function takes a single argument.
00315   if (FPT->getNumParams() != 1)
00316     return;
00317 
00318   // Is the argument a 'char*'?
00319   const PointerType *PT = FPT->getParamType(0)->getAs<PointerType>();
00320   if (!PT)
00321     return;
00322 
00323   if (PT->getPointeeType().getUnqualifiedType() != BR.getContext().CharTy)
00324     return;
00325 
00326   // Issue a warning.
00327   PathDiagnosticLocation CELoc =
00328     PathDiagnosticLocation::createBegin(CE, BR.getSourceManager(), AC);
00329   BR.EmitBasicReport(AC->getDecl(), filter.checkName_gets,
00330                      "Potential buffer overflow in call to 'gets'",
00331                      "Security",
00332                      "Call to function 'gets' is extremely insecure as it can "
00333                      "always result in a buffer overflow",
00334                      CELoc, CE->getCallee()->getSourceRange());
00335 }
00336 
00337 //===----------------------------------------------------------------------===//
00338 // Check: Any use of 'getpwd' is insecure.
00339 // CWE-477: Use of Obsolete Functions
00340 //===----------------------------------------------------------------------===//
00341 
00342 void WalkAST::checkCall_getpw(const CallExpr *CE, const FunctionDecl *FD) {
00343   if (!filter.check_getpw)
00344     return;
00345 
00346   const FunctionProtoType *FPT = FD->getType()->getAs<FunctionProtoType>();
00347   if (!FPT)
00348     return;
00349 
00350   // Verify that the function takes two arguments.
00351   if (FPT->getNumParams() != 2)
00352     return;
00353 
00354   // Verify the first argument type is integer.
00355   if (!FPT->getParamType(0)->isIntegralOrUnscopedEnumerationType())
00356     return;
00357 
00358   // Verify the second argument type is char*.
00359   const PointerType *PT = FPT->getParamType(1)->getAs<PointerType>();
00360   if (!PT)
00361     return;
00362 
00363   if (PT->getPointeeType().getUnqualifiedType() != BR.getContext().CharTy)
00364     return;
00365 
00366   // Issue a warning.
00367   PathDiagnosticLocation CELoc =
00368     PathDiagnosticLocation::createBegin(CE, BR.getSourceManager(), AC);
00369   BR.EmitBasicReport(AC->getDecl(), filter.checkName_getpw,
00370                      "Potential buffer overflow in call to 'getpw'",
00371                      "Security",
00372                      "The getpw() function is dangerous as it may overflow the "
00373                      "provided buffer. It is obsoleted by getpwuid().",
00374                      CELoc, CE->getCallee()->getSourceRange());
00375 }
00376 
00377 //===----------------------------------------------------------------------===//
00378 // Check: Any use of 'mktemp' is insecure.  It is obsoleted by mkstemp().
00379 // CWE-377: Insecure Temporary File
00380 //===----------------------------------------------------------------------===//
00381 
00382 void WalkAST::checkCall_mktemp(const CallExpr *CE, const FunctionDecl *FD) {
00383   if (!filter.check_mktemp) {
00384     // Fall back to the security check of looking for enough 'X's in the
00385     // format string, since that is a less severe warning.
00386     checkCall_mkstemp(CE, FD);
00387     return;
00388   }
00389 
00390   const FunctionProtoType *FPT = FD->getType()->getAs<FunctionProtoType>();
00391   if(!FPT)
00392     return;
00393 
00394   // Verify that the function takes a single argument.
00395   if (FPT->getNumParams() != 1)
00396     return;
00397 
00398   // Verify that the argument is Pointer Type.
00399   const PointerType *PT = FPT->getParamType(0)->getAs<PointerType>();
00400   if (!PT)
00401     return;
00402 
00403   // Verify that the argument is a 'char*'.
00404   if (PT->getPointeeType().getUnqualifiedType() != BR.getContext().CharTy)
00405     return;
00406 
00407   // Issue a warning.
00408   PathDiagnosticLocation CELoc =
00409     PathDiagnosticLocation::createBegin(CE, BR.getSourceManager(), AC);
00410   BR.EmitBasicReport(AC->getDecl(), filter.checkName_mktemp,
00411                      "Potential insecure temporary file in call 'mktemp'",
00412                      "Security",
00413                      "Call to function 'mktemp' is insecure as it always "
00414                      "creates or uses insecure temporary file.  Use 'mkstemp' "
00415                      "instead",
00416                      CELoc, CE->getCallee()->getSourceRange());
00417 }
00418 
00419 
00420 //===----------------------------------------------------------------------===//
00421 // Check: Use of 'mkstemp', 'mktemp', 'mkdtemp' should contain at least 6 X's.
00422 //===----------------------------------------------------------------------===//
00423 
00424 void WalkAST::checkCall_mkstemp(const CallExpr *CE, const FunctionDecl *FD) {
00425   if (!filter.check_mkstemp)
00426     return;
00427 
00428   StringRef Name = FD->getIdentifier()->getName();
00429   std::pair<signed, signed> ArgSuffix =
00430     llvm::StringSwitch<std::pair<signed, signed> >(Name)
00431       .Case("mktemp", std::make_pair(0,-1))
00432       .Case("mkstemp", std::make_pair(0,-1))
00433       .Case("mkdtemp", std::make_pair(0,-1))
00434       .Case("mkstemps", std::make_pair(0,1))
00435       .Default(std::make_pair(-1, -1));
00436   
00437   assert(ArgSuffix.first >= 0 && "Unsupported function");
00438 
00439   // Check if the number of arguments is consistent with out expectations.
00440   unsigned numArgs = CE->getNumArgs();
00441   if ((signed) numArgs <= ArgSuffix.first)
00442     return;
00443   
00444   const StringLiteral *strArg =
00445     dyn_cast<StringLiteral>(CE->getArg((unsigned)ArgSuffix.first)
00446                               ->IgnoreParenImpCasts());
00447   
00448   // Currently we only handle string literals.  It is possible to do better,
00449   // either by looking at references to const variables, or by doing real
00450   // flow analysis.
00451   if (!strArg || strArg->getCharByteWidth() != 1)
00452     return;
00453 
00454   // Count the number of X's, taking into account a possible cutoff suffix.
00455   StringRef str = strArg->getString();
00456   unsigned numX = 0;
00457   unsigned n = str.size();
00458 
00459   // Take into account the suffix.
00460   unsigned suffix = 0;
00461   if (ArgSuffix.second >= 0) {
00462     const Expr *suffixEx = CE->getArg((unsigned)ArgSuffix.second);
00463     llvm::APSInt Result;
00464     if (!suffixEx->EvaluateAsInt(Result, BR.getContext()))
00465       return;
00466     // FIXME: Issue a warning.
00467     if (Result.isNegative())
00468       return;
00469     suffix = (unsigned) Result.getZExtValue();
00470     n = (n > suffix) ? n - suffix : 0;
00471   }
00472   
00473   for (unsigned i = 0; i < n; ++i)
00474     if (str[i] == 'X') ++numX;
00475   
00476   if (numX >= 6)
00477     return;
00478   
00479   // Issue a warning.
00480   PathDiagnosticLocation CELoc =
00481     PathDiagnosticLocation::createBegin(CE, BR.getSourceManager(), AC);
00482   SmallString<512> buf;
00483   llvm::raw_svector_ostream out(buf);
00484   out << "Call to '" << Name << "' should have at least 6 'X's in the"
00485     " format string to be secure (" << numX << " 'X'";
00486   if (numX != 1)
00487     out << 's';
00488   out << " seen";
00489   if (suffix) {
00490     out << ", " << suffix << " character";
00491     if (suffix > 1)
00492       out << 's';
00493     out << " used as a suffix";
00494   }
00495   out << ')';
00496   BR.EmitBasicReport(AC->getDecl(), filter.checkName_mkstemp,
00497                      "Insecure temporary file creation", "Security",
00498                      out.str(), CELoc, strArg->getSourceRange());
00499 }
00500 
00501 //===----------------------------------------------------------------------===//
00502 // Check: Any use of 'strcpy' is insecure.
00503 //
00504 // CWE-119: Improper Restriction of Operations within 
00505 // the Bounds of a Memory Buffer 
00506 //===----------------------------------------------------------------------===//
00507 void WalkAST::checkCall_strcpy(const CallExpr *CE, const FunctionDecl *FD) {
00508   if (!filter.check_strcpy)
00509     return;
00510   
00511   if (!checkCall_strCommon(CE, FD))
00512     return;
00513 
00514   // Issue a warning.
00515   PathDiagnosticLocation CELoc =
00516     PathDiagnosticLocation::createBegin(CE, BR.getSourceManager(), AC);
00517   BR.EmitBasicReport(AC->getDecl(), filter.checkName_strcpy,
00518                      "Potential insecure memory buffer bounds restriction in "
00519                      "call 'strcpy'",
00520                      "Security",
00521                      "Call to function 'strcpy' is insecure as it does not "
00522                      "provide bounding of the memory buffer. Replace "
00523                      "unbounded copy functions with analogous functions that "
00524                      "support length arguments such as 'strlcpy'. CWE-119.",
00525                      CELoc, CE->getCallee()->getSourceRange());
00526 }
00527 
00528 //===----------------------------------------------------------------------===//
00529 // Check: Any use of 'strcat' is insecure.
00530 //
00531 // CWE-119: Improper Restriction of Operations within 
00532 // the Bounds of a Memory Buffer 
00533 //===----------------------------------------------------------------------===//
00534 void WalkAST::checkCall_strcat(const CallExpr *CE, const FunctionDecl *FD) {
00535   if (!filter.check_strcpy)
00536     return;
00537 
00538   if (!checkCall_strCommon(CE, FD))
00539     return;
00540 
00541   // Issue a warning.
00542   PathDiagnosticLocation CELoc =
00543     PathDiagnosticLocation::createBegin(CE, BR.getSourceManager(), AC);
00544   BR.EmitBasicReport(AC->getDecl(), filter.checkName_strcpy,
00545                      "Potential insecure memory buffer bounds restriction in "
00546                      "call 'strcat'",
00547                      "Security",
00548                      "Call to function 'strcat' is insecure as it does not "
00549                      "provide bounding of the memory buffer. Replace "
00550                      "unbounded copy functions with analogous functions that "
00551                      "support length arguments such as 'strlcat'. CWE-119.",
00552                      CELoc, CE->getCallee()->getSourceRange());
00553 }
00554 
00555 //===----------------------------------------------------------------------===//
00556 // Common check for str* functions with no bounds parameters.
00557 //===----------------------------------------------------------------------===//
00558 bool WalkAST::checkCall_strCommon(const CallExpr *CE, const FunctionDecl *FD) {
00559   const FunctionProtoType *FPT = FD->getType()->getAs<FunctionProtoType>();
00560   if (!FPT)
00561     return false;
00562 
00563   // Verify the function takes two arguments, three in the _chk version.
00564   int numArgs = FPT->getNumParams();
00565   if (numArgs != 2 && numArgs != 3)
00566     return false;
00567 
00568   // Verify the type for both arguments.
00569   for (int i = 0; i < 2; i++) {
00570     // Verify that the arguments are pointers.
00571     const PointerType *PT = FPT->getParamType(i)->getAs<PointerType>();
00572     if (!PT)
00573       return false;
00574 
00575     // Verify that the argument is a 'char*'.
00576     if (PT->getPointeeType().getUnqualifiedType() != BR.getContext().CharTy)
00577       return false;
00578   }
00579 
00580   return true;
00581 }
00582 
00583 //===----------------------------------------------------------------------===//
00584 // Check: Linear congruent random number generators should not be used
00585 // Originally: <rdar://problem/63371000>
00586 // CWE-338: Use of cryptographically weak prng
00587 //===----------------------------------------------------------------------===//
00588 
00589 void WalkAST::checkCall_rand(const CallExpr *CE, const FunctionDecl *FD) {
00590   if (!filter.check_rand || !CheckRand)
00591     return;
00592 
00593   const FunctionProtoType *FTP = FD->getType()->getAs<FunctionProtoType>();
00594   if (!FTP)
00595     return;
00596 
00597   if (FTP->getNumParams() == 1) {
00598     // Is the argument an 'unsigned short *'?
00599     // (Actually any integer type is allowed.)
00600     const PointerType *PT = FTP->getParamType(0)->getAs<PointerType>();
00601     if (!PT)
00602       return;
00603 
00604     if (! PT->getPointeeType()->isIntegralOrUnscopedEnumerationType())
00605       return;
00606   } else if (FTP->getNumParams() != 0)
00607     return;
00608 
00609   // Issue a warning.
00610   SmallString<256> buf1;
00611   llvm::raw_svector_ostream os1(buf1);
00612   os1 << '\'' << *FD << "' is a poor random number generator";
00613 
00614   SmallString<256> buf2;
00615   llvm::raw_svector_ostream os2(buf2);
00616   os2 << "Function '" << *FD
00617       << "' is obsolete because it implements a poor random number generator."
00618       << "  Use 'arc4random' instead";
00619 
00620   PathDiagnosticLocation CELoc =
00621     PathDiagnosticLocation::createBegin(CE, BR.getSourceManager(), AC);
00622   BR.EmitBasicReport(AC->getDecl(), filter.checkName_rand, os1.str(),
00623                      "Security", os2.str(), CELoc,
00624                      CE->getCallee()->getSourceRange());
00625 }
00626 
00627 //===----------------------------------------------------------------------===//
00628 // Check: 'random' should not be used
00629 // Originally: <rdar://problem/63371000>
00630 //===----------------------------------------------------------------------===//
00631 
00632 void WalkAST::checkCall_random(const CallExpr *CE, const FunctionDecl *FD) {
00633   if (!CheckRand || !filter.check_rand)
00634     return;
00635 
00636   const FunctionProtoType *FTP = FD->getType()->getAs<FunctionProtoType>();
00637   if (!FTP)
00638     return;
00639 
00640   // Verify that the function takes no argument.
00641   if (FTP->getNumParams() != 0)
00642     return;
00643 
00644   // Issue a warning.
00645   PathDiagnosticLocation CELoc =
00646     PathDiagnosticLocation::createBegin(CE, BR.getSourceManager(), AC);
00647   BR.EmitBasicReport(AC->getDecl(), filter.checkName_rand,
00648                      "'random' is not a secure random number generator",
00649                      "Security",
00650                      "The 'random' function produces a sequence of values that "
00651                      "an adversary may be able to predict.  Use 'arc4random' "
00652                      "instead", CELoc, CE->getCallee()->getSourceRange());
00653 }
00654 
00655 //===----------------------------------------------------------------------===//
00656 // Check: 'vfork' should not be used.
00657 // POS33-C: Do not use vfork().
00658 //===----------------------------------------------------------------------===//
00659 
00660 void WalkAST::checkCall_vfork(const CallExpr *CE, const FunctionDecl *FD) {
00661   if (!filter.check_vfork)
00662     return;
00663 
00664   // All calls to vfork() are insecure, issue a warning.
00665   PathDiagnosticLocation CELoc =
00666     PathDiagnosticLocation::createBegin(CE, BR.getSourceManager(), AC);
00667   BR.EmitBasicReport(AC->getDecl(), filter.checkName_vfork,
00668                      "Potential insecure implementation-specific behavior in "
00669                      "call 'vfork'",
00670                      "Security",
00671                      "Call to function 'vfork' is insecure as it can lead to "
00672                      "denial of service situations in the parent process. "
00673                      "Replace calls to vfork with calls to the safer "
00674                      "'posix_spawn' function",
00675                      CELoc, CE->getCallee()->getSourceRange());
00676 }
00677 
00678 //===----------------------------------------------------------------------===//
00679 // Check: Should check whether privileges are dropped successfully.
00680 // Originally: <rdar://problem/6337132>
00681 //===----------------------------------------------------------------------===//
00682 
00683 void WalkAST::checkUncheckedReturnValue(CallExpr *CE) {
00684   if (!filter.check_UncheckedReturn)
00685     return;
00686   
00687   const FunctionDecl *FD = CE->getDirectCallee();
00688   if (!FD)
00689     return;
00690 
00691   if (II_setid[0] == nullptr) {
00692     static const char * const identifiers[num_setids] = {
00693       "setuid", "setgid", "seteuid", "setegid",
00694       "setreuid", "setregid"
00695     };
00696 
00697     for (size_t i = 0; i < num_setids; i++)
00698       II_setid[i] = &BR.getContext().Idents.get(identifiers[i]);
00699   }
00700 
00701   const IdentifierInfo *id = FD->getIdentifier();
00702   size_t identifierid;
00703 
00704   for (identifierid = 0; identifierid < num_setids; identifierid++)
00705     if (id == II_setid[identifierid])
00706       break;
00707 
00708   if (identifierid >= num_setids)
00709     return;
00710 
00711   const FunctionProtoType *FTP = FD->getType()->getAs<FunctionProtoType>();
00712   if (!FTP)
00713     return;
00714 
00715   // Verify that the function takes one or two arguments (depending on
00716   //   the function).
00717   if (FTP->getNumParams() != (identifierid < 4 ? 1 : 2))
00718     return;
00719 
00720   // The arguments must be integers.
00721   for (unsigned i = 0; i < FTP->getNumParams(); i++)
00722     if (!FTP->getParamType(i)->isIntegralOrUnscopedEnumerationType())
00723       return;
00724 
00725   // Issue a warning.
00726   SmallString<256> buf1;
00727   llvm::raw_svector_ostream os1(buf1);
00728   os1 << "Return value is not checked in call to '" << *FD << '\'';
00729 
00730   SmallString<256> buf2;
00731   llvm::raw_svector_ostream os2(buf2);
00732   os2 << "The return value from the call to '" << *FD
00733       << "' is not checked.  If an error occurs in '" << *FD
00734       << "', the following code may execute with unexpected privileges";
00735 
00736   PathDiagnosticLocation CELoc =
00737     PathDiagnosticLocation::createBegin(CE, BR.getSourceManager(), AC);
00738   BR.EmitBasicReport(AC->getDecl(), filter.checkName_UncheckedReturn, os1.str(),
00739                      "Security", os2.str(), CELoc,
00740                      CE->getCallee()->getSourceRange());
00741 }
00742 
00743 //===----------------------------------------------------------------------===//
00744 // SecuritySyntaxChecker
00745 //===----------------------------------------------------------------------===//
00746 
00747 namespace {
00748 class SecuritySyntaxChecker : public Checker<check::ASTCodeBody> {
00749 public:
00750   ChecksFilter filter;
00751   
00752   void checkASTCodeBody(const Decl *D, AnalysisManager& mgr,
00753                         BugReporter &BR) const {
00754     WalkAST walker(BR, mgr.getAnalysisDeclContext(D), filter);
00755     walker.Visit(D->getBody());
00756   }
00757 };
00758 }
00759 
00760 #define REGISTER_CHECKER(name)                                                 \
00761   void ento::register##name(CheckerManager &mgr) {                             \
00762     SecuritySyntaxChecker *checker =                                           \
00763         mgr.registerChecker<SecuritySyntaxChecker>();                          \
00764     checker->filter.check_##name = true;                                       \
00765     checker->filter.checkName_##name = mgr.getCurrentCheckName();              \
00766   }
00767 
00768 REGISTER_CHECKER(gets)
00769 REGISTER_CHECKER(getpw)
00770 REGISTER_CHECKER(mkstemp)
00771 REGISTER_CHECKER(mktemp)
00772 REGISTER_CHECKER(strcpy)
00773 REGISTER_CHECKER(rand)
00774 REGISTER_CHECKER(vfork)
00775 REGISTER_CHECKER(FloatLoopCounter)
00776 REGISTER_CHECKER(UncheckedReturn)
00777 
00778