12754fe60SDimitry Andric //==- CheckSecuritySyntaxOnly.cpp - Basic security checks --------*- C++ -*-==//
22754fe60SDimitry Andric //
32754fe60SDimitry Andric //                     The LLVM Compiler Infrastructure
42754fe60SDimitry Andric //
52754fe60SDimitry Andric // This file is distributed under the University of Illinois Open Source
62754fe60SDimitry Andric // License. See LICENSE.TXT for details.
72754fe60SDimitry Andric //
82754fe60SDimitry Andric //===----------------------------------------------------------------------===//
92754fe60SDimitry Andric //
102754fe60SDimitry Andric //  This file defines a set of flow-insensitive security checks.
112754fe60SDimitry Andric //
122754fe60SDimitry Andric //===----------------------------------------------------------------------===//
132754fe60SDimitry Andric 
14*b5893f02SDimitry Andric #include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h"
156122f3e6SDimitry Andric #include "clang/AST/StmtVisitor.h"
169a199699SDimitry Andric #include "clang/Analysis/AnalysisDeclContext.h"
176122f3e6SDimitry Andric #include "clang/Basic/TargetInfo.h"
182754fe60SDimitry Andric #include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h"
19139f7f9bSDimitry Andric #include "clang/StaticAnalyzer/Core/Checker.h"
206122f3e6SDimitry Andric #include "clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h"
21dff0c46cSDimitry Andric #include "llvm/ADT/SmallString.h"
223b0f4066SDimitry Andric #include "llvm/ADT/StringSwitch.h"
236122f3e6SDimitry Andric #include "llvm/Support/raw_ostream.h"
242754fe60SDimitry Andric 
252754fe60SDimitry Andric using namespace clang;
262754fe60SDimitry Andric using namespace ento;
272754fe60SDimitry Andric 
isArc4RandomAvailable(const ASTContext & Ctx)282754fe60SDimitry Andric static bool isArc4RandomAvailable(const ASTContext &Ctx) {
296122f3e6SDimitry Andric   const llvm::Triple &T = Ctx.getTargetInfo().getTriple();
302754fe60SDimitry Andric   return T.getVendor() == llvm::Triple::Apple ||
3133956c43SDimitry Andric          T.getOS() == llvm::Triple::CloudABI ||
32*b5893f02SDimitry Andric          T.isOSFreeBSD() ||
33*b5893f02SDimitry Andric          T.isOSNetBSD() ||
34*b5893f02SDimitry Andric          T.isOSOpenBSD() ||
35*b5893f02SDimitry Andric          T.isOSDragonFly();
362754fe60SDimitry Andric }
372754fe60SDimitry Andric 
382754fe60SDimitry Andric namespace {
39dff0c46cSDimitry Andric struct ChecksFilter {
404ba319b5SDimitry Andric   DefaultBool check_bcmp;
414ba319b5SDimitry Andric   DefaultBool check_bcopy;
424ba319b5SDimitry Andric   DefaultBool check_bzero;
43dff0c46cSDimitry Andric   DefaultBool check_gets;
44dff0c46cSDimitry Andric   DefaultBool check_getpw;
45dff0c46cSDimitry Andric   DefaultBool check_mktemp;
46dff0c46cSDimitry Andric   DefaultBool check_mkstemp;
47dff0c46cSDimitry Andric   DefaultBool check_strcpy;
48dff0c46cSDimitry Andric   DefaultBool check_rand;
49dff0c46cSDimitry Andric   DefaultBool check_vfork;
50dff0c46cSDimitry Andric   DefaultBool check_FloatLoopCounter;
51dff0c46cSDimitry Andric   DefaultBool check_UncheckedReturn;
5259d1ed5bSDimitry Andric 
534ba319b5SDimitry Andric   CheckName checkName_bcmp;
544ba319b5SDimitry Andric   CheckName checkName_bcopy;
554ba319b5SDimitry Andric   CheckName checkName_bzero;
5659d1ed5bSDimitry Andric   CheckName checkName_gets;
5759d1ed5bSDimitry Andric   CheckName checkName_getpw;
5859d1ed5bSDimitry Andric   CheckName checkName_mktemp;
5959d1ed5bSDimitry Andric   CheckName checkName_mkstemp;
6059d1ed5bSDimitry Andric   CheckName checkName_strcpy;
6159d1ed5bSDimitry Andric   CheckName checkName_rand;
6259d1ed5bSDimitry Andric   CheckName checkName_vfork;
6359d1ed5bSDimitry Andric   CheckName checkName_FloatLoopCounter;
6459d1ed5bSDimitry Andric   CheckName checkName_UncheckedReturn;
65dff0c46cSDimitry Andric };
66dff0c46cSDimitry Andric 
672754fe60SDimitry Andric class WalkAST : public StmtVisitor<WalkAST> {
682754fe60SDimitry Andric   BugReporter &BR;
69dff0c46cSDimitry Andric   AnalysisDeclContext* AC;
702754fe60SDimitry Andric   enum { num_setids = 6 };
712754fe60SDimitry Andric   IdentifierInfo *II_setid[num_setids];
722754fe60SDimitry Andric 
732754fe60SDimitry Andric   const bool CheckRand;
74dff0c46cSDimitry Andric   const ChecksFilter &filter;
752754fe60SDimitry Andric 
762754fe60SDimitry Andric public:
WalkAST(BugReporter & br,AnalysisDeclContext * ac,const ChecksFilter & f)77dff0c46cSDimitry Andric   WalkAST(BugReporter &br, AnalysisDeclContext* ac,
78dff0c46cSDimitry Andric           const ChecksFilter &f)
796122f3e6SDimitry Andric   : BR(br), AC(ac), II_setid(),
80dff0c46cSDimitry Andric     CheckRand(isArc4RandomAvailable(BR.getContext())),
81dff0c46cSDimitry Andric     filter(f) {}
822754fe60SDimitry Andric 
832754fe60SDimitry Andric   // Statement visitor methods.
842754fe60SDimitry Andric   void VisitCallExpr(CallExpr *CE);
852754fe60SDimitry Andric   void VisitForStmt(ForStmt *S);
862754fe60SDimitry Andric   void VisitCompoundStmt (CompoundStmt *S);
VisitStmt(Stmt * S)872754fe60SDimitry Andric   void VisitStmt(Stmt *S) { VisitChildren(S); }
882754fe60SDimitry Andric 
892754fe60SDimitry Andric   void VisitChildren(Stmt *S);
902754fe60SDimitry Andric 
912754fe60SDimitry Andric   // Helpers.
923b0f4066SDimitry Andric   bool checkCall_strCommon(const CallExpr *CE, const FunctionDecl *FD);
933b0f4066SDimitry Andric 
940623d748SDimitry Andric   typedef void (WalkAST::*FnCheck)(const CallExpr *, const FunctionDecl *);
952754fe60SDimitry Andric 
962754fe60SDimitry Andric   // Checker-specific methods.
973b0f4066SDimitry Andric   void checkLoopConditionForFloat(const ForStmt *FS);
984ba319b5SDimitry Andric   void checkCall_bcmp(const CallExpr *CE, const FunctionDecl *FD);
994ba319b5SDimitry Andric   void checkCall_bcopy(const CallExpr *CE, const FunctionDecl *FD);
1004ba319b5SDimitry Andric   void checkCall_bzero(const CallExpr *CE, const FunctionDecl *FD);
1013b0f4066SDimitry Andric   void checkCall_gets(const CallExpr *CE, const FunctionDecl *FD);
1023b0f4066SDimitry Andric   void checkCall_getpw(const CallExpr *CE, const FunctionDecl *FD);
1033b0f4066SDimitry Andric   void checkCall_mktemp(const CallExpr *CE, const FunctionDecl *FD);
104dff0c46cSDimitry Andric   void checkCall_mkstemp(const CallExpr *CE, const FunctionDecl *FD);
1053b0f4066SDimitry Andric   void checkCall_strcpy(const CallExpr *CE, const FunctionDecl *FD);
1063b0f4066SDimitry Andric   void checkCall_strcat(const CallExpr *CE, const FunctionDecl *FD);
1073b0f4066SDimitry Andric   void checkCall_rand(const CallExpr *CE, const FunctionDecl *FD);
1083b0f4066SDimitry Andric   void checkCall_random(const CallExpr *CE, const FunctionDecl *FD);
1096122f3e6SDimitry Andric   void checkCall_vfork(const CallExpr *CE, const FunctionDecl *FD);
1103b0f4066SDimitry Andric   void checkUncheckedReturnValue(CallExpr *CE);
1112754fe60SDimitry Andric };
1122754fe60SDimitry Andric } // end anonymous namespace
1132754fe60SDimitry Andric 
1142754fe60SDimitry Andric //===----------------------------------------------------------------------===//
1152754fe60SDimitry Andric // AST walking.
1162754fe60SDimitry Andric //===----------------------------------------------------------------------===//
1172754fe60SDimitry Andric 
VisitChildren(Stmt * S)1182754fe60SDimitry Andric void WalkAST::VisitChildren(Stmt *S) {
1193dac3a9bSDimitry Andric   for (Stmt *Child : S->children())
1203dac3a9bSDimitry Andric     if (Child)
1213dac3a9bSDimitry Andric       Visit(Child);
1222754fe60SDimitry Andric }
1232754fe60SDimitry Andric 
VisitCallExpr(CallExpr * CE)1242754fe60SDimitry Andric void WalkAST::VisitCallExpr(CallExpr *CE) {
1253b0f4066SDimitry Andric   // Get the callee.
1263b0f4066SDimitry Andric   const FunctionDecl *FD = CE->getDirectCallee();
1273b0f4066SDimitry Andric 
1283b0f4066SDimitry Andric   if (!FD)
1293b0f4066SDimitry Andric     return;
1303b0f4066SDimitry Andric 
1313b0f4066SDimitry Andric   // Get the name of the callee. If it's a builtin, strip off the prefix.
1323b0f4066SDimitry Andric   IdentifierInfo *II = FD->getIdentifier();
1333b0f4066SDimitry Andric   if (!II)   // if no identifier, not a simple C function
1343b0f4066SDimitry Andric     return;
1356122f3e6SDimitry Andric   StringRef Name = II->getName();
1363b0f4066SDimitry Andric   if (Name.startswith("__builtin_"))
1373b0f4066SDimitry Andric     Name = Name.substr(10);
1383b0f4066SDimitry Andric 
1393b0f4066SDimitry Andric   // Set the evaluation function by switching on the callee name.
1403b0f4066SDimitry Andric   FnCheck evalFunction = llvm::StringSwitch<FnCheck>(Name)
1414ba319b5SDimitry Andric     .Case("bcmp", &WalkAST::checkCall_bcmp)
1424ba319b5SDimitry Andric     .Case("bcopy", &WalkAST::checkCall_bcopy)
1434ba319b5SDimitry Andric     .Case("bzero", &WalkAST::checkCall_bzero)
1443b0f4066SDimitry Andric     .Case("gets", &WalkAST::checkCall_gets)
1453b0f4066SDimitry Andric     .Case("getpw", &WalkAST::checkCall_getpw)
1463b0f4066SDimitry Andric     .Case("mktemp", &WalkAST::checkCall_mktemp)
147dff0c46cSDimitry Andric     .Case("mkstemp", &WalkAST::checkCall_mkstemp)
148dff0c46cSDimitry Andric     .Case("mkdtemp", &WalkAST::checkCall_mkstemp)
149dff0c46cSDimitry Andric     .Case("mkstemps", &WalkAST::checkCall_mkstemp)
1503b0f4066SDimitry Andric     .Cases("strcpy", "__strcpy_chk", &WalkAST::checkCall_strcpy)
1513b0f4066SDimitry Andric     .Cases("strcat", "__strcat_chk", &WalkAST::checkCall_strcat)
1523b0f4066SDimitry Andric     .Case("drand48", &WalkAST::checkCall_rand)
1533b0f4066SDimitry Andric     .Case("erand48", &WalkAST::checkCall_rand)
1543b0f4066SDimitry Andric     .Case("jrand48", &WalkAST::checkCall_rand)
1553b0f4066SDimitry Andric     .Case("lrand48", &WalkAST::checkCall_rand)
1563b0f4066SDimitry Andric     .Case("mrand48", &WalkAST::checkCall_rand)
1573b0f4066SDimitry Andric     .Case("nrand48", &WalkAST::checkCall_rand)
1583b0f4066SDimitry Andric     .Case("lcong48", &WalkAST::checkCall_rand)
1593b0f4066SDimitry Andric     .Case("rand", &WalkAST::checkCall_rand)
1603b0f4066SDimitry Andric     .Case("rand_r", &WalkAST::checkCall_rand)
1613b0f4066SDimitry Andric     .Case("random", &WalkAST::checkCall_random)
1626122f3e6SDimitry Andric     .Case("vfork", &WalkAST::checkCall_vfork)
16359d1ed5bSDimitry Andric     .Default(nullptr);
1643b0f4066SDimitry Andric 
1653b0f4066SDimitry Andric   // If the callee isn't defined, it is not of security concern.
1663b0f4066SDimitry Andric   // Check and evaluate the call.
1673b0f4066SDimitry Andric   if (evalFunction)
1683b0f4066SDimitry Andric     (this->*evalFunction)(CE, FD);
1692754fe60SDimitry Andric 
1702754fe60SDimitry Andric   // Recurse and check children.
1712754fe60SDimitry Andric   VisitChildren(CE);
1722754fe60SDimitry Andric }
1732754fe60SDimitry Andric 
VisitCompoundStmt(CompoundStmt * S)1742754fe60SDimitry Andric void WalkAST::VisitCompoundStmt(CompoundStmt *S) {
1753dac3a9bSDimitry Andric   for (Stmt *Child : S->children())
1763dac3a9bSDimitry Andric     if (Child) {
1773dac3a9bSDimitry Andric       if (CallExpr *CE = dyn_cast<CallExpr>(Child))
1783b0f4066SDimitry Andric         checkUncheckedReturnValue(CE);
1793dac3a9bSDimitry Andric       Visit(Child);
1802754fe60SDimitry Andric     }
1812754fe60SDimitry Andric }
1822754fe60SDimitry Andric 
VisitForStmt(ForStmt * FS)1832754fe60SDimitry Andric void WalkAST::VisitForStmt(ForStmt *FS) {
1843b0f4066SDimitry Andric   checkLoopConditionForFloat(FS);
1852754fe60SDimitry Andric 
1862754fe60SDimitry Andric   // Recurse and check children.
1872754fe60SDimitry Andric   VisitChildren(FS);
1882754fe60SDimitry Andric }
1892754fe60SDimitry Andric 
1902754fe60SDimitry Andric //===----------------------------------------------------------------------===//
191*b5893f02SDimitry Andric // Check: floating point variable used as loop counter.
1922754fe60SDimitry Andric // Originally: <rdar://problem/6336718>
1932754fe60SDimitry Andric // Implements: CERT security coding advisory FLP-30.
1942754fe60SDimitry Andric //===----------------------------------------------------------------------===//
1952754fe60SDimitry Andric 
1962754fe60SDimitry Andric static const DeclRefExpr*
getIncrementedVar(const Expr * expr,const VarDecl * x,const VarDecl * y)1973b0f4066SDimitry Andric getIncrementedVar(const Expr *expr, const VarDecl *x, const VarDecl *y) {
1982754fe60SDimitry Andric   expr = expr->IgnoreParenCasts();
1992754fe60SDimitry Andric 
2002754fe60SDimitry Andric   if (const BinaryOperator *B = dyn_cast<BinaryOperator>(expr)) {
2012754fe60SDimitry Andric     if (!(B->isAssignmentOp() || B->isCompoundAssignmentOp() ||
2022754fe60SDimitry Andric           B->getOpcode() == BO_Comma))
20359d1ed5bSDimitry Andric       return nullptr;
2042754fe60SDimitry Andric 
2053b0f4066SDimitry Andric     if (const DeclRefExpr *lhs = getIncrementedVar(B->getLHS(), x, y))
2062754fe60SDimitry Andric       return lhs;
2072754fe60SDimitry Andric 
2083b0f4066SDimitry Andric     if (const DeclRefExpr *rhs = getIncrementedVar(B->getRHS(), x, y))
2092754fe60SDimitry Andric       return rhs;
2102754fe60SDimitry Andric 
21159d1ed5bSDimitry Andric     return nullptr;
2122754fe60SDimitry Andric   }
2132754fe60SDimitry Andric 
2142754fe60SDimitry Andric   if (const DeclRefExpr *DR = dyn_cast<DeclRefExpr>(expr)) {
2152754fe60SDimitry Andric     const NamedDecl *ND = DR->getDecl();
21659d1ed5bSDimitry Andric     return ND == x || ND == y ? DR : nullptr;
2172754fe60SDimitry Andric   }
2182754fe60SDimitry Andric 
2192754fe60SDimitry Andric   if (const UnaryOperator *U = dyn_cast<UnaryOperator>(expr))
2202754fe60SDimitry Andric     return U->isIncrementDecrementOp()
22159d1ed5bSDimitry Andric       ? getIncrementedVar(U->getSubExpr(), x, y) : nullptr;
2222754fe60SDimitry Andric 
22359d1ed5bSDimitry Andric   return nullptr;
2242754fe60SDimitry Andric }
2252754fe60SDimitry Andric 
2262754fe60SDimitry Andric /// CheckLoopConditionForFloat - This check looks for 'for' statements that
2272754fe60SDimitry Andric ///  use a floating point variable as a loop counter.
2282754fe60SDimitry Andric ///  CERT: FLP30-C, FLP30-CPP.
2292754fe60SDimitry Andric ///
checkLoopConditionForFloat(const ForStmt * FS)2303b0f4066SDimitry Andric void WalkAST::checkLoopConditionForFloat(const ForStmt *FS) {
231dff0c46cSDimitry Andric   if (!filter.check_FloatLoopCounter)
232dff0c46cSDimitry Andric     return;
233dff0c46cSDimitry Andric 
2342754fe60SDimitry Andric   // Does the loop have a condition?
2352754fe60SDimitry Andric   const Expr *condition = FS->getCond();
2362754fe60SDimitry Andric 
2372754fe60SDimitry Andric   if (!condition)
2382754fe60SDimitry Andric     return;
2392754fe60SDimitry Andric 
2402754fe60SDimitry Andric   // Does the loop have an increment?
2412754fe60SDimitry Andric   const Expr *increment = FS->getInc();
2422754fe60SDimitry Andric 
2432754fe60SDimitry Andric   if (!increment)
2442754fe60SDimitry Andric     return;
2452754fe60SDimitry Andric 
2462754fe60SDimitry Andric   // Strip away '()' and casts.
2472754fe60SDimitry Andric   condition = condition->IgnoreParenCasts();
2482754fe60SDimitry Andric   increment = increment->IgnoreParenCasts();
2492754fe60SDimitry Andric 
2502754fe60SDimitry Andric   // Is the loop condition a comparison?
2512754fe60SDimitry Andric   const BinaryOperator *B = dyn_cast<BinaryOperator>(condition);
2522754fe60SDimitry Andric 
2532754fe60SDimitry Andric   if (!B)
2542754fe60SDimitry Andric     return;
2552754fe60SDimitry Andric 
2562754fe60SDimitry Andric   // Is this a comparison?
2572754fe60SDimitry Andric   if (!(B->isRelationalOp() || B->isEqualityOp()))
2582754fe60SDimitry Andric     return;
2592754fe60SDimitry Andric 
2602754fe60SDimitry Andric   // Are we comparing variables?
2612754fe60SDimitry Andric   const DeclRefExpr *drLHS =
2622754fe60SDimitry Andric     dyn_cast<DeclRefExpr>(B->getLHS()->IgnoreParenLValueCasts());
2632754fe60SDimitry Andric   const DeclRefExpr *drRHS =
2642754fe60SDimitry Andric     dyn_cast<DeclRefExpr>(B->getRHS()->IgnoreParenLValueCasts());
2652754fe60SDimitry Andric 
2662754fe60SDimitry Andric   // Does at least one of the variables have a floating point type?
26759d1ed5bSDimitry Andric   drLHS = drLHS && drLHS->getType()->isRealFloatingType() ? drLHS : nullptr;
26859d1ed5bSDimitry Andric   drRHS = drRHS && drRHS->getType()->isRealFloatingType() ? drRHS : nullptr;
2692754fe60SDimitry Andric 
2702754fe60SDimitry Andric   if (!drLHS && !drRHS)
2712754fe60SDimitry Andric     return;
2722754fe60SDimitry Andric 
27359d1ed5bSDimitry Andric   const VarDecl *vdLHS = drLHS ? dyn_cast<VarDecl>(drLHS->getDecl()) : nullptr;
27459d1ed5bSDimitry Andric   const VarDecl *vdRHS = drRHS ? dyn_cast<VarDecl>(drRHS->getDecl()) : nullptr;
2752754fe60SDimitry Andric 
2762754fe60SDimitry Andric   if (!vdLHS && !vdRHS)
2772754fe60SDimitry Andric     return;
2782754fe60SDimitry Andric 
2792754fe60SDimitry Andric   // Does either variable appear in increment?
2803b0f4066SDimitry Andric   const DeclRefExpr *drInc = getIncrementedVar(increment, vdLHS, vdRHS);
2812754fe60SDimitry Andric 
2822754fe60SDimitry Andric   if (!drInc)
2832754fe60SDimitry Andric     return;
2842754fe60SDimitry Andric 
2852754fe60SDimitry Andric   // Emit the error.  First figure out which DeclRefExpr in the condition
2862754fe60SDimitry Andric   // referenced the compared variable.
2873861d79fSDimitry Andric   assert(drInc->getDecl());
2882754fe60SDimitry Andric   const DeclRefExpr *drCond = vdLHS == drInc->getDecl() ? drLHS : drRHS;
2892754fe60SDimitry Andric 
2906122f3e6SDimitry Andric   SmallVector<SourceRange, 2> ranges;
291dff0c46cSDimitry Andric   SmallString<256> sbuf;
2922754fe60SDimitry Andric   llvm::raw_svector_ostream os(sbuf);
2932754fe60SDimitry Andric 
2942754fe60SDimitry Andric   os << "Variable '" << drCond->getDecl()->getName()
2952754fe60SDimitry Andric      << "' with floating point type '" << drCond->getType().getAsString()
2962754fe60SDimitry Andric      << "' should not be used as a loop counter";
2972754fe60SDimitry Andric 
2982754fe60SDimitry Andric   ranges.push_back(drCond->getSourceRange());
2992754fe60SDimitry Andric   ranges.push_back(drInc->getSourceRange());
3002754fe60SDimitry Andric 
3012754fe60SDimitry Andric   const char *bugType = "Floating point variable used as loop counter";
3026122f3e6SDimitry Andric 
3036122f3e6SDimitry Andric   PathDiagnosticLocation FSLoc =
3046122f3e6SDimitry Andric     PathDiagnosticLocation::createBegin(FS, BR.getSourceManager(), AC);
30559d1ed5bSDimitry Andric   BR.EmitBasicReport(AC->getDecl(), filter.checkName_FloatLoopCounter,
306dff0c46cSDimitry Andric                      bugType, "Security", os.str(),
307f785676fSDimitry Andric                      FSLoc, ranges);
3082754fe60SDimitry Andric }
3092754fe60SDimitry Andric 
3102754fe60SDimitry Andric //===----------------------------------------------------------------------===//
3114ba319b5SDimitry Andric // Check: Any use of bcmp.
3124ba319b5SDimitry Andric // CWE-477: Use of Obsolete Functions
3134ba319b5SDimitry Andric // bcmp was deprecated in POSIX.1-2008
3144ba319b5SDimitry Andric //===----------------------------------------------------------------------===//
3154ba319b5SDimitry Andric 
checkCall_bcmp(const CallExpr * CE,const FunctionDecl * FD)3164ba319b5SDimitry Andric void WalkAST::checkCall_bcmp(const CallExpr *CE, const FunctionDecl *FD) {
3174ba319b5SDimitry Andric   if (!filter.check_bcmp)
3184ba319b5SDimitry Andric     return;
3194ba319b5SDimitry Andric 
3204ba319b5SDimitry Andric   const FunctionProtoType *FPT = FD->getType()->getAs<FunctionProtoType>();
3214ba319b5SDimitry Andric   if (!FPT)
3224ba319b5SDimitry Andric     return;
3234ba319b5SDimitry Andric 
3244ba319b5SDimitry Andric   // Verify that the function takes three arguments.
3254ba319b5SDimitry Andric   if (FPT->getNumParams() != 3)
3264ba319b5SDimitry Andric     return;
3274ba319b5SDimitry Andric 
3284ba319b5SDimitry Andric   for (int i = 0; i < 2; i++) {
3294ba319b5SDimitry Andric     // Verify the first and second argument type is void*.
3304ba319b5SDimitry Andric     const PointerType *PT = FPT->getParamType(i)->getAs<PointerType>();
3314ba319b5SDimitry Andric     if (!PT)
3324ba319b5SDimitry Andric       return;
3334ba319b5SDimitry Andric 
3344ba319b5SDimitry Andric     if (PT->getPointeeType().getUnqualifiedType() != BR.getContext().VoidTy)
3354ba319b5SDimitry Andric       return;
3364ba319b5SDimitry Andric   }
3374ba319b5SDimitry Andric 
3384ba319b5SDimitry Andric   // Verify the third argument type is integer.
3394ba319b5SDimitry Andric   if (!FPT->getParamType(2)->isIntegralOrUnscopedEnumerationType())
3404ba319b5SDimitry Andric     return;
3414ba319b5SDimitry Andric 
3424ba319b5SDimitry Andric   // Issue a warning.
3434ba319b5SDimitry Andric   PathDiagnosticLocation CELoc =
3444ba319b5SDimitry Andric     PathDiagnosticLocation::createBegin(CE, BR.getSourceManager(), AC);
3454ba319b5SDimitry Andric   BR.EmitBasicReport(AC->getDecl(), filter.checkName_bcmp,
3464ba319b5SDimitry Andric                      "Use of deprecated function in call to 'bcmp()'",
3474ba319b5SDimitry Andric                      "Security",
3484ba319b5SDimitry Andric                      "The bcmp() function is obsoleted by memcmp().",
3494ba319b5SDimitry Andric                      CELoc, CE->getCallee()->getSourceRange());
3504ba319b5SDimitry Andric }
3514ba319b5SDimitry Andric 
3524ba319b5SDimitry Andric //===----------------------------------------------------------------------===//
3534ba319b5SDimitry Andric // Check: Any use of bcopy.
3544ba319b5SDimitry Andric // CWE-477: Use of Obsolete Functions
3554ba319b5SDimitry Andric // bcopy was deprecated in POSIX.1-2008
3564ba319b5SDimitry Andric //===----------------------------------------------------------------------===//
3574ba319b5SDimitry Andric 
checkCall_bcopy(const CallExpr * CE,const FunctionDecl * FD)3584ba319b5SDimitry Andric void WalkAST::checkCall_bcopy(const CallExpr *CE, const FunctionDecl *FD) {
3594ba319b5SDimitry Andric   if (!filter.check_bcopy)
3604ba319b5SDimitry Andric     return;
3614ba319b5SDimitry Andric 
3624ba319b5SDimitry Andric   const FunctionProtoType *FPT = FD->getType()->getAs<FunctionProtoType>();
3634ba319b5SDimitry Andric   if (!FPT)
3644ba319b5SDimitry Andric     return;
3654ba319b5SDimitry Andric 
3664ba319b5SDimitry Andric   // Verify that the function takes three arguments.
3674ba319b5SDimitry Andric   if (FPT->getNumParams() != 3)
3684ba319b5SDimitry Andric     return;
3694ba319b5SDimitry Andric 
3704ba319b5SDimitry Andric   for (int i = 0; i < 2; i++) {
3714ba319b5SDimitry Andric     // Verify the first and second argument type is void*.
3724ba319b5SDimitry Andric     const PointerType *PT = FPT->getParamType(i)->getAs<PointerType>();
3734ba319b5SDimitry Andric     if (!PT)
3744ba319b5SDimitry Andric       return;
3754ba319b5SDimitry Andric 
3764ba319b5SDimitry Andric     if (PT->getPointeeType().getUnqualifiedType() != BR.getContext().VoidTy)
3774ba319b5SDimitry Andric       return;
3784ba319b5SDimitry Andric   }
3794ba319b5SDimitry Andric 
3804ba319b5SDimitry Andric   // Verify the third argument type is integer.
3814ba319b5SDimitry Andric   if (!FPT->getParamType(2)->isIntegralOrUnscopedEnumerationType())
3824ba319b5SDimitry Andric     return;
3834ba319b5SDimitry Andric 
3844ba319b5SDimitry Andric   // Issue a warning.
3854ba319b5SDimitry Andric   PathDiagnosticLocation CELoc =
3864ba319b5SDimitry Andric     PathDiagnosticLocation::createBegin(CE, BR.getSourceManager(), AC);
3874ba319b5SDimitry Andric   BR.EmitBasicReport(AC->getDecl(), filter.checkName_bcopy,
3884ba319b5SDimitry Andric                      "Use of deprecated function in call to 'bcopy()'",
3894ba319b5SDimitry Andric                      "Security",
3904ba319b5SDimitry Andric                      "The bcopy() function is obsoleted by memcpy() "
3914ba319b5SDimitry Andric                      "or memmove().",
3924ba319b5SDimitry Andric                      CELoc, CE->getCallee()->getSourceRange());
3934ba319b5SDimitry Andric }
3944ba319b5SDimitry Andric 
3954ba319b5SDimitry Andric //===----------------------------------------------------------------------===//
3964ba319b5SDimitry Andric // Check: Any use of bzero.
3974ba319b5SDimitry Andric // CWE-477: Use of Obsolete Functions
3984ba319b5SDimitry Andric // bzero was deprecated in POSIX.1-2008
3994ba319b5SDimitry Andric //===----------------------------------------------------------------------===//
4004ba319b5SDimitry Andric 
checkCall_bzero(const CallExpr * CE,const FunctionDecl * FD)4014ba319b5SDimitry Andric void WalkAST::checkCall_bzero(const CallExpr *CE, const FunctionDecl *FD) {
4024ba319b5SDimitry Andric   if (!filter.check_bzero)
4034ba319b5SDimitry Andric     return;
4044ba319b5SDimitry Andric 
4054ba319b5SDimitry Andric   const FunctionProtoType *FPT = FD->getType()->getAs<FunctionProtoType>();
4064ba319b5SDimitry Andric   if (!FPT)
4074ba319b5SDimitry Andric     return;
4084ba319b5SDimitry Andric 
4094ba319b5SDimitry Andric   // Verify that the function takes two arguments.
4104ba319b5SDimitry Andric   if (FPT->getNumParams() != 2)
4114ba319b5SDimitry Andric     return;
4124ba319b5SDimitry Andric 
4134ba319b5SDimitry Andric   // Verify the first argument type is void*.
4144ba319b5SDimitry Andric   const PointerType *PT = FPT->getParamType(0)->getAs<PointerType>();
4154ba319b5SDimitry Andric   if (!PT)
4164ba319b5SDimitry Andric     return;
4174ba319b5SDimitry Andric 
4184ba319b5SDimitry Andric   if (PT->getPointeeType().getUnqualifiedType() != BR.getContext().VoidTy)
4194ba319b5SDimitry Andric     return;
4204ba319b5SDimitry Andric 
4214ba319b5SDimitry Andric   // Verify the second argument type is integer.
4224ba319b5SDimitry Andric   if (!FPT->getParamType(1)->isIntegralOrUnscopedEnumerationType())
4234ba319b5SDimitry Andric     return;
4244ba319b5SDimitry Andric 
4254ba319b5SDimitry Andric   // Issue a warning.
4264ba319b5SDimitry Andric   PathDiagnosticLocation CELoc =
4274ba319b5SDimitry Andric     PathDiagnosticLocation::createBegin(CE, BR.getSourceManager(), AC);
4284ba319b5SDimitry Andric   BR.EmitBasicReport(AC->getDecl(), filter.checkName_bzero,
4294ba319b5SDimitry Andric                      "Use of deprecated function in call to 'bzero()'",
4304ba319b5SDimitry Andric                      "Security",
4314ba319b5SDimitry Andric                      "The bzero() function is obsoleted by memset().",
4324ba319b5SDimitry Andric                      CELoc, CE->getCallee()->getSourceRange());
4334ba319b5SDimitry Andric }
4344ba319b5SDimitry Andric 
4354ba319b5SDimitry Andric 
4364ba319b5SDimitry Andric //===----------------------------------------------------------------------===//
4372754fe60SDimitry Andric // Check: Any use of 'gets' is insecure.
4382754fe60SDimitry Andric // Originally: <rdar://problem/6335715>
4392754fe60SDimitry Andric // Implements (part of): 300-BSI (buildsecurityin.us-cert.gov)
4402754fe60SDimitry Andric // CWE-242: Use of Inherently Dangerous Function
4412754fe60SDimitry Andric //===----------------------------------------------------------------------===//
4422754fe60SDimitry Andric 
checkCall_gets(const CallExpr * CE,const FunctionDecl * FD)4433b0f4066SDimitry Andric void WalkAST::checkCall_gets(const CallExpr *CE, const FunctionDecl *FD) {
444dff0c46cSDimitry Andric   if (!filter.check_gets)
445dff0c46cSDimitry Andric     return;
446dff0c46cSDimitry Andric 
447f785676fSDimitry Andric   const FunctionProtoType *FPT = FD->getType()->getAs<FunctionProtoType>();
4482754fe60SDimitry Andric   if (!FPT)
4492754fe60SDimitry Andric     return;
4502754fe60SDimitry Andric 
4512754fe60SDimitry Andric   // Verify that the function takes a single argument.
45259d1ed5bSDimitry Andric   if (FPT->getNumParams() != 1)
4532754fe60SDimitry Andric     return;
4542754fe60SDimitry Andric 
4552754fe60SDimitry Andric   // Is the argument a 'char*'?
45659d1ed5bSDimitry Andric   const PointerType *PT = FPT->getParamType(0)->getAs<PointerType>();
4572754fe60SDimitry Andric   if (!PT)
4582754fe60SDimitry Andric     return;
4592754fe60SDimitry Andric 
4602754fe60SDimitry Andric   if (PT->getPointeeType().getUnqualifiedType() != BR.getContext().CharTy)
4612754fe60SDimitry Andric     return;
4622754fe60SDimitry Andric 
4632754fe60SDimitry Andric   // Issue a warning.
4646122f3e6SDimitry Andric   PathDiagnosticLocation CELoc =
4656122f3e6SDimitry Andric     PathDiagnosticLocation::createBegin(CE, BR.getSourceManager(), AC);
46659d1ed5bSDimitry Andric   BR.EmitBasicReport(AC->getDecl(), filter.checkName_gets,
467dff0c46cSDimitry Andric                      "Potential buffer overflow in call to 'gets'",
4682754fe60SDimitry Andric                      "Security",
4692754fe60SDimitry Andric                      "Call to function 'gets' is extremely insecure as it can "
4702754fe60SDimitry Andric                      "always result in a buffer overflow",
471f785676fSDimitry Andric                      CELoc, CE->getCallee()->getSourceRange());
4722754fe60SDimitry Andric }
4732754fe60SDimitry Andric 
4742754fe60SDimitry Andric //===----------------------------------------------------------------------===//
4752754fe60SDimitry Andric // Check: Any use of 'getpwd' is insecure.
4762754fe60SDimitry Andric // CWE-477: Use of Obsolete Functions
4772754fe60SDimitry Andric //===----------------------------------------------------------------------===//
4782754fe60SDimitry Andric 
checkCall_getpw(const CallExpr * CE,const FunctionDecl * FD)4793b0f4066SDimitry Andric void WalkAST::checkCall_getpw(const CallExpr *CE, const FunctionDecl *FD) {
480dff0c46cSDimitry Andric   if (!filter.check_getpw)
481dff0c46cSDimitry Andric     return;
482dff0c46cSDimitry Andric 
483f785676fSDimitry Andric   const FunctionProtoType *FPT = FD->getType()->getAs<FunctionProtoType>();
4842754fe60SDimitry Andric   if (!FPT)
4852754fe60SDimitry Andric     return;
4862754fe60SDimitry Andric 
4872754fe60SDimitry Andric   // Verify that the function takes two arguments.
48859d1ed5bSDimitry Andric   if (FPT->getNumParams() != 2)
4892754fe60SDimitry Andric     return;
4902754fe60SDimitry Andric 
4912754fe60SDimitry Andric   // Verify the first argument type is integer.
49259d1ed5bSDimitry Andric   if (!FPT->getParamType(0)->isIntegralOrUnscopedEnumerationType())
4932754fe60SDimitry Andric     return;
4942754fe60SDimitry Andric 
4952754fe60SDimitry Andric   // Verify the second argument type is char*.
49659d1ed5bSDimitry Andric   const PointerType *PT = FPT->getParamType(1)->getAs<PointerType>();
4972754fe60SDimitry Andric   if (!PT)
4982754fe60SDimitry Andric     return;
4992754fe60SDimitry Andric 
5002754fe60SDimitry Andric   if (PT->getPointeeType().getUnqualifiedType() != BR.getContext().CharTy)
5012754fe60SDimitry Andric     return;
5022754fe60SDimitry Andric 
5032754fe60SDimitry Andric   // Issue a warning.
5046122f3e6SDimitry Andric   PathDiagnosticLocation CELoc =
5056122f3e6SDimitry Andric     PathDiagnosticLocation::createBegin(CE, BR.getSourceManager(), AC);
50659d1ed5bSDimitry Andric   BR.EmitBasicReport(AC->getDecl(), filter.checkName_getpw,
507dff0c46cSDimitry Andric                      "Potential buffer overflow in call to 'getpw'",
5082754fe60SDimitry Andric                      "Security",
5092754fe60SDimitry Andric                      "The getpw() function is dangerous as it may overflow the "
5102754fe60SDimitry Andric                      "provided buffer. It is obsoleted by getpwuid().",
511f785676fSDimitry Andric                      CELoc, CE->getCallee()->getSourceRange());
5122754fe60SDimitry Andric }
5132754fe60SDimitry Andric 
5142754fe60SDimitry Andric //===----------------------------------------------------------------------===//
5152754fe60SDimitry Andric // Check: Any use of 'mktemp' is insecure.  It is obsoleted by mkstemp().
5162754fe60SDimitry Andric // CWE-377: Insecure Temporary File
5172754fe60SDimitry Andric //===----------------------------------------------------------------------===//
5182754fe60SDimitry Andric 
checkCall_mktemp(const CallExpr * CE,const FunctionDecl * FD)5193b0f4066SDimitry Andric void WalkAST::checkCall_mktemp(const CallExpr *CE, const FunctionDecl *FD) {
520dff0c46cSDimitry Andric   if (!filter.check_mktemp) {
521dff0c46cSDimitry Andric     // Fall back to the security check of looking for enough 'X's in the
522dff0c46cSDimitry Andric     // format string, since that is a less severe warning.
523dff0c46cSDimitry Andric     checkCall_mkstemp(CE, FD);
524dff0c46cSDimitry Andric     return;
525dff0c46cSDimitry Andric   }
526dff0c46cSDimitry Andric 
527f785676fSDimitry Andric   const FunctionProtoType *FPT = FD->getType()->getAs<FunctionProtoType>();
5282754fe60SDimitry Andric   if(!FPT)
5292754fe60SDimitry Andric     return;
5302754fe60SDimitry Andric 
5313b0f4066SDimitry Andric   // Verify that the function takes a single argument.
53259d1ed5bSDimitry Andric   if (FPT->getNumParams() != 1)
5332754fe60SDimitry Andric     return;
5342754fe60SDimitry Andric 
5352754fe60SDimitry Andric   // Verify that the argument is Pointer Type.
53659d1ed5bSDimitry Andric   const PointerType *PT = FPT->getParamType(0)->getAs<PointerType>();
5372754fe60SDimitry Andric   if (!PT)
5382754fe60SDimitry Andric     return;
5392754fe60SDimitry Andric 
5402754fe60SDimitry Andric   // Verify that the argument is a 'char*'.
5412754fe60SDimitry Andric   if (PT->getPointeeType().getUnqualifiedType() != BR.getContext().CharTy)
5422754fe60SDimitry Andric     return;
5432754fe60SDimitry Andric 
54459d1ed5bSDimitry Andric   // Issue a warning.
5456122f3e6SDimitry Andric   PathDiagnosticLocation CELoc =
5466122f3e6SDimitry Andric     PathDiagnosticLocation::createBegin(CE, BR.getSourceManager(), AC);
54759d1ed5bSDimitry Andric   BR.EmitBasicReport(AC->getDecl(), filter.checkName_mktemp,
548dff0c46cSDimitry Andric                      "Potential insecure temporary file in call 'mktemp'",
5492754fe60SDimitry Andric                      "Security",
5502754fe60SDimitry Andric                      "Call to function 'mktemp' is insecure as it always "
551dff0c46cSDimitry Andric                      "creates or uses insecure temporary file.  Use 'mkstemp' "
552dff0c46cSDimitry Andric                      "instead",
553f785676fSDimitry Andric                      CELoc, CE->getCallee()->getSourceRange());
5542754fe60SDimitry Andric }
5552754fe60SDimitry Andric 
556dff0c46cSDimitry Andric 
557dff0c46cSDimitry Andric //===----------------------------------------------------------------------===//
558dff0c46cSDimitry Andric // Check: Use of 'mkstemp', 'mktemp', 'mkdtemp' should contain at least 6 X's.
559dff0c46cSDimitry Andric //===----------------------------------------------------------------------===//
560dff0c46cSDimitry Andric 
checkCall_mkstemp(const CallExpr * CE,const FunctionDecl * FD)561dff0c46cSDimitry Andric void WalkAST::checkCall_mkstemp(const CallExpr *CE, const FunctionDecl *FD) {
562dff0c46cSDimitry Andric   if (!filter.check_mkstemp)
563dff0c46cSDimitry Andric     return;
564dff0c46cSDimitry Andric 
565dff0c46cSDimitry Andric   StringRef Name = FD->getIdentifier()->getName();
566dff0c46cSDimitry Andric   std::pair<signed, signed> ArgSuffix =
567dff0c46cSDimitry Andric     llvm::StringSwitch<std::pair<signed, signed> >(Name)
568dff0c46cSDimitry Andric       .Case("mktemp", std::make_pair(0,-1))
569dff0c46cSDimitry Andric       .Case("mkstemp", std::make_pair(0,-1))
570dff0c46cSDimitry Andric       .Case("mkdtemp", std::make_pair(0,-1))
571dff0c46cSDimitry Andric       .Case("mkstemps", std::make_pair(0,1))
572dff0c46cSDimitry Andric       .Default(std::make_pair(-1, -1));
573dff0c46cSDimitry Andric 
574dff0c46cSDimitry Andric   assert(ArgSuffix.first >= 0 && "Unsupported function");
575dff0c46cSDimitry Andric 
576dff0c46cSDimitry Andric   // Check if the number of arguments is consistent with out expectations.
577dff0c46cSDimitry Andric   unsigned numArgs = CE->getNumArgs();
578dff0c46cSDimitry Andric   if ((signed) numArgs <= ArgSuffix.first)
579dff0c46cSDimitry Andric     return;
580dff0c46cSDimitry Andric 
581dff0c46cSDimitry Andric   const StringLiteral *strArg =
582dff0c46cSDimitry Andric     dyn_cast<StringLiteral>(CE->getArg((unsigned)ArgSuffix.first)
583dff0c46cSDimitry Andric                               ->IgnoreParenImpCasts());
584dff0c46cSDimitry Andric 
585dff0c46cSDimitry Andric   // Currently we only handle string literals.  It is possible to do better,
586dff0c46cSDimitry Andric   // either by looking at references to const variables, or by doing real
587dff0c46cSDimitry Andric   // flow analysis.
588dff0c46cSDimitry Andric   if (!strArg || strArg->getCharByteWidth() != 1)
589dff0c46cSDimitry Andric     return;
590dff0c46cSDimitry Andric 
591dff0c46cSDimitry Andric   // Count the number of X's, taking into account a possible cutoff suffix.
592dff0c46cSDimitry Andric   StringRef str = strArg->getString();
593dff0c46cSDimitry Andric   unsigned numX = 0;
594dff0c46cSDimitry Andric   unsigned n = str.size();
595dff0c46cSDimitry Andric 
596dff0c46cSDimitry Andric   // Take into account the suffix.
597dff0c46cSDimitry Andric   unsigned suffix = 0;
598dff0c46cSDimitry Andric   if (ArgSuffix.second >= 0) {
599dff0c46cSDimitry Andric     const Expr *suffixEx = CE->getArg((unsigned)ArgSuffix.second);
600*b5893f02SDimitry Andric     Expr::EvalResult EVResult;
601*b5893f02SDimitry Andric     if (!suffixEx->EvaluateAsInt(EVResult, BR.getContext()))
602dff0c46cSDimitry Andric       return;
603*b5893f02SDimitry Andric     llvm::APSInt Result = EVResult.Val.getInt();
604dff0c46cSDimitry Andric     // FIXME: Issue a warning.
605dff0c46cSDimitry Andric     if (Result.isNegative())
606dff0c46cSDimitry Andric       return;
607dff0c46cSDimitry Andric     suffix = (unsigned) Result.getZExtValue();
608dff0c46cSDimitry Andric     n = (n > suffix) ? n - suffix : 0;
609dff0c46cSDimitry Andric   }
610dff0c46cSDimitry Andric 
611dff0c46cSDimitry Andric   for (unsigned i = 0; i < n; ++i)
612dff0c46cSDimitry Andric     if (str[i] == 'X') ++numX;
613dff0c46cSDimitry Andric 
614dff0c46cSDimitry Andric   if (numX >= 6)
615dff0c46cSDimitry Andric     return;
616dff0c46cSDimitry Andric 
617dff0c46cSDimitry Andric   // Issue a warning.
618dff0c46cSDimitry Andric   PathDiagnosticLocation CELoc =
619dff0c46cSDimitry Andric     PathDiagnosticLocation::createBegin(CE, BR.getSourceManager(), AC);
620dff0c46cSDimitry Andric   SmallString<512> buf;
621dff0c46cSDimitry Andric   llvm::raw_svector_ostream out(buf);
622dff0c46cSDimitry Andric   out << "Call to '" << Name << "' should have at least 6 'X's in the"
623dff0c46cSDimitry Andric     " format string to be secure (" << numX << " 'X'";
624dff0c46cSDimitry Andric   if (numX != 1)
625dff0c46cSDimitry Andric     out << 's';
626dff0c46cSDimitry Andric   out << " seen";
627dff0c46cSDimitry Andric   if (suffix) {
628dff0c46cSDimitry Andric     out << ", " << suffix << " character";
629dff0c46cSDimitry Andric     if (suffix > 1)
630dff0c46cSDimitry Andric       out << 's';
631dff0c46cSDimitry Andric     out << " used as a suffix";
632dff0c46cSDimitry Andric   }
633dff0c46cSDimitry Andric   out << ')';
63459d1ed5bSDimitry Andric   BR.EmitBasicReport(AC->getDecl(), filter.checkName_mkstemp,
635dff0c46cSDimitry Andric                      "Insecure temporary file creation", "Security",
636f785676fSDimitry Andric                      out.str(), CELoc, strArg->getSourceRange());
637dff0c46cSDimitry Andric }
638dff0c46cSDimitry Andric 
6392754fe60SDimitry Andric //===----------------------------------------------------------------------===//
6403b0f4066SDimitry Andric // Check: Any use of 'strcpy' is insecure.
6413b0f4066SDimitry Andric //
6423b0f4066SDimitry Andric // CWE-119: Improper Restriction of Operations within
6433b0f4066SDimitry Andric // the Bounds of a Memory Buffer
6443b0f4066SDimitry Andric //===----------------------------------------------------------------------===//
checkCall_strcpy(const CallExpr * CE,const FunctionDecl * FD)6453b0f4066SDimitry Andric void WalkAST::checkCall_strcpy(const CallExpr *CE, const FunctionDecl *FD) {
646dff0c46cSDimitry Andric   if (!filter.check_strcpy)
647dff0c46cSDimitry Andric     return;
648dff0c46cSDimitry Andric 
6493b0f4066SDimitry Andric   if (!checkCall_strCommon(CE, FD))
6503b0f4066SDimitry Andric     return;
6513b0f4066SDimitry Andric 
6524ba319b5SDimitry Andric   const auto *Target = CE->getArg(0)->IgnoreImpCasts(),
6534ba319b5SDimitry Andric              *Source = CE->getArg(1)->IgnoreImpCasts();
654*b5893f02SDimitry Andric 
655*b5893f02SDimitry Andric   if (const auto *Array = dyn_cast<ConstantArrayType>(Target->getType())) {
6564ba319b5SDimitry Andric     uint64_t ArraySize = BR.getContext().getTypeSize(Array) / 8;
6574ba319b5SDimitry Andric     if (const auto *String = dyn_cast<StringLiteral>(Source)) {
6584ba319b5SDimitry Andric       if (ArraySize >= String->getLength() + 1)
6594ba319b5SDimitry Andric         return;
6604ba319b5SDimitry Andric     }
6614ba319b5SDimitry Andric   }
6624ba319b5SDimitry Andric 
6633b0f4066SDimitry Andric   // Issue a warning.
6646122f3e6SDimitry Andric   PathDiagnosticLocation CELoc =
6656122f3e6SDimitry Andric     PathDiagnosticLocation::createBegin(CE, BR.getSourceManager(), AC);
66659d1ed5bSDimitry Andric   BR.EmitBasicReport(AC->getDecl(), filter.checkName_strcpy,
667dff0c46cSDimitry Andric                      "Potential insecure memory buffer bounds restriction in "
6683b0f4066SDimitry Andric                      "call 'strcpy'",
6693b0f4066SDimitry Andric                      "Security",
6703b0f4066SDimitry Andric                      "Call to function 'strcpy' is insecure as it does not "
6713b0f4066SDimitry Andric                      "provide bounding of the memory buffer. Replace "
6723b0f4066SDimitry Andric                      "unbounded copy functions with analogous functions that "
673dff0c46cSDimitry Andric                      "support length arguments such as 'strlcpy'. CWE-119.",
674f785676fSDimitry Andric                      CELoc, CE->getCallee()->getSourceRange());
6753b0f4066SDimitry Andric }
6763b0f4066SDimitry Andric 
6773b0f4066SDimitry Andric //===----------------------------------------------------------------------===//
6783b0f4066SDimitry Andric // Check: Any use of 'strcat' is insecure.
6793b0f4066SDimitry Andric //
6803b0f4066SDimitry Andric // CWE-119: Improper Restriction of Operations within
6813b0f4066SDimitry Andric // the Bounds of a Memory Buffer
6823b0f4066SDimitry Andric //===----------------------------------------------------------------------===//
checkCall_strcat(const CallExpr * CE,const FunctionDecl * FD)6833b0f4066SDimitry Andric void WalkAST::checkCall_strcat(const CallExpr *CE, const FunctionDecl *FD) {
684dff0c46cSDimitry Andric   if (!filter.check_strcpy)
685dff0c46cSDimitry Andric     return;
686dff0c46cSDimitry Andric 
6873b0f4066SDimitry Andric   if (!checkCall_strCommon(CE, FD))
6883b0f4066SDimitry Andric     return;
6893b0f4066SDimitry Andric 
6903b0f4066SDimitry Andric   // Issue a warning.
6916122f3e6SDimitry Andric   PathDiagnosticLocation CELoc =
6926122f3e6SDimitry Andric     PathDiagnosticLocation::createBegin(CE, BR.getSourceManager(), AC);
69359d1ed5bSDimitry Andric   BR.EmitBasicReport(AC->getDecl(), filter.checkName_strcpy,
694dff0c46cSDimitry Andric                      "Potential insecure memory buffer bounds restriction in "
6953b0f4066SDimitry Andric                      "call 'strcat'",
6963b0f4066SDimitry Andric                      "Security",
6973b0f4066SDimitry Andric                      "Call to function 'strcat' is insecure as it does not "
6983b0f4066SDimitry Andric                      "provide bounding of the memory buffer. Replace "
6993b0f4066SDimitry Andric                      "unbounded copy functions with analogous functions that "
700dff0c46cSDimitry Andric                      "support length arguments such as 'strlcat'. CWE-119.",
701f785676fSDimitry Andric                      CELoc, CE->getCallee()->getSourceRange());
7023b0f4066SDimitry Andric }
7033b0f4066SDimitry Andric 
7043b0f4066SDimitry Andric //===----------------------------------------------------------------------===//
7053b0f4066SDimitry Andric // Common check for str* functions with no bounds parameters.
7063b0f4066SDimitry Andric //===----------------------------------------------------------------------===//
checkCall_strCommon(const CallExpr * CE,const FunctionDecl * FD)7073b0f4066SDimitry Andric bool WalkAST::checkCall_strCommon(const CallExpr *CE, const FunctionDecl *FD) {
708f785676fSDimitry Andric   const FunctionProtoType *FPT = FD->getType()->getAs<FunctionProtoType>();
7093b0f4066SDimitry Andric   if (!FPT)
7103b0f4066SDimitry Andric     return false;
7113b0f4066SDimitry Andric 
7123b0f4066SDimitry Andric   // Verify the function takes two arguments, three in the _chk version.
71359d1ed5bSDimitry Andric   int numArgs = FPT->getNumParams();
7143b0f4066SDimitry Andric   if (numArgs != 2 && numArgs != 3)
7153b0f4066SDimitry Andric     return false;
7163b0f4066SDimitry Andric 
7173b0f4066SDimitry Andric   // Verify the type for both arguments.
7183b0f4066SDimitry Andric   for (int i = 0; i < 2; i++) {
7193b0f4066SDimitry Andric     // Verify that the arguments are pointers.
72059d1ed5bSDimitry Andric     const PointerType *PT = FPT->getParamType(i)->getAs<PointerType>();
7213b0f4066SDimitry Andric     if (!PT)
7223b0f4066SDimitry Andric       return false;
7233b0f4066SDimitry Andric 
7243b0f4066SDimitry Andric     // Verify that the argument is a 'char*'.
7253b0f4066SDimitry Andric     if (PT->getPointeeType().getUnqualifiedType() != BR.getContext().CharTy)
7263b0f4066SDimitry Andric       return false;
7273b0f4066SDimitry Andric   }
7283b0f4066SDimitry Andric 
7293b0f4066SDimitry Andric   return true;
7303b0f4066SDimitry Andric }
7313b0f4066SDimitry Andric 
7323b0f4066SDimitry Andric //===----------------------------------------------------------------------===//
7332754fe60SDimitry Andric // Check: Linear congruent random number generators should not be used
7342754fe60SDimitry Andric // Originally: <rdar://problem/63371000>
7352754fe60SDimitry Andric // CWE-338: Use of cryptographically weak prng
7362754fe60SDimitry Andric //===----------------------------------------------------------------------===//
7372754fe60SDimitry Andric 
checkCall_rand(const CallExpr * CE,const FunctionDecl * FD)7383b0f4066SDimitry Andric void WalkAST::checkCall_rand(const CallExpr *CE, const FunctionDecl *FD) {
739dff0c46cSDimitry Andric   if (!filter.check_rand || !CheckRand)
7402754fe60SDimitry Andric     return;
7412754fe60SDimitry Andric 
742f785676fSDimitry Andric   const FunctionProtoType *FTP = FD->getType()->getAs<FunctionProtoType>();
7432754fe60SDimitry Andric   if (!FTP)
7442754fe60SDimitry Andric     return;
7452754fe60SDimitry Andric 
74659d1ed5bSDimitry Andric   if (FTP->getNumParams() == 1) {
7472754fe60SDimitry Andric     // Is the argument an 'unsigned short *'?
7482754fe60SDimitry Andric     // (Actually any integer type is allowed.)
74959d1ed5bSDimitry Andric     const PointerType *PT = FTP->getParamType(0)->getAs<PointerType>();
7502754fe60SDimitry Andric     if (!PT)
7512754fe60SDimitry Andric       return;
7522754fe60SDimitry Andric 
753284c1978SDimitry Andric     if (! PT->getPointeeType()->isIntegralOrUnscopedEnumerationType())
7542754fe60SDimitry Andric       return;
75559d1ed5bSDimitry Andric   } else if (FTP->getNumParams() != 0)
7562754fe60SDimitry Andric     return;
7572754fe60SDimitry Andric 
7582754fe60SDimitry Andric   // Issue a warning.
759dff0c46cSDimitry Andric   SmallString<256> buf1;
7602754fe60SDimitry Andric   llvm::raw_svector_ostream os1(buf1);
7616122f3e6SDimitry Andric   os1 << '\'' << *FD << "' is a poor random number generator";
7622754fe60SDimitry Andric 
763dff0c46cSDimitry Andric   SmallString<256> buf2;
7642754fe60SDimitry Andric   llvm::raw_svector_ostream os2(buf2);
7656122f3e6SDimitry Andric   os2 << "Function '" << *FD
7662754fe60SDimitry Andric       << "' is obsolete because it implements a poor random number generator."
7672754fe60SDimitry Andric       << "  Use 'arc4random' instead";
7682754fe60SDimitry Andric 
7696122f3e6SDimitry Andric   PathDiagnosticLocation CELoc =
7706122f3e6SDimitry Andric     PathDiagnosticLocation::createBegin(CE, BR.getSourceManager(), AC);
77159d1ed5bSDimitry Andric   BR.EmitBasicReport(AC->getDecl(), filter.checkName_rand, os1.str(),
77259d1ed5bSDimitry Andric                      "Security", os2.str(), CELoc,
77359d1ed5bSDimitry Andric                      CE->getCallee()->getSourceRange());
7742754fe60SDimitry Andric }
7752754fe60SDimitry Andric 
7762754fe60SDimitry Andric //===----------------------------------------------------------------------===//
7772754fe60SDimitry Andric // Check: 'random' should not be used
7782754fe60SDimitry Andric // Originally: <rdar://problem/63371000>
7792754fe60SDimitry Andric //===----------------------------------------------------------------------===//
7802754fe60SDimitry Andric 
checkCall_random(const CallExpr * CE,const FunctionDecl * FD)7813b0f4066SDimitry Andric void WalkAST::checkCall_random(const CallExpr *CE, const FunctionDecl *FD) {
782dff0c46cSDimitry Andric   if (!CheckRand || !filter.check_rand)
7832754fe60SDimitry Andric     return;
7842754fe60SDimitry Andric 
785f785676fSDimitry Andric   const FunctionProtoType *FTP = FD->getType()->getAs<FunctionProtoType>();
7862754fe60SDimitry Andric   if (!FTP)
7872754fe60SDimitry Andric     return;
7882754fe60SDimitry Andric 
7892754fe60SDimitry Andric   // Verify that the function takes no argument.
79059d1ed5bSDimitry Andric   if (FTP->getNumParams() != 0)
7912754fe60SDimitry Andric     return;
7922754fe60SDimitry Andric 
7932754fe60SDimitry Andric   // Issue a warning.
7946122f3e6SDimitry Andric   PathDiagnosticLocation CELoc =
7956122f3e6SDimitry Andric     PathDiagnosticLocation::createBegin(CE, BR.getSourceManager(), AC);
79659d1ed5bSDimitry Andric   BR.EmitBasicReport(AC->getDecl(), filter.checkName_rand,
797dff0c46cSDimitry Andric                      "'random' is not a secure random number generator",
7982754fe60SDimitry Andric                      "Security",
7992754fe60SDimitry Andric                      "The 'random' function produces a sequence of values that "
8002754fe60SDimitry Andric                      "an adversary may be able to predict.  Use 'arc4random' "
801f785676fSDimitry Andric                      "instead", CELoc, CE->getCallee()->getSourceRange());
8026122f3e6SDimitry Andric }
8036122f3e6SDimitry Andric 
8046122f3e6SDimitry Andric //===----------------------------------------------------------------------===//
8056122f3e6SDimitry Andric // Check: 'vfork' should not be used.
8066122f3e6SDimitry Andric // POS33-C: Do not use vfork().
8076122f3e6SDimitry Andric //===----------------------------------------------------------------------===//
8086122f3e6SDimitry Andric 
checkCall_vfork(const CallExpr * CE,const FunctionDecl * FD)8096122f3e6SDimitry Andric void WalkAST::checkCall_vfork(const CallExpr *CE, const FunctionDecl *FD) {
810dff0c46cSDimitry Andric   if (!filter.check_vfork)
811dff0c46cSDimitry Andric     return;
812dff0c46cSDimitry Andric 
8136122f3e6SDimitry Andric   // All calls to vfork() are insecure, issue a warning.
8146122f3e6SDimitry Andric   PathDiagnosticLocation CELoc =
8156122f3e6SDimitry Andric     PathDiagnosticLocation::createBegin(CE, BR.getSourceManager(), AC);
81659d1ed5bSDimitry Andric   BR.EmitBasicReport(AC->getDecl(), filter.checkName_vfork,
817dff0c46cSDimitry Andric                      "Potential insecure implementation-specific behavior in "
8186122f3e6SDimitry Andric                      "call 'vfork'",
8196122f3e6SDimitry Andric                      "Security",
8206122f3e6SDimitry Andric                      "Call to function 'vfork' is insecure as it can lead to "
8216122f3e6SDimitry Andric                      "denial of service situations in the parent process. "
8226122f3e6SDimitry Andric                      "Replace calls to vfork with calls to the safer "
8236122f3e6SDimitry Andric                      "'posix_spawn' function",
824f785676fSDimitry Andric                      CELoc, CE->getCallee()->getSourceRange());
8252754fe60SDimitry Andric }
8262754fe60SDimitry Andric 
8272754fe60SDimitry Andric //===----------------------------------------------------------------------===//
8282754fe60SDimitry Andric // Check: Should check whether privileges are dropped successfully.
8292754fe60SDimitry Andric // Originally: <rdar://problem/6337132>
8302754fe60SDimitry Andric //===----------------------------------------------------------------------===//
8312754fe60SDimitry Andric 
checkUncheckedReturnValue(CallExpr * CE)8323b0f4066SDimitry Andric void WalkAST::checkUncheckedReturnValue(CallExpr *CE) {
833dff0c46cSDimitry Andric   if (!filter.check_UncheckedReturn)
834dff0c46cSDimitry Andric     return;
835dff0c46cSDimitry Andric 
8362754fe60SDimitry Andric   const FunctionDecl *FD = CE->getDirectCallee();
8372754fe60SDimitry Andric   if (!FD)
8382754fe60SDimitry Andric     return;
8392754fe60SDimitry Andric 
84059d1ed5bSDimitry Andric   if (II_setid[0] == nullptr) {
8412754fe60SDimitry Andric     static const char * const identifiers[num_setids] = {
8422754fe60SDimitry Andric       "setuid", "setgid", "seteuid", "setegid",
8432754fe60SDimitry Andric       "setreuid", "setregid"
8442754fe60SDimitry Andric     };
8452754fe60SDimitry Andric 
8462754fe60SDimitry Andric     for (size_t i = 0; i < num_setids; i++)
8472754fe60SDimitry Andric       II_setid[i] = &BR.getContext().Idents.get(identifiers[i]);
8482754fe60SDimitry Andric   }
8492754fe60SDimitry Andric 
8502754fe60SDimitry Andric   const IdentifierInfo *id = FD->getIdentifier();
8512754fe60SDimitry Andric   size_t identifierid;
8522754fe60SDimitry Andric 
8532754fe60SDimitry Andric   for (identifierid = 0; identifierid < num_setids; identifierid++)
8542754fe60SDimitry Andric     if (id == II_setid[identifierid])
8552754fe60SDimitry Andric       break;
8562754fe60SDimitry Andric 
8572754fe60SDimitry Andric   if (identifierid >= num_setids)
8582754fe60SDimitry Andric     return;
8592754fe60SDimitry Andric 
860f785676fSDimitry Andric   const FunctionProtoType *FTP = FD->getType()->getAs<FunctionProtoType>();
8612754fe60SDimitry Andric   if (!FTP)
8622754fe60SDimitry Andric     return;
8632754fe60SDimitry Andric 
8642754fe60SDimitry Andric   // Verify that the function takes one or two arguments (depending on
8652754fe60SDimitry Andric   //   the function).
86659d1ed5bSDimitry Andric   if (FTP->getNumParams() != (identifierid < 4 ? 1 : 2))
8672754fe60SDimitry Andric     return;
8682754fe60SDimitry Andric 
8692754fe60SDimitry Andric   // The arguments must be integers.
87059d1ed5bSDimitry Andric   for (unsigned i = 0; i < FTP->getNumParams(); i++)
87159d1ed5bSDimitry Andric     if (!FTP->getParamType(i)->isIntegralOrUnscopedEnumerationType())
8722754fe60SDimitry Andric       return;
8732754fe60SDimitry Andric 
8742754fe60SDimitry Andric   // Issue a warning.
875dff0c46cSDimitry Andric   SmallString<256> buf1;
8762754fe60SDimitry Andric   llvm::raw_svector_ostream os1(buf1);
8776122f3e6SDimitry Andric   os1 << "Return value is not checked in call to '" << *FD << '\'';
8782754fe60SDimitry Andric 
879dff0c46cSDimitry Andric   SmallString<256> buf2;
8802754fe60SDimitry Andric   llvm::raw_svector_ostream os2(buf2);
8816122f3e6SDimitry Andric   os2 << "The return value from the call to '" << *FD
8826122f3e6SDimitry Andric       << "' is not checked.  If an error occurs in '" << *FD
8832754fe60SDimitry Andric       << "', the following code may execute with unexpected privileges";
8842754fe60SDimitry Andric 
8856122f3e6SDimitry Andric   PathDiagnosticLocation CELoc =
8866122f3e6SDimitry Andric     PathDiagnosticLocation::createBegin(CE, BR.getSourceManager(), AC);
88759d1ed5bSDimitry Andric   BR.EmitBasicReport(AC->getDecl(), filter.checkName_UncheckedReturn, os1.str(),
88859d1ed5bSDimitry Andric                      "Security", os2.str(), CELoc,
88959d1ed5bSDimitry Andric                      CE->getCallee()->getSourceRange());
8902754fe60SDimitry Andric }
8912754fe60SDimitry Andric 
8922754fe60SDimitry Andric //===----------------------------------------------------------------------===//
8932754fe60SDimitry Andric // SecuritySyntaxChecker
8942754fe60SDimitry Andric //===----------------------------------------------------------------------===//
8952754fe60SDimitry Andric 
8962754fe60SDimitry Andric namespace {
8973b0f4066SDimitry Andric class SecuritySyntaxChecker : public Checker<check::ASTCodeBody> {
8982754fe60SDimitry Andric public:
899dff0c46cSDimitry Andric   ChecksFilter filter;
900dff0c46cSDimitry Andric 
checkASTCodeBody(const Decl * D,AnalysisManager & mgr,BugReporter & BR) const9012754fe60SDimitry Andric   void checkASTCodeBody(const Decl *D, AnalysisManager& mgr,
9022754fe60SDimitry Andric                         BugReporter &BR) const {
903dff0c46cSDimitry Andric     WalkAST walker(BR, mgr.getAnalysisDeclContext(D), filter);
9042754fe60SDimitry Andric     walker.Visit(D->getBody());
9052754fe60SDimitry Andric   }
9062754fe60SDimitry Andric };
9072754fe60SDimitry Andric }
9082754fe60SDimitry Andric 
909dff0c46cSDimitry Andric #define REGISTER_CHECKER(name)                                                 \
910dff0c46cSDimitry Andric   void ento::register##name(CheckerManager &mgr) {                             \
91159d1ed5bSDimitry Andric     SecuritySyntaxChecker *checker =                                           \
91259d1ed5bSDimitry Andric         mgr.registerChecker<SecuritySyntaxChecker>();                          \
91359d1ed5bSDimitry Andric     checker->filter.check_##name = true;                                       \
91459d1ed5bSDimitry Andric     checker->filter.checkName_##name = mgr.getCurrentCheckName();              \
9152754fe60SDimitry Andric   }
916dff0c46cSDimitry Andric 
9174ba319b5SDimitry Andric REGISTER_CHECKER(bcmp)
9184ba319b5SDimitry Andric REGISTER_CHECKER(bcopy)
9194ba319b5SDimitry Andric REGISTER_CHECKER(bzero)
920dff0c46cSDimitry Andric REGISTER_CHECKER(gets)
921dff0c46cSDimitry Andric REGISTER_CHECKER(getpw)
922dff0c46cSDimitry Andric REGISTER_CHECKER(mkstemp)
923dff0c46cSDimitry Andric REGISTER_CHECKER(mktemp)
924dff0c46cSDimitry Andric REGISTER_CHECKER(strcpy)
925dff0c46cSDimitry Andric REGISTER_CHECKER(rand)
926dff0c46cSDimitry Andric REGISTER_CHECKER(vfork)
927dff0c46cSDimitry Andric REGISTER_CHECKER(FloatLoopCounter)
928dff0c46cSDimitry Andric REGISTER_CHECKER(UncheckedReturn)
929dff0c46cSDimitry Andric 
930dff0c46cSDimitry Andric 
931