14c8b2481SRoman Divacky //==- CheckSecuritySyntaxOnly.cpp - Basic security checks --------*- C++ -*-==//
24c8b2481SRoman Divacky //
322989816SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
422989816SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
522989816SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
64c8b2481SRoman Divacky //
74c8b2481SRoman Divacky //===----------------------------------------------------------------------===//
84c8b2481SRoman Divacky //
94c8b2481SRoman Divacky // This file defines a set of flow-insensitive security checks.
104c8b2481SRoman Divacky //
114c8b2481SRoman Divacky //===----------------------------------------------------------------------===//
124c8b2481SRoman Divacky
13676fbe81SDimitry Andric #include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h"
1436981b17SDimitry Andric #include "clang/AST/StmtVisitor.h"
15461a67faSDimitry Andric #include "clang/Analysis/AnalysisDeclContext.h"
1636981b17SDimitry Andric #include "clang/Basic/TargetInfo.h"
17bca07a45SDimitry Andric #include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h"
18809500fcSDimitry Andric #include "clang/StaticAnalyzer/Core/Checker.h"
1936981b17SDimitry Andric #include "clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h"
20dbe13110SDimitry Andric #include "llvm/ADT/SmallString.h"
2101af97d3SDimitry Andric #include "llvm/ADT/StringSwitch.h"
2236981b17SDimitry Andric #include "llvm/Support/raw_ostream.h"
234c8b2481SRoman Divacky
244c8b2481SRoman Divacky using namespace clang;
25bca07a45SDimitry Andric using namespace ento;
264c8b2481SRoman Divacky
isArc4RandomAvailable(const ASTContext & Ctx)27ee791ddeSRoman Divacky static bool isArc4RandomAvailable(const ASTContext &Ctx) {
2836981b17SDimitry Andric const llvm::Triple &T = Ctx.getTargetInfo().getTriple();
29ee791ddeSRoman Divacky return T.getVendor() == llvm::Triple::Apple ||
30676fbe81SDimitry Andric T.isOSFreeBSD() ||
31676fbe81SDimitry Andric T.isOSNetBSD() ||
32676fbe81SDimitry Andric T.isOSOpenBSD() ||
33676fbe81SDimitry Andric T.isOSDragonFly();
34ee791ddeSRoman Divacky }
35ee791ddeSRoman Divacky
364c8b2481SRoman Divacky namespace {
37dbe13110SDimitry Andric struct ChecksFilter {
38145449b1SDimitry Andric bool check_bcmp = false;
39145449b1SDimitry Andric bool check_bcopy = false;
40145449b1SDimitry Andric bool check_bzero = false;
41145449b1SDimitry Andric bool check_gets = false;
42145449b1SDimitry Andric bool check_getpw = false;
43145449b1SDimitry Andric bool check_mktemp = false;
44145449b1SDimitry Andric bool check_mkstemp = false;
45145449b1SDimitry Andric bool check_strcpy = false;
46145449b1SDimitry Andric bool check_DeprecatedOrUnsafeBufferHandling = false;
47145449b1SDimitry Andric bool check_rand = false;
48145449b1SDimitry Andric bool check_vfork = false;
49145449b1SDimitry Andric bool check_FloatLoopCounter = false;
50145449b1SDimitry Andric bool check_UncheckedReturn = false;
51145449b1SDimitry Andric bool check_decodeValueOfObjCType = false;
529f4dbff6SDimitry Andric
53519fc96cSDimitry Andric CheckerNameRef checkName_bcmp;
54519fc96cSDimitry Andric CheckerNameRef checkName_bcopy;
55519fc96cSDimitry Andric CheckerNameRef checkName_bzero;
56519fc96cSDimitry Andric CheckerNameRef checkName_gets;
57519fc96cSDimitry Andric CheckerNameRef checkName_getpw;
58519fc96cSDimitry Andric CheckerNameRef checkName_mktemp;
59519fc96cSDimitry Andric CheckerNameRef checkName_mkstemp;
60519fc96cSDimitry Andric CheckerNameRef checkName_strcpy;
61519fc96cSDimitry Andric CheckerNameRef checkName_DeprecatedOrUnsafeBufferHandling;
62519fc96cSDimitry Andric CheckerNameRef checkName_rand;
63519fc96cSDimitry Andric CheckerNameRef checkName_vfork;
64519fc96cSDimitry Andric CheckerNameRef checkName_FloatLoopCounter;
65519fc96cSDimitry Andric CheckerNameRef checkName_UncheckedReturn;
66706b4fc4SDimitry Andric CheckerNameRef checkName_decodeValueOfObjCType;
67dbe13110SDimitry Andric };
68dbe13110SDimitry Andric
691569ce68SRoman Divacky class WalkAST : public StmtVisitor<WalkAST> {
704c8b2481SRoman Divacky BugReporter &BR;
71dbe13110SDimitry Andric AnalysisDeclContext* AC;
724c8b2481SRoman Divacky enum { num_setids = 6 };
734c8b2481SRoman Divacky IdentifierInfo *II_setid[num_setids];
744c8b2481SRoman Divacky
75ee791ddeSRoman Divacky const bool CheckRand;
76dbe13110SDimitry Andric const ChecksFilter &filter;
77ee791ddeSRoman Divacky
784c8b2481SRoman Divacky public:
WalkAST(BugReporter & br,AnalysisDeclContext * ac,const ChecksFilter & f)79dbe13110SDimitry Andric WalkAST(BugReporter &br, AnalysisDeclContext* ac,
80dbe13110SDimitry Andric const ChecksFilter &f)
8136981b17SDimitry Andric : BR(br), AC(ac), II_setid(),
82dbe13110SDimitry Andric CheckRand(isArc4RandomAvailable(BR.getContext())),
83dbe13110SDimitry Andric filter(f) {}
844c8b2481SRoman Divacky
854c8b2481SRoman Divacky // Statement visitor methods.
864c8b2481SRoman Divacky void VisitCallExpr(CallExpr *CE);
87706b4fc4SDimitry Andric void VisitObjCMessageExpr(ObjCMessageExpr *CE);
884c8b2481SRoman Divacky void VisitForStmt(ForStmt *S);
894c8b2481SRoman Divacky void VisitCompoundStmt (CompoundStmt *S);
VisitStmt(Stmt * S)904c8b2481SRoman Divacky void VisitStmt(Stmt *S) { VisitChildren(S); }
914c8b2481SRoman Divacky
924c8b2481SRoman Divacky void VisitChildren(Stmt *S);
934c8b2481SRoman Divacky
944c8b2481SRoman Divacky // Helpers.
9501af97d3SDimitry Andric bool checkCall_strCommon(const CallExpr *CE, const FunctionDecl *FD);
9601af97d3SDimitry Andric
9745b53394SDimitry Andric typedef void (WalkAST::*FnCheck)(const CallExpr *, const FunctionDecl *);
98706b4fc4SDimitry Andric typedef void (WalkAST::*MsgCheck)(const ObjCMessageExpr *);
994c8b2481SRoman Divacky
1004c8b2481SRoman Divacky // Checker-specific methods.
10101af97d3SDimitry Andric void checkLoopConditionForFloat(const ForStmt *FS);
10248675466SDimitry Andric void checkCall_bcmp(const CallExpr *CE, const FunctionDecl *FD);
10348675466SDimitry Andric void checkCall_bcopy(const CallExpr *CE, const FunctionDecl *FD);
10448675466SDimitry Andric void checkCall_bzero(const CallExpr *CE, const FunctionDecl *FD);
10501af97d3SDimitry Andric void checkCall_gets(const CallExpr *CE, const FunctionDecl *FD);
10601af97d3SDimitry Andric void checkCall_getpw(const CallExpr *CE, const FunctionDecl *FD);
10701af97d3SDimitry Andric void checkCall_mktemp(const CallExpr *CE, const FunctionDecl *FD);
108dbe13110SDimitry Andric void checkCall_mkstemp(const CallExpr *CE, const FunctionDecl *FD);
10901af97d3SDimitry Andric void checkCall_strcpy(const CallExpr *CE, const FunctionDecl *FD);
11001af97d3SDimitry Andric void checkCall_strcat(const CallExpr *CE, const FunctionDecl *FD);
11122989816SDimitry Andric void checkDeprecatedOrUnsafeBufferHandling(const CallExpr *CE,
11222989816SDimitry Andric const FunctionDecl *FD);
11301af97d3SDimitry Andric void checkCall_rand(const CallExpr *CE, const FunctionDecl *FD);
11401af97d3SDimitry Andric void checkCall_random(const CallExpr *CE, const FunctionDecl *FD);
11536981b17SDimitry Andric void checkCall_vfork(const CallExpr *CE, const FunctionDecl *FD);
116706b4fc4SDimitry Andric void checkMsg_decodeValueOfObjCType(const ObjCMessageExpr *ME);
11701af97d3SDimitry Andric void checkUncheckedReturnValue(CallExpr *CE);
1184c8b2481SRoman Divacky };
1194c8b2481SRoman Divacky } // end anonymous namespace
1204c8b2481SRoman Divacky
1214c8b2481SRoman Divacky //===----------------------------------------------------------------------===//
1224c8b2481SRoman Divacky // AST walking.
1234c8b2481SRoman Divacky //===----------------------------------------------------------------------===//
1244c8b2481SRoman Divacky
VisitChildren(Stmt * S)1254c8b2481SRoman Divacky void WalkAST::VisitChildren(Stmt *S) {
126c192b3dcSDimitry Andric for (Stmt *Child : S->children())
127c192b3dcSDimitry Andric if (Child)
128c192b3dcSDimitry Andric Visit(Child);
1294c8b2481SRoman Divacky }
1304c8b2481SRoman Divacky
VisitCallExpr(CallExpr * CE)1314c8b2481SRoman Divacky void WalkAST::VisitCallExpr(CallExpr *CE) {
13201af97d3SDimitry Andric // Get the callee.
13301af97d3SDimitry Andric const FunctionDecl *FD = CE->getDirectCallee();
13401af97d3SDimitry Andric
13501af97d3SDimitry Andric if (!FD)
13601af97d3SDimitry Andric return;
13701af97d3SDimitry Andric
13801af97d3SDimitry Andric // Get the name of the callee. If it's a builtin, strip off the prefix.
13901af97d3SDimitry Andric IdentifierInfo *II = FD->getIdentifier();
14001af97d3SDimitry Andric if (!II) // if no identifier, not a simple C function
14101af97d3SDimitry Andric return;
14236981b17SDimitry Andric StringRef Name = II->getName();
14377dbea07SDimitry Andric Name.consume_front("__builtin_");
14401af97d3SDimitry Andric
14501af97d3SDimitry Andric // Set the evaluation function by switching on the callee name.
146b1c73532SDimitry Andric FnCheck evalFunction =
147b1c73532SDimitry Andric llvm::StringSwitch<FnCheck>(Name)
14848675466SDimitry Andric .Case("bcmp", &WalkAST::checkCall_bcmp)
14948675466SDimitry Andric .Case("bcopy", &WalkAST::checkCall_bcopy)
15048675466SDimitry Andric .Case("bzero", &WalkAST::checkCall_bzero)
15101af97d3SDimitry Andric .Case("gets", &WalkAST::checkCall_gets)
15201af97d3SDimitry Andric .Case("getpw", &WalkAST::checkCall_getpw)
15301af97d3SDimitry Andric .Case("mktemp", &WalkAST::checkCall_mktemp)
154dbe13110SDimitry Andric .Case("mkstemp", &WalkAST::checkCall_mkstemp)
155dbe13110SDimitry Andric .Case("mkdtemp", &WalkAST::checkCall_mkstemp)
156dbe13110SDimitry Andric .Case("mkstemps", &WalkAST::checkCall_mkstemp)
15701af97d3SDimitry Andric .Cases("strcpy", "__strcpy_chk", &WalkAST::checkCall_strcpy)
15801af97d3SDimitry Andric .Cases("strcat", "__strcat_chk", &WalkAST::checkCall_strcat)
15922989816SDimitry Andric .Cases("sprintf", "vsprintf", "scanf", "wscanf", "fscanf", "fwscanf",
16022989816SDimitry Andric "vscanf", "vwscanf", "vfscanf", "vfwscanf",
16122989816SDimitry Andric &WalkAST::checkDeprecatedOrUnsafeBufferHandling)
16222989816SDimitry Andric .Cases("sscanf", "swscanf", "vsscanf", "vswscanf", "swprintf",
16322989816SDimitry Andric "snprintf", "vswprintf", "vsnprintf", "memcpy", "memmove",
16422989816SDimitry Andric &WalkAST::checkDeprecatedOrUnsafeBufferHandling)
165b1c73532SDimitry Andric .Cases("strncpy", "strncat", "memset", "fprintf",
16622989816SDimitry Andric &WalkAST::checkDeprecatedOrUnsafeBufferHandling)
16701af97d3SDimitry Andric .Case("drand48", &WalkAST::checkCall_rand)
16801af97d3SDimitry Andric .Case("erand48", &WalkAST::checkCall_rand)
16901af97d3SDimitry Andric .Case("jrand48", &WalkAST::checkCall_rand)
17001af97d3SDimitry Andric .Case("lrand48", &WalkAST::checkCall_rand)
17101af97d3SDimitry Andric .Case("mrand48", &WalkAST::checkCall_rand)
17201af97d3SDimitry Andric .Case("nrand48", &WalkAST::checkCall_rand)
17301af97d3SDimitry Andric .Case("lcong48", &WalkAST::checkCall_rand)
17401af97d3SDimitry Andric .Case("rand", &WalkAST::checkCall_rand)
17501af97d3SDimitry Andric .Case("rand_r", &WalkAST::checkCall_rand)
17601af97d3SDimitry Andric .Case("random", &WalkAST::checkCall_random)
17736981b17SDimitry Andric .Case("vfork", &WalkAST::checkCall_vfork)
1789f4dbff6SDimitry Andric .Default(nullptr);
17901af97d3SDimitry Andric
18001af97d3SDimitry Andric // If the callee isn't defined, it is not of security concern.
18101af97d3SDimitry Andric // Check and evaluate the call.
18201af97d3SDimitry Andric if (evalFunction)
18301af97d3SDimitry Andric (this->*evalFunction)(CE, FD);
1844c8b2481SRoman Divacky
1854c8b2481SRoman Divacky // Recurse and check children.
1864c8b2481SRoman Divacky VisitChildren(CE);
1874c8b2481SRoman Divacky }
1884c8b2481SRoman Divacky
VisitObjCMessageExpr(ObjCMessageExpr * ME)189706b4fc4SDimitry Andric void WalkAST::VisitObjCMessageExpr(ObjCMessageExpr *ME) {
190706b4fc4SDimitry Andric MsgCheck evalFunction =
191706b4fc4SDimitry Andric llvm::StringSwitch<MsgCheck>(ME->getSelector().getAsString())
192706b4fc4SDimitry Andric .Case("decodeValueOfObjCType:at:",
193706b4fc4SDimitry Andric &WalkAST::checkMsg_decodeValueOfObjCType)
194706b4fc4SDimitry Andric .Default(nullptr);
195706b4fc4SDimitry Andric
196706b4fc4SDimitry Andric if (evalFunction)
197706b4fc4SDimitry Andric (this->*evalFunction)(ME);
198706b4fc4SDimitry Andric
199706b4fc4SDimitry Andric // Recurse and check children.
200706b4fc4SDimitry Andric VisitChildren(ME);
201706b4fc4SDimitry Andric }
202706b4fc4SDimitry Andric
VisitCompoundStmt(CompoundStmt * S)2034c8b2481SRoman Divacky void WalkAST::VisitCompoundStmt(CompoundStmt *S) {
204c192b3dcSDimitry Andric for (Stmt *Child : S->children())
205c192b3dcSDimitry Andric if (Child) {
206c192b3dcSDimitry Andric if (CallExpr *CE = dyn_cast<CallExpr>(Child))
20701af97d3SDimitry Andric checkUncheckedReturnValue(CE);
208c192b3dcSDimitry Andric Visit(Child);
2094c8b2481SRoman Divacky }
2104c8b2481SRoman Divacky }
2114c8b2481SRoman Divacky
VisitForStmt(ForStmt * FS)2124c8b2481SRoman Divacky void WalkAST::VisitForStmt(ForStmt *FS) {
21301af97d3SDimitry Andric checkLoopConditionForFloat(FS);
2144c8b2481SRoman Divacky
2154c8b2481SRoman Divacky // Recurse and check children.
2164c8b2481SRoman Divacky VisitChildren(FS);
2174c8b2481SRoman Divacky }
2184c8b2481SRoman Divacky
2194c8b2481SRoman Divacky //===----------------------------------------------------------------------===//
220676fbe81SDimitry Andric // Check: floating point variable used as loop counter.
2214c8b2481SRoman Divacky // Implements: CERT security coding advisory FLP-30.
2224c8b2481SRoman Divacky //===----------------------------------------------------------------------===//
2234c8b2481SRoman Divacky
224519fc96cSDimitry Andric // Returns either 'x' or 'y', depending on which one of them is incremented
225519fc96cSDimitry Andric // in 'expr', or nullptr if none of them is incremented.
2264c8b2481SRoman Divacky static const DeclRefExpr*
getIncrementedVar(const Expr * expr,const VarDecl * x,const VarDecl * y)22701af97d3SDimitry Andric getIncrementedVar(const Expr *expr, const VarDecl *x, const VarDecl *y) {
2284c8b2481SRoman Divacky expr = expr->IgnoreParenCasts();
2294c8b2481SRoman Divacky
2304c8b2481SRoman Divacky if (const BinaryOperator *B = dyn_cast<BinaryOperator>(expr)) {
2314c8b2481SRoman Divacky if (!(B->isAssignmentOp() || B->isCompoundAssignmentOp() ||
2323d1dcd9bSDimitry Andric B->getOpcode() == BO_Comma))
2339f4dbff6SDimitry Andric return nullptr;
2344c8b2481SRoman Divacky
23501af97d3SDimitry Andric if (const DeclRefExpr *lhs = getIncrementedVar(B->getLHS(), x, y))
2364c8b2481SRoman Divacky return lhs;
2374c8b2481SRoman Divacky
23801af97d3SDimitry Andric if (const DeclRefExpr *rhs = getIncrementedVar(B->getRHS(), x, y))
2394c8b2481SRoman Divacky return rhs;
2404c8b2481SRoman Divacky
2419f4dbff6SDimitry Andric return nullptr;
2424c8b2481SRoman Divacky }
2434c8b2481SRoman Divacky
2444c8b2481SRoman Divacky if (const DeclRefExpr *DR = dyn_cast<DeclRefExpr>(expr)) {
2454c8b2481SRoman Divacky const NamedDecl *ND = DR->getDecl();
2469f4dbff6SDimitry Andric return ND == x || ND == y ? DR : nullptr;
2474c8b2481SRoman Divacky }
2484c8b2481SRoman Divacky
2494c8b2481SRoman Divacky if (const UnaryOperator *U = dyn_cast<UnaryOperator>(expr))
2504c8b2481SRoman Divacky return U->isIncrementDecrementOp()
2519f4dbff6SDimitry Andric ? getIncrementedVar(U->getSubExpr(), x, y) : nullptr;
2524c8b2481SRoman Divacky
2539f4dbff6SDimitry Andric return nullptr;
2544c8b2481SRoman Divacky }
2554c8b2481SRoman Divacky
2564c8b2481SRoman Divacky /// CheckLoopConditionForFloat - This check looks for 'for' statements that
2574c8b2481SRoman Divacky /// use a floating point variable as a loop counter.
2584c8b2481SRoman Divacky /// CERT: FLP30-C, FLP30-CPP.
2594c8b2481SRoman Divacky ///
checkLoopConditionForFloat(const ForStmt * FS)26001af97d3SDimitry Andric void WalkAST::checkLoopConditionForFloat(const ForStmt *FS) {
261dbe13110SDimitry Andric if (!filter.check_FloatLoopCounter)
262dbe13110SDimitry Andric return;
263dbe13110SDimitry Andric
2644c8b2481SRoman Divacky // Does the loop have a condition?
2654c8b2481SRoman Divacky const Expr *condition = FS->getCond();
2664c8b2481SRoman Divacky
2674c8b2481SRoman Divacky if (!condition)
2684c8b2481SRoman Divacky return;
2694c8b2481SRoman Divacky
2704c8b2481SRoman Divacky // Does the loop have an increment?
2714c8b2481SRoman Divacky const Expr *increment = FS->getInc();
2724c8b2481SRoman Divacky
2734c8b2481SRoman Divacky if (!increment)
2744c8b2481SRoman Divacky return;
2754c8b2481SRoman Divacky
2764c8b2481SRoman Divacky // Strip away '()' and casts.
2774c8b2481SRoman Divacky condition = condition->IgnoreParenCasts();
2784c8b2481SRoman Divacky increment = increment->IgnoreParenCasts();
2794c8b2481SRoman Divacky
2804c8b2481SRoman Divacky // Is the loop condition a comparison?
2814c8b2481SRoman Divacky const BinaryOperator *B = dyn_cast<BinaryOperator>(condition);
2824c8b2481SRoman Divacky
2834c8b2481SRoman Divacky if (!B)
2844c8b2481SRoman Divacky return;
2854c8b2481SRoman Divacky
2864c8b2481SRoman Divacky // Is this a comparison?
2874c8b2481SRoman Divacky if (!(B->isRelationalOp() || B->isEqualityOp()))
2884c8b2481SRoman Divacky return;
2894c8b2481SRoman Divacky
2904c8b2481SRoman Divacky // Are we comparing variables?
291bca07a45SDimitry Andric const DeclRefExpr *drLHS =
292bca07a45SDimitry Andric dyn_cast<DeclRefExpr>(B->getLHS()->IgnoreParenLValueCasts());
293bca07a45SDimitry Andric const DeclRefExpr *drRHS =
294bca07a45SDimitry Andric dyn_cast<DeclRefExpr>(B->getRHS()->IgnoreParenLValueCasts());
2954c8b2481SRoman Divacky
2964c8b2481SRoman Divacky // Does at least one of the variables have a floating point type?
2979f4dbff6SDimitry Andric drLHS = drLHS && drLHS->getType()->isRealFloatingType() ? drLHS : nullptr;
2989f4dbff6SDimitry Andric drRHS = drRHS && drRHS->getType()->isRealFloatingType() ? drRHS : nullptr;
2994c8b2481SRoman Divacky
3004c8b2481SRoman Divacky if (!drLHS && !drRHS)
3014c8b2481SRoman Divacky return;
3024c8b2481SRoman Divacky
3039f4dbff6SDimitry Andric const VarDecl *vdLHS = drLHS ? dyn_cast<VarDecl>(drLHS->getDecl()) : nullptr;
3049f4dbff6SDimitry Andric const VarDecl *vdRHS = drRHS ? dyn_cast<VarDecl>(drRHS->getDecl()) : nullptr;
3054c8b2481SRoman Divacky
3064c8b2481SRoman Divacky if (!vdLHS && !vdRHS)
3074c8b2481SRoman Divacky return;
3084c8b2481SRoman Divacky
3094c8b2481SRoman Divacky // Does either variable appear in increment?
31001af97d3SDimitry Andric const DeclRefExpr *drInc = getIncrementedVar(increment, vdLHS, vdRHS);
3114c8b2481SRoman Divacky if (!drInc)
3124c8b2481SRoman Divacky return;
3134c8b2481SRoman Divacky
314519fc96cSDimitry Andric const VarDecl *vdInc = cast<VarDecl>(drInc->getDecl());
315519fc96cSDimitry Andric assert(vdInc && (vdInc == vdLHS || vdInc == vdRHS));
316519fc96cSDimitry Andric
3174c8b2481SRoman Divacky // Emit the error. First figure out which DeclRefExpr in the condition
3184c8b2481SRoman Divacky // referenced the compared variable.
319519fc96cSDimitry Andric const DeclRefExpr *drCond = vdLHS == vdInc ? drLHS : drRHS;
3204c8b2481SRoman Divacky
32136981b17SDimitry Andric SmallVector<SourceRange, 2> ranges;
322dbe13110SDimitry Andric SmallString<256> sbuf;
32311d2b2d2SRoman Divacky llvm::raw_svector_ostream os(sbuf);
3244c8b2481SRoman Divacky
3253d1dcd9bSDimitry Andric os << "Variable '" << drCond->getDecl()->getName()
326145449b1SDimitry Andric << "' with floating point type '" << drCond->getType()
3274c8b2481SRoman Divacky << "' should not be used as a loop counter";
3284c8b2481SRoman Divacky
3294c8b2481SRoman Divacky ranges.push_back(drCond->getSourceRange());
3304c8b2481SRoman Divacky ranges.push_back(drInc->getSourceRange());
3314c8b2481SRoman Divacky
3324c8b2481SRoman Divacky const char *bugType = "Floating point variable used as loop counter";
33336981b17SDimitry Andric
33436981b17SDimitry Andric PathDiagnosticLocation FSLoc =
33536981b17SDimitry Andric PathDiagnosticLocation::createBegin(FS, BR.getSourceManager(), AC);
3369f4dbff6SDimitry Andric BR.EmitBasicReport(AC->getDecl(), filter.checkName_FloatLoopCounter,
337dbe13110SDimitry Andric bugType, "Security", os.str(),
338bfef3995SDimitry Andric FSLoc, ranges);
3394c8b2481SRoman Divacky }
3404c8b2481SRoman Divacky
3414c8b2481SRoman Divacky //===----------------------------------------------------------------------===//
34248675466SDimitry Andric // Check: Any use of bcmp.
34348675466SDimitry Andric // CWE-477: Use of Obsolete Functions
34448675466SDimitry Andric // bcmp was deprecated in POSIX.1-2008
34548675466SDimitry Andric //===----------------------------------------------------------------------===//
34648675466SDimitry Andric
checkCall_bcmp(const CallExpr * CE,const FunctionDecl * FD)34748675466SDimitry Andric void WalkAST::checkCall_bcmp(const CallExpr *CE, const FunctionDecl *FD) {
34848675466SDimitry Andric if (!filter.check_bcmp)
34948675466SDimitry Andric return;
35048675466SDimitry Andric
35148675466SDimitry Andric const FunctionProtoType *FPT = FD->getType()->getAs<FunctionProtoType>();
35248675466SDimitry Andric if (!FPT)
35348675466SDimitry Andric return;
35448675466SDimitry Andric
35548675466SDimitry Andric // Verify that the function takes three arguments.
35648675466SDimitry Andric if (FPT->getNumParams() != 3)
35748675466SDimitry Andric return;
35848675466SDimitry Andric
35948675466SDimitry Andric for (int i = 0; i < 2; i++) {
36048675466SDimitry Andric // Verify the first and second argument type is void*.
36148675466SDimitry Andric const PointerType *PT = FPT->getParamType(i)->getAs<PointerType>();
36248675466SDimitry Andric if (!PT)
36348675466SDimitry Andric return;
36448675466SDimitry Andric
36548675466SDimitry Andric if (PT->getPointeeType().getUnqualifiedType() != BR.getContext().VoidTy)
36648675466SDimitry Andric return;
36748675466SDimitry Andric }
36848675466SDimitry Andric
36948675466SDimitry Andric // Verify the third argument type is integer.
37048675466SDimitry Andric if (!FPT->getParamType(2)->isIntegralOrUnscopedEnumerationType())
37148675466SDimitry Andric return;
37248675466SDimitry Andric
37348675466SDimitry Andric // Issue a warning.
37448675466SDimitry Andric PathDiagnosticLocation CELoc =
37548675466SDimitry Andric PathDiagnosticLocation::createBegin(CE, BR.getSourceManager(), AC);
37648675466SDimitry Andric BR.EmitBasicReport(AC->getDecl(), filter.checkName_bcmp,
37748675466SDimitry Andric "Use of deprecated function in call to 'bcmp()'",
37848675466SDimitry Andric "Security",
37948675466SDimitry Andric "The bcmp() function is obsoleted by memcmp().",
38048675466SDimitry Andric CELoc, CE->getCallee()->getSourceRange());
38148675466SDimitry Andric }
38248675466SDimitry Andric
38348675466SDimitry Andric //===----------------------------------------------------------------------===//
38448675466SDimitry Andric // Check: Any use of bcopy.
38548675466SDimitry Andric // CWE-477: Use of Obsolete Functions
38648675466SDimitry Andric // bcopy was deprecated in POSIX.1-2008
38748675466SDimitry Andric //===----------------------------------------------------------------------===//
38848675466SDimitry Andric
checkCall_bcopy(const CallExpr * CE,const FunctionDecl * FD)38948675466SDimitry Andric void WalkAST::checkCall_bcopy(const CallExpr *CE, const FunctionDecl *FD) {
39048675466SDimitry Andric if (!filter.check_bcopy)
39148675466SDimitry Andric return;
39248675466SDimitry Andric
39348675466SDimitry Andric const FunctionProtoType *FPT = FD->getType()->getAs<FunctionProtoType>();
39448675466SDimitry Andric if (!FPT)
39548675466SDimitry Andric return;
39648675466SDimitry Andric
39748675466SDimitry Andric // Verify that the function takes three arguments.
39848675466SDimitry Andric if (FPT->getNumParams() != 3)
39948675466SDimitry Andric return;
40048675466SDimitry Andric
40148675466SDimitry Andric for (int i = 0; i < 2; i++) {
40248675466SDimitry Andric // Verify the first and second argument type is void*.
40348675466SDimitry Andric const PointerType *PT = FPT->getParamType(i)->getAs<PointerType>();
40448675466SDimitry Andric if (!PT)
40548675466SDimitry Andric return;
40648675466SDimitry Andric
40748675466SDimitry Andric if (PT->getPointeeType().getUnqualifiedType() != BR.getContext().VoidTy)
40848675466SDimitry Andric return;
40948675466SDimitry Andric }
41048675466SDimitry Andric
41148675466SDimitry Andric // Verify the third argument type is integer.
41248675466SDimitry Andric if (!FPT->getParamType(2)->isIntegralOrUnscopedEnumerationType())
41348675466SDimitry Andric return;
41448675466SDimitry Andric
41548675466SDimitry Andric // Issue a warning.
41648675466SDimitry Andric PathDiagnosticLocation CELoc =
41748675466SDimitry Andric PathDiagnosticLocation::createBegin(CE, BR.getSourceManager(), AC);
41848675466SDimitry Andric BR.EmitBasicReport(AC->getDecl(), filter.checkName_bcopy,
41948675466SDimitry Andric "Use of deprecated function in call to 'bcopy()'",
42048675466SDimitry Andric "Security",
42148675466SDimitry Andric "The bcopy() function is obsoleted by memcpy() "
42248675466SDimitry Andric "or memmove().",
42348675466SDimitry Andric CELoc, CE->getCallee()->getSourceRange());
42448675466SDimitry Andric }
42548675466SDimitry Andric
42648675466SDimitry Andric //===----------------------------------------------------------------------===//
42748675466SDimitry Andric // Check: Any use of bzero.
42848675466SDimitry Andric // CWE-477: Use of Obsolete Functions
42948675466SDimitry Andric // bzero was deprecated in POSIX.1-2008
43048675466SDimitry Andric //===----------------------------------------------------------------------===//
43148675466SDimitry Andric
checkCall_bzero(const CallExpr * CE,const FunctionDecl * FD)43248675466SDimitry Andric void WalkAST::checkCall_bzero(const CallExpr *CE, const FunctionDecl *FD) {
43348675466SDimitry Andric if (!filter.check_bzero)
43448675466SDimitry Andric return;
43548675466SDimitry Andric
43648675466SDimitry Andric const FunctionProtoType *FPT = FD->getType()->getAs<FunctionProtoType>();
43748675466SDimitry Andric if (!FPT)
43848675466SDimitry Andric return;
43948675466SDimitry Andric
44048675466SDimitry Andric // Verify that the function takes two arguments.
44148675466SDimitry Andric if (FPT->getNumParams() != 2)
44248675466SDimitry Andric return;
44348675466SDimitry Andric
44448675466SDimitry Andric // Verify the first argument type is void*.
44548675466SDimitry Andric const PointerType *PT = FPT->getParamType(0)->getAs<PointerType>();
44648675466SDimitry Andric if (!PT)
44748675466SDimitry Andric return;
44848675466SDimitry Andric
44948675466SDimitry Andric if (PT->getPointeeType().getUnqualifiedType() != BR.getContext().VoidTy)
45048675466SDimitry Andric return;
45148675466SDimitry Andric
45248675466SDimitry Andric // Verify the second argument type is integer.
45348675466SDimitry Andric if (!FPT->getParamType(1)->isIntegralOrUnscopedEnumerationType())
45448675466SDimitry Andric return;
45548675466SDimitry Andric
45648675466SDimitry Andric // Issue a warning.
45748675466SDimitry Andric PathDiagnosticLocation CELoc =
45848675466SDimitry Andric PathDiagnosticLocation::createBegin(CE, BR.getSourceManager(), AC);
45948675466SDimitry Andric BR.EmitBasicReport(AC->getDecl(), filter.checkName_bzero,
46048675466SDimitry Andric "Use of deprecated function in call to 'bzero()'",
46148675466SDimitry Andric "Security",
46248675466SDimitry Andric "The bzero() function is obsoleted by memset().",
46348675466SDimitry Andric CELoc, CE->getCallee()->getSourceRange());
46448675466SDimitry Andric }
46548675466SDimitry Andric
46648675466SDimitry Andric
46748675466SDimitry Andric //===----------------------------------------------------------------------===//
468b1c73532SDimitry Andric // Check: Any use of 'gets' is insecure. Most man pages literally says this.
469b1c73532SDimitry Andric //
4704c8b2481SRoman Divacky // Implements (part of): 300-BSI (buildsecurityin.us-cert.gov)
471b3d5a323SRoman Divacky // CWE-242: Use of Inherently Dangerous Function
4724c8b2481SRoman Divacky //===----------------------------------------------------------------------===//
4734c8b2481SRoman Divacky
checkCall_gets(const CallExpr * CE,const FunctionDecl * FD)47401af97d3SDimitry Andric void WalkAST::checkCall_gets(const CallExpr *CE, const FunctionDecl *FD) {
475dbe13110SDimitry Andric if (!filter.check_gets)
476dbe13110SDimitry Andric return;
477dbe13110SDimitry Andric
478bfef3995SDimitry Andric const FunctionProtoType *FPT = FD->getType()->getAs<FunctionProtoType>();
479b3d5a323SRoman Divacky if (!FPT)
4804c8b2481SRoman Divacky return;
4814c8b2481SRoman Divacky
4824c8b2481SRoman Divacky // Verify that the function takes a single argument.
4839f4dbff6SDimitry Andric if (FPT->getNumParams() != 1)
4844c8b2481SRoman Divacky return;
4854c8b2481SRoman Divacky
4864c8b2481SRoman Divacky // Is the argument a 'char*'?
4879f4dbff6SDimitry Andric const PointerType *PT = FPT->getParamType(0)->getAs<PointerType>();
4884c8b2481SRoman Divacky if (!PT)
4894c8b2481SRoman Divacky return;
4904c8b2481SRoman Divacky
4914c8b2481SRoman Divacky if (PT->getPointeeType().getUnqualifiedType() != BR.getContext().CharTy)
4924c8b2481SRoman Divacky return;
4934c8b2481SRoman Divacky
4944c8b2481SRoman Divacky // Issue a warning.
49536981b17SDimitry Andric PathDiagnosticLocation CELoc =
49636981b17SDimitry Andric PathDiagnosticLocation::createBegin(CE, BR.getSourceManager(), AC);
4979f4dbff6SDimitry Andric BR.EmitBasicReport(AC->getDecl(), filter.checkName_gets,
498dbe13110SDimitry Andric "Potential buffer overflow in call to 'gets'",
4994c8b2481SRoman Divacky "Security",
5004c8b2481SRoman Divacky "Call to function 'gets' is extremely insecure as it can "
5014c8b2481SRoman Divacky "always result in a buffer overflow",
502bfef3995SDimitry Andric CELoc, CE->getCallee()->getSourceRange());
5034c8b2481SRoman Divacky }
5044c8b2481SRoman Divacky
5054c8b2481SRoman Divacky //===----------------------------------------------------------------------===//
506b3d5a323SRoman Divacky // Check: Any use of 'getpwd' is insecure.
507b3d5a323SRoman Divacky // CWE-477: Use of Obsolete Functions
508b3d5a323SRoman Divacky //===----------------------------------------------------------------------===//
509b3d5a323SRoman Divacky
checkCall_getpw(const CallExpr * CE,const FunctionDecl * FD)51001af97d3SDimitry Andric void WalkAST::checkCall_getpw(const CallExpr *CE, const FunctionDecl *FD) {
511dbe13110SDimitry Andric if (!filter.check_getpw)
512dbe13110SDimitry Andric return;
513dbe13110SDimitry Andric
514bfef3995SDimitry Andric const FunctionProtoType *FPT = FD->getType()->getAs<FunctionProtoType>();
515b3d5a323SRoman Divacky if (!FPT)
516b3d5a323SRoman Divacky return;
517b3d5a323SRoman Divacky
518b3d5a323SRoman Divacky // Verify that the function takes two arguments.
5199f4dbff6SDimitry Andric if (FPT->getNumParams() != 2)
520b3d5a323SRoman Divacky return;
521b3d5a323SRoman Divacky
522b3d5a323SRoman Divacky // Verify the first argument type is integer.
5239f4dbff6SDimitry Andric if (!FPT->getParamType(0)->isIntegralOrUnscopedEnumerationType())
524b3d5a323SRoman Divacky return;
525b3d5a323SRoman Divacky
526b3d5a323SRoman Divacky // Verify the second argument type is char*.
5279f4dbff6SDimitry Andric const PointerType *PT = FPT->getParamType(1)->getAs<PointerType>();
528b3d5a323SRoman Divacky if (!PT)
529b3d5a323SRoman Divacky return;
530b3d5a323SRoman Divacky
531b3d5a323SRoman Divacky if (PT->getPointeeType().getUnqualifiedType() != BR.getContext().CharTy)
532b3d5a323SRoman Divacky return;
533b3d5a323SRoman Divacky
534b3d5a323SRoman Divacky // Issue a warning.
53536981b17SDimitry Andric PathDiagnosticLocation CELoc =
53636981b17SDimitry Andric PathDiagnosticLocation::createBegin(CE, BR.getSourceManager(), AC);
5379f4dbff6SDimitry Andric BR.EmitBasicReport(AC->getDecl(), filter.checkName_getpw,
538dbe13110SDimitry Andric "Potential buffer overflow in call to 'getpw'",
539b3d5a323SRoman Divacky "Security",
540b3d5a323SRoman Divacky "The getpw() function is dangerous as it may overflow the "
541b3d5a323SRoman Divacky "provided buffer. It is obsoleted by getpwuid().",
542bfef3995SDimitry Andric CELoc, CE->getCallee()->getSourceRange());
543b3d5a323SRoman Divacky }
544b3d5a323SRoman Divacky
545b3d5a323SRoman Divacky //===----------------------------------------------------------------------===//
54634d02d0bSRoman Divacky // Check: Any use of 'mktemp' is insecure. It is obsoleted by mkstemp().
54734d02d0bSRoman Divacky // CWE-377: Insecure Temporary File
54834d02d0bSRoman Divacky //===----------------------------------------------------------------------===//
54934d02d0bSRoman Divacky
checkCall_mktemp(const CallExpr * CE,const FunctionDecl * FD)55001af97d3SDimitry Andric void WalkAST::checkCall_mktemp(const CallExpr *CE, const FunctionDecl *FD) {
551dbe13110SDimitry Andric if (!filter.check_mktemp) {
552dbe13110SDimitry Andric // Fall back to the security check of looking for enough 'X's in the
553dbe13110SDimitry Andric // format string, since that is a less severe warning.
554dbe13110SDimitry Andric checkCall_mkstemp(CE, FD);
555dbe13110SDimitry Andric return;
556dbe13110SDimitry Andric }
557dbe13110SDimitry Andric
558bfef3995SDimitry Andric const FunctionProtoType *FPT = FD->getType()->getAs<FunctionProtoType>();
55934d02d0bSRoman Divacky if(!FPT)
56034d02d0bSRoman Divacky return;
56134d02d0bSRoman Divacky
56201af97d3SDimitry Andric // Verify that the function takes a single argument.
5639f4dbff6SDimitry Andric if (FPT->getNumParams() != 1)
56434d02d0bSRoman Divacky return;
56534d02d0bSRoman Divacky
56634d02d0bSRoman Divacky // Verify that the argument is Pointer Type.
5679f4dbff6SDimitry Andric const PointerType *PT = FPT->getParamType(0)->getAs<PointerType>();
56834d02d0bSRoman Divacky if (!PT)
56934d02d0bSRoman Divacky return;
57034d02d0bSRoman Divacky
57134d02d0bSRoman Divacky // Verify that the argument is a 'char*'.
57234d02d0bSRoman Divacky if (PT->getPointeeType().getUnqualifiedType() != BR.getContext().CharTy)
57334d02d0bSRoman Divacky return;
57434d02d0bSRoman Divacky
5759f4dbff6SDimitry Andric // Issue a warning.
57636981b17SDimitry Andric PathDiagnosticLocation CELoc =
57736981b17SDimitry Andric PathDiagnosticLocation::createBegin(CE, BR.getSourceManager(), AC);
5789f4dbff6SDimitry Andric BR.EmitBasicReport(AC->getDecl(), filter.checkName_mktemp,
579dbe13110SDimitry Andric "Potential insecure temporary file in call 'mktemp'",
58034d02d0bSRoman Divacky "Security",
58134d02d0bSRoman Divacky "Call to function 'mktemp' is insecure as it always "
582dbe13110SDimitry Andric "creates or uses insecure temporary file. Use 'mkstemp' "
583dbe13110SDimitry Andric "instead",
584bfef3995SDimitry Andric CELoc, CE->getCallee()->getSourceRange());
58534d02d0bSRoman Divacky }
58634d02d0bSRoman Divacky
587dbe13110SDimitry Andric //===----------------------------------------------------------------------===//
588dbe13110SDimitry Andric // Check: Use of 'mkstemp', 'mktemp', 'mkdtemp' should contain at least 6 X's.
589dbe13110SDimitry Andric //===----------------------------------------------------------------------===//
590dbe13110SDimitry Andric
checkCall_mkstemp(const CallExpr * CE,const FunctionDecl * FD)591dbe13110SDimitry Andric void WalkAST::checkCall_mkstemp(const CallExpr *CE, const FunctionDecl *FD) {
592dbe13110SDimitry Andric if (!filter.check_mkstemp)
593dbe13110SDimitry Andric return;
594dbe13110SDimitry Andric
595dbe13110SDimitry Andric StringRef Name = FD->getIdentifier()->getName();
596dbe13110SDimitry Andric std::pair<signed, signed> ArgSuffix =
597dbe13110SDimitry Andric llvm::StringSwitch<std::pair<signed, signed> >(Name)
598dbe13110SDimitry Andric .Case("mktemp", std::make_pair(0,-1))
599dbe13110SDimitry Andric .Case("mkstemp", std::make_pair(0,-1))
600dbe13110SDimitry Andric .Case("mkdtemp", std::make_pair(0,-1))
601dbe13110SDimitry Andric .Case("mkstemps", std::make_pair(0,1))
602dbe13110SDimitry Andric .Default(std::make_pair(-1, -1));
603dbe13110SDimitry Andric
604dbe13110SDimitry Andric assert(ArgSuffix.first >= 0 && "Unsupported function");
605dbe13110SDimitry Andric
606dbe13110SDimitry Andric // Check if the number of arguments is consistent with out expectations.
607dbe13110SDimitry Andric unsigned numArgs = CE->getNumArgs();
608dbe13110SDimitry Andric if ((signed) numArgs <= ArgSuffix.first)
609dbe13110SDimitry Andric return;
610dbe13110SDimitry Andric
611dbe13110SDimitry Andric const StringLiteral *strArg =
612dbe13110SDimitry Andric dyn_cast<StringLiteral>(CE->getArg((unsigned)ArgSuffix.first)
613dbe13110SDimitry Andric ->IgnoreParenImpCasts());
614dbe13110SDimitry Andric
615dbe13110SDimitry Andric // Currently we only handle string literals. It is possible to do better,
616dbe13110SDimitry Andric // either by looking at references to const variables, or by doing real
617dbe13110SDimitry Andric // flow analysis.
618dbe13110SDimitry Andric if (!strArg || strArg->getCharByteWidth() != 1)
619dbe13110SDimitry Andric return;
620dbe13110SDimitry Andric
621dbe13110SDimitry Andric // Count the number of X's, taking into account a possible cutoff suffix.
622dbe13110SDimitry Andric StringRef str = strArg->getString();
623dbe13110SDimitry Andric unsigned numX = 0;
624dbe13110SDimitry Andric unsigned n = str.size();
625dbe13110SDimitry Andric
626dbe13110SDimitry Andric // Take into account the suffix.
627dbe13110SDimitry Andric unsigned suffix = 0;
628dbe13110SDimitry Andric if (ArgSuffix.second >= 0) {
629dbe13110SDimitry Andric const Expr *suffixEx = CE->getArg((unsigned)ArgSuffix.second);
630676fbe81SDimitry Andric Expr::EvalResult EVResult;
631676fbe81SDimitry Andric if (!suffixEx->EvaluateAsInt(EVResult, BR.getContext()))
632dbe13110SDimitry Andric return;
633676fbe81SDimitry Andric llvm::APSInt Result = EVResult.Val.getInt();
634dbe13110SDimitry Andric // FIXME: Issue a warning.
635dbe13110SDimitry Andric if (Result.isNegative())
636dbe13110SDimitry Andric return;
637dbe13110SDimitry Andric suffix = (unsigned) Result.getZExtValue();
638dbe13110SDimitry Andric n = (n > suffix) ? n - suffix : 0;
639dbe13110SDimitry Andric }
640dbe13110SDimitry Andric
641dbe13110SDimitry Andric for (unsigned i = 0; i < n; ++i)
642dbe13110SDimitry Andric if (str[i] == 'X') ++numX;
643dbe13110SDimitry Andric
644dbe13110SDimitry Andric if (numX >= 6)
645dbe13110SDimitry Andric return;
646dbe13110SDimitry Andric
647dbe13110SDimitry Andric // Issue a warning.
648dbe13110SDimitry Andric PathDiagnosticLocation CELoc =
649dbe13110SDimitry Andric PathDiagnosticLocation::createBegin(CE, BR.getSourceManager(), AC);
650dbe13110SDimitry Andric SmallString<512> buf;
651dbe13110SDimitry Andric llvm::raw_svector_ostream out(buf);
652dbe13110SDimitry Andric out << "Call to '" << Name << "' should have at least 6 'X's in the"
653dbe13110SDimitry Andric " format string to be secure (" << numX << " 'X'";
654dbe13110SDimitry Andric if (numX != 1)
655dbe13110SDimitry Andric out << 's';
656dbe13110SDimitry Andric out << " seen";
657dbe13110SDimitry Andric if (suffix) {
658dbe13110SDimitry Andric out << ", " << suffix << " character";
659dbe13110SDimitry Andric if (suffix > 1)
660dbe13110SDimitry Andric out << 's';
661dbe13110SDimitry Andric out << " used as a suffix";
662dbe13110SDimitry Andric }
663dbe13110SDimitry Andric out << ')';
6649f4dbff6SDimitry Andric BR.EmitBasicReport(AC->getDecl(), filter.checkName_mkstemp,
665dbe13110SDimitry Andric "Insecure temporary file creation", "Security",
666bfef3995SDimitry Andric out.str(), CELoc, strArg->getSourceRange());
667dbe13110SDimitry Andric }
668dbe13110SDimitry Andric
66934d02d0bSRoman Divacky //===----------------------------------------------------------------------===//
67001af97d3SDimitry Andric // Check: Any use of 'strcpy' is insecure.
67101af97d3SDimitry Andric //
67201af97d3SDimitry Andric // CWE-119: Improper Restriction of Operations within
67301af97d3SDimitry Andric // the Bounds of a Memory Buffer
67401af97d3SDimitry Andric //===----------------------------------------------------------------------===//
67522989816SDimitry Andric
checkCall_strcpy(const CallExpr * CE,const FunctionDecl * FD)67601af97d3SDimitry Andric void WalkAST::checkCall_strcpy(const CallExpr *CE, const FunctionDecl *FD) {
677dbe13110SDimitry Andric if (!filter.check_strcpy)
678dbe13110SDimitry Andric return;
679dbe13110SDimitry Andric
68001af97d3SDimitry Andric if (!checkCall_strCommon(CE, FD))
68101af97d3SDimitry Andric return;
68201af97d3SDimitry Andric
68348675466SDimitry Andric const auto *Target = CE->getArg(0)->IgnoreImpCasts(),
68448675466SDimitry Andric *Source = CE->getArg(1)->IgnoreImpCasts();
685676fbe81SDimitry Andric
686676fbe81SDimitry Andric if (const auto *Array = dyn_cast<ConstantArrayType>(Target->getType())) {
68748675466SDimitry Andric uint64_t ArraySize = BR.getContext().getTypeSize(Array) / 8;
68848675466SDimitry Andric if (const auto *String = dyn_cast<StringLiteral>(Source)) {
68948675466SDimitry Andric if (ArraySize >= String->getLength() + 1)
69048675466SDimitry Andric return;
69148675466SDimitry Andric }
69248675466SDimitry Andric }
69348675466SDimitry Andric
69401af97d3SDimitry Andric // Issue a warning.
69536981b17SDimitry Andric PathDiagnosticLocation CELoc =
69636981b17SDimitry Andric PathDiagnosticLocation::createBegin(CE, BR.getSourceManager(), AC);
6979f4dbff6SDimitry Andric BR.EmitBasicReport(AC->getDecl(), filter.checkName_strcpy,
698dbe13110SDimitry Andric "Potential insecure memory buffer bounds restriction in "
69901af97d3SDimitry Andric "call 'strcpy'",
70001af97d3SDimitry Andric "Security",
70101af97d3SDimitry Andric "Call to function 'strcpy' is insecure as it does not "
70201af97d3SDimitry Andric "provide bounding of the memory buffer. Replace "
70301af97d3SDimitry Andric "unbounded copy functions with analogous functions that "
704dbe13110SDimitry Andric "support length arguments such as 'strlcpy'. CWE-119.",
705bfef3995SDimitry Andric CELoc, CE->getCallee()->getSourceRange());
70601af97d3SDimitry Andric }
70701af97d3SDimitry Andric
70801af97d3SDimitry Andric //===----------------------------------------------------------------------===//
70901af97d3SDimitry Andric // Check: Any use of 'strcat' is insecure.
71001af97d3SDimitry Andric //
71101af97d3SDimitry Andric // CWE-119: Improper Restriction of Operations within
71201af97d3SDimitry Andric // the Bounds of a Memory Buffer
71301af97d3SDimitry Andric //===----------------------------------------------------------------------===//
71422989816SDimitry Andric
checkCall_strcat(const CallExpr * CE,const FunctionDecl * FD)71501af97d3SDimitry Andric void WalkAST::checkCall_strcat(const CallExpr *CE, const FunctionDecl *FD) {
716dbe13110SDimitry Andric if (!filter.check_strcpy)
717dbe13110SDimitry Andric return;
718dbe13110SDimitry Andric
71901af97d3SDimitry Andric if (!checkCall_strCommon(CE, FD))
72001af97d3SDimitry Andric return;
72101af97d3SDimitry Andric
72201af97d3SDimitry Andric // Issue a warning.
72336981b17SDimitry Andric PathDiagnosticLocation CELoc =
72436981b17SDimitry Andric PathDiagnosticLocation::createBegin(CE, BR.getSourceManager(), AC);
7259f4dbff6SDimitry Andric BR.EmitBasicReport(AC->getDecl(), filter.checkName_strcpy,
726dbe13110SDimitry Andric "Potential insecure memory buffer bounds restriction in "
72701af97d3SDimitry Andric "call 'strcat'",
72801af97d3SDimitry Andric "Security",
72901af97d3SDimitry Andric "Call to function 'strcat' is insecure as it does not "
73001af97d3SDimitry Andric "provide bounding of the memory buffer. Replace "
73101af97d3SDimitry Andric "unbounded copy functions with analogous functions that "
732dbe13110SDimitry Andric "support length arguments such as 'strlcat'. CWE-119.",
733bfef3995SDimitry Andric CELoc, CE->getCallee()->getSourceRange());
73401af97d3SDimitry Andric }
73501af97d3SDimitry Andric
73601af97d3SDimitry Andric //===----------------------------------------------------------------------===//
73722989816SDimitry Andric // Check: Any use of 'sprintf', 'vsprintf', 'scanf', 'wscanf', 'fscanf',
73822989816SDimitry Andric // 'fwscanf', 'vscanf', 'vwscanf', 'vfscanf', 'vfwscanf', 'sscanf',
73922989816SDimitry Andric // 'swscanf', 'vsscanf', 'vswscanf', 'swprintf', 'snprintf', 'vswprintf',
740b1c73532SDimitry Andric // 'vsnprintf', 'memcpy', 'memmove', 'strncpy', 'strncat', 'memset',
741b1c73532SDimitry Andric // 'fprintf' is deprecated since C11.
74222989816SDimitry Andric //
743b1c73532SDimitry Andric // Use of 'sprintf', 'fprintf', 'vsprintf', 'scanf', 'wscanf', 'fscanf',
74422989816SDimitry Andric // 'fwscanf', 'vscanf', 'vwscanf', 'vfscanf', 'vfwscanf', 'sscanf',
74522989816SDimitry Andric // 'swscanf', 'vsscanf', 'vswscanf' without buffer limitations
74622989816SDimitry Andric // is insecure.
74722989816SDimitry Andric //
74822989816SDimitry Andric // CWE-119: Improper Restriction of Operations within
74922989816SDimitry Andric // the Bounds of a Memory Buffer
75022989816SDimitry Andric //===----------------------------------------------------------------------===//
75122989816SDimitry Andric
checkDeprecatedOrUnsafeBufferHandling(const CallExpr * CE,const FunctionDecl * FD)75222989816SDimitry Andric void WalkAST::checkDeprecatedOrUnsafeBufferHandling(const CallExpr *CE,
75322989816SDimitry Andric const FunctionDecl *FD) {
75422989816SDimitry Andric if (!filter.check_DeprecatedOrUnsafeBufferHandling)
75522989816SDimitry Andric return;
75622989816SDimitry Andric
75722989816SDimitry Andric if (!BR.getContext().getLangOpts().C11)
75822989816SDimitry Andric return;
75922989816SDimitry Andric
76022989816SDimitry Andric // Issue a warning. ArgIndex == -1: Deprecated but not unsafe (has size
76122989816SDimitry Andric // restrictions).
76222989816SDimitry Andric enum { DEPR_ONLY = -1, UNKNOWN_CALL = -2 };
76322989816SDimitry Andric
76422989816SDimitry Andric StringRef Name = FD->getIdentifier()->getName();
76577dbea07SDimitry Andric Name.consume_front("__builtin_");
76622989816SDimitry Andric
76722989816SDimitry Andric int ArgIndex =
76822989816SDimitry Andric llvm::StringSwitch<int>(Name)
76922989816SDimitry Andric .Cases("scanf", "wscanf", "vscanf", "vwscanf", 0)
770b1c73532SDimitry Andric .Cases("fscanf", "fwscanf", "vfscanf", "vfwscanf", "sscanf",
771b1c73532SDimitry Andric "swscanf", "vsscanf", "vswscanf", 1)
772b1c73532SDimitry Andric .Cases("sprintf", "vsprintf", "fprintf", 1)
77322989816SDimitry Andric .Cases("swprintf", "snprintf", "vswprintf", "vsnprintf", "memcpy",
77422989816SDimitry Andric "memmove", "memset", "strncpy", "strncat", DEPR_ONLY)
77522989816SDimitry Andric .Default(UNKNOWN_CALL);
77622989816SDimitry Andric
77722989816SDimitry Andric assert(ArgIndex != UNKNOWN_CALL && "Unsupported function");
77822989816SDimitry Andric bool BoundsProvided = ArgIndex == DEPR_ONLY;
77922989816SDimitry Andric
78022989816SDimitry Andric if (!BoundsProvided) {
78122989816SDimitry Andric // Currently we only handle (not wide) string literals. It is possible to do
78222989816SDimitry Andric // better, either by looking at references to const variables, or by doing
78322989816SDimitry Andric // real flow analysis.
78422989816SDimitry Andric auto FormatString =
78522989816SDimitry Andric dyn_cast<StringLiteral>(CE->getArg(ArgIndex)->IgnoreParenImpCasts());
786c0981da4SDimitry Andric if (FormatString && !FormatString->getString().contains("%s") &&
787c0981da4SDimitry Andric !FormatString->getString().contains("%["))
78822989816SDimitry Andric BoundsProvided = true;
78922989816SDimitry Andric }
79022989816SDimitry Andric
79122989816SDimitry Andric SmallString<128> Buf1;
79222989816SDimitry Andric SmallString<512> Buf2;
79322989816SDimitry Andric llvm::raw_svector_ostream Out1(Buf1);
79422989816SDimitry Andric llvm::raw_svector_ostream Out2(Buf2);
79522989816SDimitry Andric
79622989816SDimitry Andric Out1 << "Potential insecure memory buffer bounds restriction in call '"
79722989816SDimitry Andric << Name << "'";
79822989816SDimitry Andric Out2 << "Call to function '" << Name
79922989816SDimitry Andric << "' is insecure as it does not provide ";
80022989816SDimitry Andric
80122989816SDimitry Andric if (!BoundsProvided) {
80222989816SDimitry Andric Out2 << "bounding of the memory buffer or ";
80322989816SDimitry Andric }
80422989816SDimitry Andric
80522989816SDimitry Andric Out2 << "security checks introduced "
80622989816SDimitry Andric "in the C11 standard. Replace with analogous functions that "
80722989816SDimitry Andric "support length arguments or provides boundary checks such as '"
80822989816SDimitry Andric << Name << "_s' in case of C11";
80922989816SDimitry Andric
81022989816SDimitry Andric PathDiagnosticLocation CELoc =
81122989816SDimitry Andric PathDiagnosticLocation::createBegin(CE, BR.getSourceManager(), AC);
81222989816SDimitry Andric BR.EmitBasicReport(AC->getDecl(),
81322989816SDimitry Andric filter.checkName_DeprecatedOrUnsafeBufferHandling,
81422989816SDimitry Andric Out1.str(), "Security", Out2.str(), CELoc,
81522989816SDimitry Andric CE->getCallee()->getSourceRange());
81622989816SDimitry Andric }
81722989816SDimitry Andric
81822989816SDimitry Andric //===----------------------------------------------------------------------===//
81901af97d3SDimitry Andric // Common check for str* functions with no bounds parameters.
82001af97d3SDimitry Andric //===----------------------------------------------------------------------===//
82122989816SDimitry Andric
checkCall_strCommon(const CallExpr * CE,const FunctionDecl * FD)82201af97d3SDimitry Andric bool WalkAST::checkCall_strCommon(const CallExpr *CE, const FunctionDecl *FD) {
823bfef3995SDimitry Andric const FunctionProtoType *FPT = FD->getType()->getAs<FunctionProtoType>();
82401af97d3SDimitry Andric if (!FPT)
82501af97d3SDimitry Andric return false;
82601af97d3SDimitry Andric
82701af97d3SDimitry Andric // Verify the function takes two arguments, three in the _chk version.
8289f4dbff6SDimitry Andric int numArgs = FPT->getNumParams();
82901af97d3SDimitry Andric if (numArgs != 2 && numArgs != 3)
83001af97d3SDimitry Andric return false;
83101af97d3SDimitry Andric
83201af97d3SDimitry Andric // Verify the type for both arguments.
83301af97d3SDimitry Andric for (int i = 0; i < 2; i++) {
83401af97d3SDimitry Andric // Verify that the arguments are pointers.
8359f4dbff6SDimitry Andric const PointerType *PT = FPT->getParamType(i)->getAs<PointerType>();
83601af97d3SDimitry Andric if (!PT)
83701af97d3SDimitry Andric return false;
83801af97d3SDimitry Andric
83901af97d3SDimitry Andric // Verify that the argument is a 'char*'.
84001af97d3SDimitry Andric if (PT->getPointeeType().getUnqualifiedType() != BR.getContext().CharTy)
84101af97d3SDimitry Andric return false;
84201af97d3SDimitry Andric }
84301af97d3SDimitry Andric
84401af97d3SDimitry Andric return true;
84501af97d3SDimitry Andric }
84601af97d3SDimitry Andric
84701af97d3SDimitry Andric //===----------------------------------------------------------------------===//
848b1c73532SDimitry Andric // Check: Linear congruent random number generators should not be used,
849b1c73532SDimitry Andric // i.e. rand(), random().
850b1c73532SDimitry Andric //
851b1c73532SDimitry Andric // E. Bach, "Efficient prediction of Marsaglia-Zaman random number generators,"
852b1c73532SDimitry Andric // in IEEE Transactions on Information Theory, vol. 44, no. 3, pp. 1253-1257,
853b1c73532SDimitry Andric // May 1998, https://doi.org/10.1109/18.669305
854b1c73532SDimitry Andric //
8554c8b2481SRoman Divacky // CWE-338: Use of cryptographically weak prng
8564c8b2481SRoman Divacky //===----------------------------------------------------------------------===//
8574c8b2481SRoman Divacky
checkCall_rand(const CallExpr * CE,const FunctionDecl * FD)85801af97d3SDimitry Andric void WalkAST::checkCall_rand(const CallExpr *CE, const FunctionDecl *FD) {
859dbe13110SDimitry Andric if (!filter.check_rand || !CheckRand)
8604c8b2481SRoman Divacky return;
8614c8b2481SRoman Divacky
862bfef3995SDimitry Andric const FunctionProtoType *FTP = FD->getType()->getAs<FunctionProtoType>();
8634c8b2481SRoman Divacky if (!FTP)
8644c8b2481SRoman Divacky return;
8654c8b2481SRoman Divacky
8669f4dbff6SDimitry Andric if (FTP->getNumParams() == 1) {
8674c8b2481SRoman Divacky // Is the argument an 'unsigned short *'?
8684c8b2481SRoman Divacky // (Actually any integer type is allowed.)
8699f4dbff6SDimitry Andric const PointerType *PT = FTP->getParamType(0)->getAs<PointerType>();
8704c8b2481SRoman Divacky if (!PT)
8714c8b2481SRoman Divacky return;
8724c8b2481SRoman Divacky
8736a037251SDimitry Andric if (! PT->getPointeeType()->isIntegralOrUnscopedEnumerationType())
8744c8b2481SRoman Divacky return;
8759f4dbff6SDimitry Andric } else if (FTP->getNumParams() != 0)
8764c8b2481SRoman Divacky return;
8774c8b2481SRoman Divacky
8784c8b2481SRoman Divacky // Issue a warning.
879dbe13110SDimitry Andric SmallString<256> buf1;
88011d2b2d2SRoman Divacky llvm::raw_svector_ostream os1(buf1);
88136981b17SDimitry Andric os1 << '\'' << *FD << "' is a poor random number generator";
8824c8b2481SRoman Divacky
883dbe13110SDimitry Andric SmallString<256> buf2;
88411d2b2d2SRoman Divacky llvm::raw_svector_ostream os2(buf2);
88536981b17SDimitry Andric os2 << "Function '" << *FD
8864c8b2481SRoman Divacky << "' is obsolete because it implements a poor random number generator."
8874c8b2481SRoman Divacky << " Use 'arc4random' instead";
8884c8b2481SRoman Divacky
88936981b17SDimitry Andric PathDiagnosticLocation CELoc =
89036981b17SDimitry Andric PathDiagnosticLocation::createBegin(CE, BR.getSourceManager(), AC);
8919f4dbff6SDimitry Andric BR.EmitBasicReport(AC->getDecl(), filter.checkName_rand, os1.str(),
8929f4dbff6SDimitry Andric "Security", os2.str(), CELoc,
8939f4dbff6SDimitry Andric CE->getCallee()->getSourceRange());
8944c8b2481SRoman Divacky }
8954c8b2481SRoman Divacky
896b1c73532SDimitry Andric // See justification for rand().
checkCall_random(const CallExpr * CE,const FunctionDecl * FD)89701af97d3SDimitry Andric void WalkAST::checkCall_random(const CallExpr *CE, const FunctionDecl *FD) {
898dbe13110SDimitry Andric if (!CheckRand || !filter.check_rand)
8994c8b2481SRoman Divacky return;
9004c8b2481SRoman Divacky
901bfef3995SDimitry Andric const FunctionProtoType *FTP = FD->getType()->getAs<FunctionProtoType>();
9024c8b2481SRoman Divacky if (!FTP)
9034c8b2481SRoman Divacky return;
9044c8b2481SRoman Divacky
9054c8b2481SRoman Divacky // Verify that the function takes no argument.
9069f4dbff6SDimitry Andric if (FTP->getNumParams() != 0)
9074c8b2481SRoman Divacky return;
9084c8b2481SRoman Divacky
9094c8b2481SRoman Divacky // Issue a warning.
91036981b17SDimitry Andric PathDiagnosticLocation CELoc =
91136981b17SDimitry Andric PathDiagnosticLocation::createBegin(CE, BR.getSourceManager(), AC);
9129f4dbff6SDimitry Andric BR.EmitBasicReport(AC->getDecl(), filter.checkName_rand,
913dbe13110SDimitry Andric "'random' is not a secure random number generator",
9144c8b2481SRoman Divacky "Security",
9154c8b2481SRoman Divacky "The 'random' function produces a sequence of values that "
9164c8b2481SRoman Divacky "an adversary may be able to predict. Use 'arc4random' "
917bfef3995SDimitry Andric "instead", CELoc, CE->getCallee()->getSourceRange());
91836981b17SDimitry Andric }
91936981b17SDimitry Andric
92036981b17SDimitry Andric //===----------------------------------------------------------------------===//
92136981b17SDimitry Andric // Check: 'vfork' should not be used.
92236981b17SDimitry Andric // POS33-C: Do not use vfork().
92336981b17SDimitry Andric //===----------------------------------------------------------------------===//
92436981b17SDimitry Andric
checkCall_vfork(const CallExpr * CE,const FunctionDecl * FD)92536981b17SDimitry Andric void WalkAST::checkCall_vfork(const CallExpr *CE, const FunctionDecl *FD) {
926dbe13110SDimitry Andric if (!filter.check_vfork)
927dbe13110SDimitry Andric return;
928dbe13110SDimitry Andric
92936981b17SDimitry Andric // All calls to vfork() are insecure, issue a warning.
93036981b17SDimitry Andric PathDiagnosticLocation CELoc =
93136981b17SDimitry Andric PathDiagnosticLocation::createBegin(CE, BR.getSourceManager(), AC);
9329f4dbff6SDimitry Andric BR.EmitBasicReport(AC->getDecl(), filter.checkName_vfork,
933dbe13110SDimitry Andric "Potential insecure implementation-specific behavior in "
93436981b17SDimitry Andric "call 'vfork'",
93536981b17SDimitry Andric "Security",
93636981b17SDimitry Andric "Call to function 'vfork' is insecure as it can lead to "
93736981b17SDimitry Andric "denial of service situations in the parent process. "
93836981b17SDimitry Andric "Replace calls to vfork with calls to the safer "
93936981b17SDimitry Andric "'posix_spawn' function",
940bfef3995SDimitry Andric CELoc, CE->getCallee()->getSourceRange());
9414c8b2481SRoman Divacky }
9424c8b2481SRoman Divacky
9434c8b2481SRoman Divacky //===----------------------------------------------------------------------===//
944706b4fc4SDimitry Andric // Check: '-decodeValueOfObjCType:at:' should not be used.
945706b4fc4SDimitry Andric // It is deprecated in favor of '-decodeValueOfObjCType:at:size:' due to
946706b4fc4SDimitry Andric // likelihood of buffer overflows.
947706b4fc4SDimitry Andric //===----------------------------------------------------------------------===//
948706b4fc4SDimitry Andric
checkMsg_decodeValueOfObjCType(const ObjCMessageExpr * ME)949706b4fc4SDimitry Andric void WalkAST::checkMsg_decodeValueOfObjCType(const ObjCMessageExpr *ME) {
950706b4fc4SDimitry Andric if (!filter.check_decodeValueOfObjCType)
951706b4fc4SDimitry Andric return;
952706b4fc4SDimitry Andric
953706b4fc4SDimitry Andric // Check availability of the secure alternative:
954706b4fc4SDimitry Andric // iOS 11+, macOS 10.13+, tvOS 11+, and watchOS 4.0+
955706b4fc4SDimitry Andric // FIXME: We probably shouldn't register the check if it's not available.
956706b4fc4SDimitry Andric const TargetInfo &TI = AC->getASTContext().getTargetInfo();
957706b4fc4SDimitry Andric const llvm::Triple &T = TI.getTriple();
958706b4fc4SDimitry Andric const VersionTuple &VT = TI.getPlatformMinVersion();
959706b4fc4SDimitry Andric switch (T.getOS()) {
960706b4fc4SDimitry Andric case llvm::Triple::IOS:
961706b4fc4SDimitry Andric if (VT < VersionTuple(11, 0))
962706b4fc4SDimitry Andric return;
963706b4fc4SDimitry Andric break;
964706b4fc4SDimitry Andric case llvm::Triple::MacOSX:
965706b4fc4SDimitry Andric if (VT < VersionTuple(10, 13))
966706b4fc4SDimitry Andric return;
967706b4fc4SDimitry Andric break;
968706b4fc4SDimitry Andric case llvm::Triple::WatchOS:
969706b4fc4SDimitry Andric if (VT < VersionTuple(4, 0))
970706b4fc4SDimitry Andric return;
971706b4fc4SDimitry Andric break;
972706b4fc4SDimitry Andric case llvm::Triple::TvOS:
973706b4fc4SDimitry Andric if (VT < VersionTuple(11, 0))
974706b4fc4SDimitry Andric return;
975706b4fc4SDimitry Andric break;
9764df029ccSDimitry Andric case llvm::Triple::XROS:
9774df029ccSDimitry Andric break;
978706b4fc4SDimitry Andric default:
979706b4fc4SDimitry Andric return;
980706b4fc4SDimitry Andric }
981706b4fc4SDimitry Andric
982706b4fc4SDimitry Andric PathDiagnosticLocation MELoc =
983706b4fc4SDimitry Andric PathDiagnosticLocation::createBegin(ME, BR.getSourceManager(), AC);
984706b4fc4SDimitry Andric BR.EmitBasicReport(
985706b4fc4SDimitry Andric AC->getDecl(), filter.checkName_decodeValueOfObjCType,
986706b4fc4SDimitry Andric "Potential buffer overflow in '-decodeValueOfObjCType:at:'", "Security",
987706b4fc4SDimitry Andric "Deprecated method '-decodeValueOfObjCType:at:' is insecure "
988706b4fc4SDimitry Andric "as it can lead to potential buffer overflows. Use the safer "
989706b4fc4SDimitry Andric "'-decodeValueOfObjCType:at:size:' method.",
990706b4fc4SDimitry Andric MELoc, ME->getSourceRange());
991706b4fc4SDimitry Andric }
992706b4fc4SDimitry Andric
993706b4fc4SDimitry Andric //===----------------------------------------------------------------------===//
994b1c73532SDimitry Andric // Check: The caller should always verify that the privileges
995b1c73532SDimitry Andric // were dropped successfully.
996b1c73532SDimitry Andric //
997b1c73532SDimitry Andric // Some library functions, like setuid() and setgid(), should always be used
998b1c73532SDimitry Andric // with a check of the return value to verify that the function completed
999b1c73532SDimitry Andric // successfully. If the drop fails, the software will continue to run
1000b1c73532SDimitry Andric // with the raised privileges, which might provide additional access
1001b1c73532SDimitry Andric // to unprivileged users.
1002b1c73532SDimitry Andric //
1003b1c73532SDimitry Andric // (Note that this check predates __attribute__((warn_unused_result)).
1004b1c73532SDimitry Andric // Do we still need it now that we have a compiler warning for this?
1005b1c73532SDimitry Andric // Are these standard functions already annotated this way?)
10064c8b2481SRoman Divacky //===----------------------------------------------------------------------===//
10074c8b2481SRoman Divacky
checkUncheckedReturnValue(CallExpr * CE)100801af97d3SDimitry Andric void WalkAST::checkUncheckedReturnValue(CallExpr *CE) {
1009dbe13110SDimitry Andric if (!filter.check_UncheckedReturn)
1010dbe13110SDimitry Andric return;
1011dbe13110SDimitry Andric
10124c8b2481SRoman Divacky const FunctionDecl *FD = CE->getDirectCallee();
10134c8b2481SRoman Divacky if (!FD)
10144c8b2481SRoman Divacky return;
10154c8b2481SRoman Divacky
10169f4dbff6SDimitry Andric if (II_setid[0] == nullptr) {
10174c8b2481SRoman Divacky static const char * const identifiers[num_setids] = {
10184c8b2481SRoman Divacky "setuid", "setgid", "seteuid", "setegid",
10194c8b2481SRoman Divacky "setreuid", "setregid"
10204c8b2481SRoman Divacky };
10214c8b2481SRoman Divacky
10224c8b2481SRoman Divacky for (size_t i = 0; i < num_setids; i++)
10234c8b2481SRoman Divacky II_setid[i] = &BR.getContext().Idents.get(identifiers[i]);
10244c8b2481SRoman Divacky }
10254c8b2481SRoman Divacky
10264c8b2481SRoman Divacky const IdentifierInfo *id = FD->getIdentifier();
10274c8b2481SRoman Divacky size_t identifierid;
10284c8b2481SRoman Divacky
10294c8b2481SRoman Divacky for (identifierid = 0; identifierid < num_setids; identifierid++)
10304c8b2481SRoman Divacky if (id == II_setid[identifierid])
10314c8b2481SRoman Divacky break;
10324c8b2481SRoman Divacky
10334c8b2481SRoman Divacky if (identifierid >= num_setids)
10344c8b2481SRoman Divacky return;
10354c8b2481SRoman Divacky
1036bfef3995SDimitry Andric const FunctionProtoType *FTP = FD->getType()->getAs<FunctionProtoType>();
10374c8b2481SRoman Divacky if (!FTP)
10384c8b2481SRoman Divacky return;
10394c8b2481SRoman Divacky
10404c8b2481SRoman Divacky // Verify that the function takes one or two arguments (depending on
10414c8b2481SRoman Divacky // the function).
10429f4dbff6SDimitry Andric if (FTP->getNumParams() != (identifierid < 4 ? 1 : 2))
10434c8b2481SRoman Divacky return;
10444c8b2481SRoman Divacky
10454c8b2481SRoman Divacky // The arguments must be integers.
10469f4dbff6SDimitry Andric for (unsigned i = 0; i < FTP->getNumParams(); i++)
10479f4dbff6SDimitry Andric if (!FTP->getParamType(i)->isIntegralOrUnscopedEnumerationType())
10484c8b2481SRoman Divacky return;
10494c8b2481SRoman Divacky
10504c8b2481SRoman Divacky // Issue a warning.
1051dbe13110SDimitry Andric SmallString<256> buf1;
105211d2b2d2SRoman Divacky llvm::raw_svector_ostream os1(buf1);
105336981b17SDimitry Andric os1 << "Return value is not checked in call to '" << *FD << '\'';
10544c8b2481SRoman Divacky
1055dbe13110SDimitry Andric SmallString<256> buf2;
105611d2b2d2SRoman Divacky llvm::raw_svector_ostream os2(buf2);
105736981b17SDimitry Andric os2 << "The return value from the call to '" << *FD
105836981b17SDimitry Andric << "' is not checked. If an error occurs in '" << *FD
10594c8b2481SRoman Divacky << "', the following code may execute with unexpected privileges";
10604c8b2481SRoman Divacky
106136981b17SDimitry Andric PathDiagnosticLocation CELoc =
106236981b17SDimitry Andric PathDiagnosticLocation::createBegin(CE, BR.getSourceManager(), AC);
10639f4dbff6SDimitry Andric BR.EmitBasicReport(AC->getDecl(), filter.checkName_UncheckedReturn, os1.str(),
10649f4dbff6SDimitry Andric "Security", os2.str(), CELoc,
10659f4dbff6SDimitry Andric CE->getCallee()->getSourceRange());
10664c8b2481SRoman Divacky }
10674c8b2481SRoman Divacky
10684c8b2481SRoman Divacky //===----------------------------------------------------------------------===//
1069bca07a45SDimitry Andric // SecuritySyntaxChecker
10704c8b2481SRoman Divacky //===----------------------------------------------------------------------===//
10714c8b2481SRoman Divacky
1072bca07a45SDimitry Andric namespace {
107301af97d3SDimitry Andric class SecuritySyntaxChecker : public Checker<check::ASTCodeBody> {
1074bca07a45SDimitry Andric public:
1075dbe13110SDimitry Andric ChecksFilter filter;
1076dbe13110SDimitry Andric
checkASTCodeBody(const Decl * D,AnalysisManager & mgr,BugReporter & BR) const1077bca07a45SDimitry Andric void checkASTCodeBody(const Decl *D, AnalysisManager& mgr,
1078bca07a45SDimitry Andric BugReporter &BR) const {
1079dbe13110SDimitry Andric WalkAST walker(BR, mgr.getAnalysisDeclContext(D), filter);
10804c8b2481SRoman Divacky walker.Visit(D->getBody());
10814c8b2481SRoman Divacky }
1082bca07a45SDimitry Andric };
1083bca07a45SDimitry Andric }
1084bca07a45SDimitry Andric
registerSecuritySyntaxChecker(CheckerManager & mgr)108522989816SDimitry Andric void ento::registerSecuritySyntaxChecker(CheckerManager &mgr) {
108622989816SDimitry Andric mgr.registerChecker<SecuritySyntaxChecker>();
108722989816SDimitry Andric }
108822989816SDimitry Andric
shouldRegisterSecuritySyntaxChecker(const CheckerManager & mgr)1089cfca06d7SDimitry Andric bool ento::shouldRegisterSecuritySyntaxChecker(const CheckerManager &mgr) {
109022989816SDimitry Andric return true;
109122989816SDimitry Andric }
109222989816SDimitry Andric
1093dbe13110SDimitry Andric #define REGISTER_CHECKER(name) \
1094dbe13110SDimitry Andric void ento::register##name(CheckerManager &mgr) { \
109522989816SDimitry Andric SecuritySyntaxChecker *checker = mgr.getChecker<SecuritySyntaxChecker>(); \
10969f4dbff6SDimitry Andric checker->filter.check_##name = true; \
1097519fc96cSDimitry Andric checker->filter.checkName_##name = mgr.getCurrentCheckerName(); \
109822989816SDimitry Andric } \
109922989816SDimitry Andric \
1100cfca06d7SDimitry Andric bool ento::shouldRegister##name(const CheckerManager &mgr) { return true; }
1101dbe13110SDimitry Andric
110248675466SDimitry Andric REGISTER_CHECKER(bcmp)
110348675466SDimitry Andric REGISTER_CHECKER(bcopy)
110448675466SDimitry Andric REGISTER_CHECKER(bzero)
1105dbe13110SDimitry Andric REGISTER_CHECKER(gets)
1106dbe13110SDimitry Andric REGISTER_CHECKER(getpw)
1107dbe13110SDimitry Andric REGISTER_CHECKER(mkstemp)
1108dbe13110SDimitry Andric REGISTER_CHECKER(mktemp)
1109dbe13110SDimitry Andric REGISTER_CHECKER(strcpy)
1110dbe13110SDimitry Andric REGISTER_CHECKER(rand)
1111dbe13110SDimitry Andric REGISTER_CHECKER(vfork)
1112dbe13110SDimitry Andric REGISTER_CHECKER(FloatLoopCounter)
1113dbe13110SDimitry Andric REGISTER_CHECKER(UncheckedReturn)
111422989816SDimitry Andric REGISTER_CHECKER(DeprecatedOrUnsafeBufferHandling)
1115706b4fc4SDimitry Andric REGISTER_CHECKER(decodeValueOfObjCType)
1116