1d99bd55aSTed Kremenek //==- CheckSecuritySyntaxOnly.cpp - Basic security checks --------*- C++ -*-==//
2d99bd55aSTed Kremenek //
32946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
42946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information.
52946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6d99bd55aSTed Kremenek //
7d99bd55aSTed Kremenek //===----------------------------------------------------------------------===//
8d99bd55aSTed Kremenek //
9d99bd55aSTed Kremenek //  This file defines a set of flow-insensitive security checks.
10d99bd55aSTed Kremenek //
11d99bd55aSTed Kremenek //===----------------------------------------------------------------------===//
12d99bd55aSTed Kremenek 
1376a21502SKristof Umann #include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h"
14c29bed39SAnna Zaks #include "clang/AST/StmtVisitor.h"
1550657f6bSGeorge Karpenkov #include "clang/Analysis/AnalysisDeclContext.h"
16c29bed39SAnna Zaks #include "clang/Basic/TargetInfo.h"
17f8cbac4bSTed Kremenek #include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h"
183a02247dSChandler Carruth #include "clang/StaticAnalyzer/Core/Checker.h"
19c29bed39SAnna Zaks #include "clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h"
204903802fSBenjamin Kramer #include "llvm/ADT/SmallString.h"
21fca2e961SLenny Maiorani #include "llvm/ADT/StringSwitch.h"
22c29bed39SAnna Zaks #include "llvm/Support/raw_ostream.h"
23d99bd55aSTed Kremenek 
24d99bd55aSTed Kremenek using namespace clang;
25d99bd55aSTed Kremenek using namespace ento;
26d99bd55aSTed Kremenek 
isArc4RandomAvailable(const ASTContext & Ctx)27d99bd55aSTed Kremenek static bool isArc4RandomAvailable(const ASTContext &Ctx) {
28e8bbc121SDouglas Gregor   const llvm::Triple &T = Ctx.getTargetInfo().getTriple();
29d99bd55aSTed Kremenek   return T.getVendor() == llvm::Triple::Apple ||
30e5bdc851SEd Schouten          T.getOS() == llvm::Triple::CloudABI ||
315a409d0eSMichal Gorny          T.isOSFreeBSD() ||
325a409d0eSMichal Gorny          T.isOSNetBSD() ||
335a409d0eSMichal Gorny          T.isOSOpenBSD() ||
345a409d0eSMichal Gorny          T.isOSDragonFly();
35d99bd55aSTed Kremenek }
36d99bd55aSTed Kremenek 
37d99bd55aSTed Kremenek namespace {
38c54dc951STed Kremenek struct ChecksFilter {
39*5114db93SVince Bridgers   bool check_bcmp = false;
40*5114db93SVince Bridgers   bool check_bcopy = false;
41*5114db93SVince Bridgers   bool check_bzero = false;
42*5114db93SVince Bridgers   bool check_gets = false;
43*5114db93SVince Bridgers   bool check_getpw = false;
44*5114db93SVince Bridgers   bool check_mktemp = false;
45*5114db93SVince Bridgers   bool check_mkstemp = false;
46*5114db93SVince Bridgers   bool check_strcpy = false;
47*5114db93SVince Bridgers   bool check_DeprecatedOrUnsafeBufferHandling = false;
48*5114db93SVince Bridgers   bool check_rand = false;
49*5114db93SVince Bridgers   bool check_vfork = false;
50*5114db93SVince Bridgers   bool check_FloatLoopCounter = false;
51*5114db93SVince Bridgers   bool check_UncheckedReturn = false;
52*5114db93SVince Bridgers   bool check_decodeValueOfObjCType = false;
534aca9b1cSAlexander Kornienko 
5472649423SKristof Umann   CheckerNameRef checkName_bcmp;
5572649423SKristof Umann   CheckerNameRef checkName_bcopy;
5672649423SKristof Umann   CheckerNameRef checkName_bzero;
5772649423SKristof Umann   CheckerNameRef checkName_gets;
5872649423SKristof Umann   CheckerNameRef checkName_getpw;
5972649423SKristof Umann   CheckerNameRef checkName_mktemp;
6072649423SKristof Umann   CheckerNameRef checkName_mkstemp;
6172649423SKristof Umann   CheckerNameRef checkName_strcpy;
6272649423SKristof Umann   CheckerNameRef checkName_DeprecatedOrUnsafeBufferHandling;
6372649423SKristof Umann   CheckerNameRef checkName_rand;
6472649423SKristof Umann   CheckerNameRef checkName_vfork;
6572649423SKristof Umann   CheckerNameRef checkName_FloatLoopCounter;
6672649423SKristof Umann   CheckerNameRef checkName_UncheckedReturn;
67b2840050SArtem Dergachev   CheckerNameRef checkName_decodeValueOfObjCType;
68c54dc951STed Kremenek };
69c54dc951STed Kremenek 
70d99bd55aSTed Kremenek class WalkAST : public StmtVisitor<WalkAST> {
71d99bd55aSTed Kremenek   BugReporter &BR;
7281ce1c8aSTed Kremenek   AnalysisDeclContext* AC;
73d99bd55aSTed Kremenek   enum { num_setids = 6 };
74d99bd55aSTed Kremenek   IdentifierInfo *II_setid[num_setids];
75d99bd55aSTed Kremenek 
76d99bd55aSTed Kremenek   const bool CheckRand;
77c54dc951STed Kremenek   const ChecksFilter &filter;
78d99bd55aSTed Kremenek 
79d99bd55aSTed Kremenek public:
WalkAST(BugReporter & br,AnalysisDeclContext * ac,const ChecksFilter & f)80c54dc951STed Kremenek   WalkAST(BugReporter &br, AnalysisDeclContext* ac,
81c54dc951STed Kremenek           const ChecksFilter &f)
82c29bed39SAnna Zaks   : BR(br), AC(ac), II_setid(),
83c54dc951STed Kremenek     CheckRand(isArc4RandomAvailable(BR.getContext())),
84c54dc951STed Kremenek     filter(f) {}
85d99bd55aSTed Kremenek 
86d99bd55aSTed Kremenek   // Statement visitor methods.
87d99bd55aSTed Kremenek   void VisitCallExpr(CallExpr *CE);
88b2840050SArtem Dergachev   void VisitObjCMessageExpr(ObjCMessageExpr *CE);
89d99bd55aSTed Kremenek   void VisitForStmt(ForStmt *S);
90d99bd55aSTed Kremenek   void VisitCompoundStmt (CompoundStmt *S);
VisitStmt(Stmt * S)91d99bd55aSTed Kremenek   void VisitStmt(Stmt *S) { VisitChildren(S); }
92d99bd55aSTed Kremenek 
93d99bd55aSTed Kremenek   void VisitChildren(Stmt *S);
94d99bd55aSTed Kremenek 
95d99bd55aSTed Kremenek   // Helpers.
96de909e49SLenny Maiorani   bool checkCall_strCommon(const CallExpr *CE, const FunctionDecl *FD);
97d99bd55aSTed Kremenek 
982a3ca840SPierre Gousseau   typedef void (WalkAST::*FnCheck)(const CallExpr *, const FunctionDecl *);
99b2840050SArtem Dergachev   typedef void (WalkAST::*MsgCheck)(const ObjCMessageExpr *);
100fca2e961SLenny Maiorani 
101d99bd55aSTed Kremenek   // Checker-specific methods.
102de909e49SLenny Maiorani   void checkLoopConditionForFloat(const ForStmt *FS);
1038419cf30SArtem Dergachev   void checkCall_bcmp(const CallExpr *CE, const FunctionDecl *FD);
1048419cf30SArtem Dergachev   void checkCall_bcopy(const CallExpr *CE, const FunctionDecl *FD);
1058419cf30SArtem Dergachev   void checkCall_bzero(const CallExpr *CE, const FunctionDecl *FD);
106de909e49SLenny Maiorani   void checkCall_gets(const CallExpr *CE, const FunctionDecl *FD);
107de909e49SLenny Maiorani   void checkCall_getpw(const CallExpr *CE, const FunctionDecl *FD);
108de909e49SLenny Maiorani   void checkCall_mktemp(const CallExpr *CE, const FunctionDecl *FD);
10989eaf8d5STed Kremenek   void checkCall_mkstemp(const CallExpr *CE, const FunctionDecl *FD);
110de909e49SLenny Maiorani   void checkCall_strcpy(const CallExpr *CE, const FunctionDecl *FD);
111de909e49SLenny Maiorani   void checkCall_strcat(const CallExpr *CE, const FunctionDecl *FD);
1128d239996SKristof Umann   void checkDeprecatedOrUnsafeBufferHandling(const CallExpr *CE,
1138d239996SKristof Umann                                              const FunctionDecl *FD);
114de909e49SLenny Maiorani   void checkCall_rand(const CallExpr *CE, const FunctionDecl *FD);
115de909e49SLenny Maiorani   void checkCall_random(const CallExpr *CE, const FunctionDecl *FD);
116fedf5dfcSAnna Zaks   void checkCall_vfork(const CallExpr *CE, const FunctionDecl *FD);
117b2840050SArtem Dergachev   void checkMsg_decodeValueOfObjCType(const ObjCMessageExpr *ME);
118de909e49SLenny Maiorani   void checkUncheckedReturnValue(CallExpr *CE);
119d99bd55aSTed Kremenek };
120d99bd55aSTed Kremenek } // end anonymous namespace
121d99bd55aSTed Kremenek 
122d99bd55aSTed Kremenek //===----------------------------------------------------------------------===//
123d99bd55aSTed Kremenek // AST walking.
124d99bd55aSTed Kremenek //===----------------------------------------------------------------------===//
125d99bd55aSTed Kremenek 
VisitChildren(Stmt * S)126d99bd55aSTed Kremenek void WalkAST::VisitChildren(Stmt *S) {
127973431b2SBenjamin Kramer   for (Stmt *Child : S->children())
128973431b2SBenjamin Kramer     if (Child)
129973431b2SBenjamin Kramer       Visit(Child);
130d99bd55aSTed Kremenek }
131d99bd55aSTed Kremenek 
VisitCallExpr(CallExpr * CE)132d99bd55aSTed Kremenek void WalkAST::VisitCallExpr(CallExpr *CE) {
133fca2e961SLenny Maiorani   // Get the callee.
134fca2e961SLenny Maiorani   const FunctionDecl *FD = CE->getDirectCallee();
135fca2e961SLenny Maiorani 
136fca2e961SLenny Maiorani   if (!FD)
137fca2e961SLenny Maiorani     return;
138fca2e961SLenny Maiorani 
139fca2e961SLenny Maiorani   // Get the name of the callee. If it's a builtin, strip off the prefix.
140fca2e961SLenny Maiorani   IdentifierInfo *II = FD->getIdentifier();
141fca2e961SLenny Maiorani   if (!II)   // if no identifier, not a simple C function
142fca2e961SLenny Maiorani     return;
1430e62c1ccSChris Lattner   StringRef Name = II->getName();
144fca2e961SLenny Maiorani   if (Name.startswith("__builtin_"))
145fca2e961SLenny Maiorani     Name = Name.substr(10);
146fca2e961SLenny Maiorani 
147fca2e961SLenny Maiorani   // Set the evaluation function by switching on the callee name.
148fca2e961SLenny Maiorani   FnCheck evalFunction = llvm::StringSwitch<FnCheck>(Name)
1498419cf30SArtem Dergachev     .Case("bcmp", &WalkAST::checkCall_bcmp)
1508419cf30SArtem Dergachev     .Case("bcopy", &WalkAST::checkCall_bcopy)
1518419cf30SArtem Dergachev     .Case("bzero", &WalkAST::checkCall_bzero)
152de909e49SLenny Maiorani     .Case("gets", &WalkAST::checkCall_gets)
153de909e49SLenny Maiorani     .Case("getpw", &WalkAST::checkCall_getpw)
154de909e49SLenny Maiorani     .Case("mktemp", &WalkAST::checkCall_mktemp)
15589eaf8d5STed Kremenek     .Case("mkstemp", &WalkAST::checkCall_mkstemp)
15689eaf8d5STed Kremenek     .Case("mkdtemp", &WalkAST::checkCall_mkstemp)
15789eaf8d5STed Kremenek     .Case("mkstemps", &WalkAST::checkCall_mkstemp)
158de909e49SLenny Maiorani     .Cases("strcpy", "__strcpy_chk", &WalkAST::checkCall_strcpy)
159de909e49SLenny Maiorani     .Cases("strcat", "__strcat_chk", &WalkAST::checkCall_strcat)
1608d239996SKristof Umann     .Cases("sprintf", "vsprintf", "scanf", "wscanf", "fscanf", "fwscanf",
1618d239996SKristof Umann            "vscanf", "vwscanf", "vfscanf", "vfwscanf",
1628d239996SKristof Umann            &WalkAST::checkDeprecatedOrUnsafeBufferHandling)
1638d239996SKristof Umann     .Cases("sscanf", "swscanf", "vsscanf", "vswscanf", "swprintf",
1648d239996SKristof Umann            "snprintf", "vswprintf", "vsnprintf", "memcpy", "memmove",
1658d239996SKristof Umann            &WalkAST::checkDeprecatedOrUnsafeBufferHandling)
1668d239996SKristof Umann     .Cases("strncpy", "strncat", "memset",
1678d239996SKristof Umann            &WalkAST::checkDeprecatedOrUnsafeBufferHandling)
168de909e49SLenny Maiorani     .Case("drand48", &WalkAST::checkCall_rand)
169de909e49SLenny Maiorani     .Case("erand48", &WalkAST::checkCall_rand)
170de909e49SLenny Maiorani     .Case("jrand48", &WalkAST::checkCall_rand)
171de909e49SLenny Maiorani     .Case("lrand48", &WalkAST::checkCall_rand)
172de909e49SLenny Maiorani     .Case("mrand48", &WalkAST::checkCall_rand)
173de909e49SLenny Maiorani     .Case("nrand48", &WalkAST::checkCall_rand)
174de909e49SLenny Maiorani     .Case("lcong48", &WalkAST::checkCall_rand)
175de909e49SLenny Maiorani     .Case("rand", &WalkAST::checkCall_rand)
176de909e49SLenny Maiorani     .Case("rand_r", &WalkAST::checkCall_rand)
177de909e49SLenny Maiorani     .Case("random", &WalkAST::checkCall_random)
178fedf5dfcSAnna Zaks     .Case("vfork", &WalkAST::checkCall_vfork)
1790dbb783cSCraig Topper     .Default(nullptr);
180fca2e961SLenny Maiorani 
181fca2e961SLenny Maiorani   // If the callee isn't defined, it is not of security concern.
182fca2e961SLenny Maiorani   // Check and evaluate the call.
183fca2e961SLenny Maiorani   if (evalFunction)
184fca2e961SLenny Maiorani     (this->*evalFunction)(CE, FD);
185d99bd55aSTed Kremenek 
186d99bd55aSTed Kremenek   // Recurse and check children.
187d99bd55aSTed Kremenek   VisitChildren(CE);
188d99bd55aSTed Kremenek }
189d99bd55aSTed Kremenek 
VisitObjCMessageExpr(ObjCMessageExpr * ME)190b2840050SArtem Dergachev void WalkAST::VisitObjCMessageExpr(ObjCMessageExpr *ME) {
191b2840050SArtem Dergachev   MsgCheck evalFunction =
192b2840050SArtem Dergachev       llvm::StringSwitch<MsgCheck>(ME->getSelector().getAsString())
193b2840050SArtem Dergachev           .Case("decodeValueOfObjCType:at:",
194b2840050SArtem Dergachev                 &WalkAST::checkMsg_decodeValueOfObjCType)
195b2840050SArtem Dergachev           .Default(nullptr);
196b2840050SArtem Dergachev 
197b2840050SArtem Dergachev   if (evalFunction)
198b2840050SArtem Dergachev     (this->*evalFunction)(ME);
199b2840050SArtem Dergachev 
200b2840050SArtem Dergachev   // Recurse and check children.
201b2840050SArtem Dergachev   VisitChildren(ME);
202b2840050SArtem Dergachev }
203b2840050SArtem Dergachev 
VisitCompoundStmt(CompoundStmt * S)204d99bd55aSTed Kremenek void WalkAST::VisitCompoundStmt(CompoundStmt *S) {
205973431b2SBenjamin Kramer   for (Stmt *Child : S->children())
206973431b2SBenjamin Kramer     if (Child) {
207973431b2SBenjamin Kramer       if (CallExpr *CE = dyn_cast<CallExpr>(Child))
208de909e49SLenny Maiorani         checkUncheckedReturnValue(CE);
209973431b2SBenjamin Kramer       Visit(Child);
210d99bd55aSTed Kremenek     }
211d99bd55aSTed Kremenek }
212d99bd55aSTed Kremenek 
VisitForStmt(ForStmt * FS)213d99bd55aSTed Kremenek void WalkAST::VisitForStmt(ForStmt *FS) {
214de909e49SLenny Maiorani   checkLoopConditionForFloat(FS);
215d99bd55aSTed Kremenek 
216d99bd55aSTed Kremenek   // Recurse and check children.
217d99bd55aSTed Kremenek   VisitChildren(FS);
218d99bd55aSTed Kremenek }
219d99bd55aSTed Kremenek 
220d99bd55aSTed Kremenek //===----------------------------------------------------------------------===//
221b23ccecbSRaphael Isemann // Check: floating point variable used as loop counter.
222d99bd55aSTed Kremenek // Originally: <rdar://problem/6336718>
223d99bd55aSTed Kremenek // Implements: CERT security coding advisory FLP-30.
224d99bd55aSTed Kremenek //===----------------------------------------------------------------------===//
225d99bd55aSTed Kremenek 
226630f7dafSArtem Dergachev // Returns either 'x' or 'y', depending on which one of them is incremented
227630f7dafSArtem Dergachev // in 'expr', or nullptr if none of them is incremented.
228d99bd55aSTed Kremenek static const DeclRefExpr*
getIncrementedVar(const Expr * expr,const VarDecl * x,const VarDecl * y)229de909e49SLenny Maiorani getIncrementedVar(const Expr *expr, const VarDecl *x, const VarDecl *y) {
230d99bd55aSTed Kremenek   expr = expr->IgnoreParenCasts();
231d99bd55aSTed Kremenek 
232d99bd55aSTed Kremenek   if (const BinaryOperator *B = dyn_cast<BinaryOperator>(expr)) {
233d99bd55aSTed Kremenek     if (!(B->isAssignmentOp() || B->isCompoundAssignmentOp() ||
234d99bd55aSTed Kremenek           B->getOpcode() == BO_Comma))
2350dbb783cSCraig Topper       return nullptr;
236d99bd55aSTed Kremenek 
237de909e49SLenny Maiorani     if (const DeclRefExpr *lhs = getIncrementedVar(B->getLHS(), x, y))
238d99bd55aSTed Kremenek       return lhs;
239d99bd55aSTed Kremenek 
240de909e49SLenny Maiorani     if (const DeclRefExpr *rhs = getIncrementedVar(B->getRHS(), x, y))
241d99bd55aSTed Kremenek       return rhs;
242d99bd55aSTed Kremenek 
2430dbb783cSCraig Topper     return nullptr;
244d99bd55aSTed Kremenek   }
245d99bd55aSTed Kremenek 
246d99bd55aSTed Kremenek   if (const DeclRefExpr *DR = dyn_cast<DeclRefExpr>(expr)) {
247d99bd55aSTed Kremenek     const NamedDecl *ND = DR->getDecl();
2480dbb783cSCraig Topper     return ND == x || ND == y ? DR : nullptr;
249d99bd55aSTed Kremenek   }
250d99bd55aSTed Kremenek 
251d99bd55aSTed Kremenek   if (const UnaryOperator *U = dyn_cast<UnaryOperator>(expr))
252d99bd55aSTed Kremenek     return U->isIncrementDecrementOp()
2530dbb783cSCraig Topper       ? getIncrementedVar(U->getSubExpr(), x, y) : nullptr;
254d99bd55aSTed Kremenek 
2550dbb783cSCraig Topper   return nullptr;
256d99bd55aSTed Kremenek }
257d99bd55aSTed Kremenek 
258d99bd55aSTed Kremenek /// CheckLoopConditionForFloat - This check looks for 'for' statements that
259d99bd55aSTed Kremenek ///  use a floating point variable as a loop counter.
260d99bd55aSTed Kremenek ///  CERT: FLP30-C, FLP30-CPP.
261d99bd55aSTed Kremenek ///
checkLoopConditionForFloat(const ForStmt * FS)262de909e49SLenny Maiorani void WalkAST::checkLoopConditionForFloat(const ForStmt *FS) {
263c54dc951STed Kremenek   if (!filter.check_FloatLoopCounter)
264c54dc951STed Kremenek     return;
265c54dc951STed Kremenek 
266d99bd55aSTed Kremenek   // Does the loop have a condition?
267d99bd55aSTed Kremenek   const Expr *condition = FS->getCond();
268d99bd55aSTed Kremenek 
269d99bd55aSTed Kremenek   if (!condition)
270d99bd55aSTed Kremenek     return;
271d99bd55aSTed Kremenek 
272d99bd55aSTed Kremenek   // Does the loop have an increment?
273d99bd55aSTed Kremenek   const Expr *increment = FS->getInc();
274d99bd55aSTed Kremenek 
275d99bd55aSTed Kremenek   if (!increment)
276d99bd55aSTed Kremenek     return;
277d99bd55aSTed Kremenek 
278d99bd55aSTed Kremenek   // Strip away '()' and casts.
279d99bd55aSTed Kremenek   condition = condition->IgnoreParenCasts();
280d99bd55aSTed Kremenek   increment = increment->IgnoreParenCasts();
281d99bd55aSTed Kremenek 
282d99bd55aSTed Kremenek   // Is the loop condition a comparison?
283d99bd55aSTed Kremenek   const BinaryOperator *B = dyn_cast<BinaryOperator>(condition);
284d99bd55aSTed Kremenek 
285d99bd55aSTed Kremenek   if (!B)
286d99bd55aSTed Kremenek     return;
287d99bd55aSTed Kremenek 
288d99bd55aSTed Kremenek   // Is this a comparison?
289d99bd55aSTed Kremenek   if (!(B->isRelationalOp() || B->isEqualityOp()))
290d99bd55aSTed Kremenek     return;
291d99bd55aSTed Kremenek 
292d99bd55aSTed Kremenek   // Are we comparing variables?
293d99bd55aSTed Kremenek   const DeclRefExpr *drLHS =
294d99bd55aSTed Kremenek     dyn_cast<DeclRefExpr>(B->getLHS()->IgnoreParenLValueCasts());
295d99bd55aSTed Kremenek   const DeclRefExpr *drRHS =
296d99bd55aSTed Kremenek     dyn_cast<DeclRefExpr>(B->getRHS()->IgnoreParenLValueCasts());
297d99bd55aSTed Kremenek 
298d99bd55aSTed Kremenek   // Does at least one of the variables have a floating point type?
2990dbb783cSCraig Topper   drLHS = drLHS && drLHS->getType()->isRealFloatingType() ? drLHS : nullptr;
3000dbb783cSCraig Topper   drRHS = drRHS && drRHS->getType()->isRealFloatingType() ? drRHS : nullptr;
301d99bd55aSTed Kremenek 
302d99bd55aSTed Kremenek   if (!drLHS && !drRHS)
303d99bd55aSTed Kremenek     return;
304d99bd55aSTed Kremenek 
3050dbb783cSCraig Topper   const VarDecl *vdLHS = drLHS ? dyn_cast<VarDecl>(drLHS->getDecl()) : nullptr;
3060dbb783cSCraig Topper   const VarDecl *vdRHS = drRHS ? dyn_cast<VarDecl>(drRHS->getDecl()) : nullptr;
307d99bd55aSTed Kremenek 
308d99bd55aSTed Kremenek   if (!vdLHS && !vdRHS)
309d99bd55aSTed Kremenek     return;
310d99bd55aSTed Kremenek 
311d99bd55aSTed Kremenek   // Does either variable appear in increment?
312de909e49SLenny Maiorani   const DeclRefExpr *drInc = getIncrementedVar(increment, vdLHS, vdRHS);
313d99bd55aSTed Kremenek   if (!drInc)
314d99bd55aSTed Kremenek     return;
315d99bd55aSTed Kremenek 
316630f7dafSArtem Dergachev   const VarDecl *vdInc = cast<VarDecl>(drInc->getDecl());
317630f7dafSArtem Dergachev   assert(vdInc && (vdInc == vdLHS || vdInc == vdRHS));
318630f7dafSArtem Dergachev 
319d99bd55aSTed Kremenek   // Emit the error.  First figure out which DeclRefExpr in the condition
320d99bd55aSTed Kremenek   // referenced the compared variable.
321630f7dafSArtem Dergachev   const DeclRefExpr *drCond = vdLHS == vdInc ? drLHS : drRHS;
322d99bd55aSTed Kremenek 
3230e62c1ccSChris Lattner   SmallVector<SourceRange, 2> ranges;
3242c1dd271SDylan Noblesmith   SmallString<256> sbuf;
325d99bd55aSTed Kremenek   llvm::raw_svector_ostream os(sbuf);
326d99bd55aSTed Kremenek 
327d99bd55aSTed Kremenek   os << "Variable '" << drCond->getDecl()->getName()
328cfb81690SNathan James      << "' with floating point type '" << drCond->getType()
329d99bd55aSTed Kremenek      << "' should not be used as a loop counter";
330d99bd55aSTed Kremenek 
331d99bd55aSTed Kremenek   ranges.push_back(drCond->getSourceRange());
332d99bd55aSTed Kremenek   ranges.push_back(drInc->getSourceRange());
333d99bd55aSTed Kremenek 
334d99bd55aSTed Kremenek   const char *bugType = "Floating point variable used as loop counter";
335c29bed39SAnna Zaks 
336c29bed39SAnna Zaks   PathDiagnosticLocation FSLoc =
337c29bed39SAnna Zaks     PathDiagnosticLocation::createBegin(FS, BR.getSourceManager(), AC);
3384aca9b1cSAlexander Kornienko   BR.EmitBasicReport(AC->getDecl(), filter.checkName_FloatLoopCounter,
3395a10f08bSTed Kremenek                      bugType, "Security", os.str(),
34042b4248fSJordan Rose                      FSLoc, ranges);
341d99bd55aSTed Kremenek }
342d99bd55aSTed Kremenek 
343d99bd55aSTed Kremenek //===----------------------------------------------------------------------===//
3448419cf30SArtem Dergachev // Check: Any use of bcmp.
3458419cf30SArtem Dergachev // CWE-477: Use of Obsolete Functions
3468419cf30SArtem Dergachev // bcmp was deprecated in POSIX.1-2008
3478419cf30SArtem Dergachev //===----------------------------------------------------------------------===//
3488419cf30SArtem Dergachev 
checkCall_bcmp(const CallExpr * CE,const FunctionDecl * FD)3498419cf30SArtem Dergachev void WalkAST::checkCall_bcmp(const CallExpr *CE, const FunctionDecl *FD) {
3508419cf30SArtem Dergachev   if (!filter.check_bcmp)
3518419cf30SArtem Dergachev     return;
3528419cf30SArtem Dergachev 
3538419cf30SArtem Dergachev   const FunctionProtoType *FPT = FD->getType()->getAs<FunctionProtoType>();
3548419cf30SArtem Dergachev   if (!FPT)
3558419cf30SArtem Dergachev     return;
3568419cf30SArtem Dergachev 
3578419cf30SArtem Dergachev   // Verify that the function takes three arguments.
3588419cf30SArtem Dergachev   if (FPT->getNumParams() != 3)
3598419cf30SArtem Dergachev     return;
3608419cf30SArtem Dergachev 
3618419cf30SArtem Dergachev   for (int i = 0; i < 2; i++) {
3628419cf30SArtem Dergachev     // Verify the first and second argument type is void*.
3638419cf30SArtem Dergachev     const PointerType *PT = FPT->getParamType(i)->getAs<PointerType>();
3648419cf30SArtem Dergachev     if (!PT)
3658419cf30SArtem Dergachev       return;
3668419cf30SArtem Dergachev 
3678419cf30SArtem Dergachev     if (PT->getPointeeType().getUnqualifiedType() != BR.getContext().VoidTy)
3688419cf30SArtem Dergachev       return;
3698419cf30SArtem Dergachev   }
3708419cf30SArtem Dergachev 
3718419cf30SArtem Dergachev   // Verify the third argument type is integer.
3728419cf30SArtem Dergachev   if (!FPT->getParamType(2)->isIntegralOrUnscopedEnumerationType())
3738419cf30SArtem Dergachev     return;
3748419cf30SArtem Dergachev 
3758419cf30SArtem Dergachev   // Issue a warning.
3768419cf30SArtem Dergachev   PathDiagnosticLocation CELoc =
3778419cf30SArtem Dergachev     PathDiagnosticLocation::createBegin(CE, BR.getSourceManager(), AC);
3788419cf30SArtem Dergachev   BR.EmitBasicReport(AC->getDecl(), filter.checkName_bcmp,
3798419cf30SArtem Dergachev                      "Use of deprecated function in call to 'bcmp()'",
3808419cf30SArtem Dergachev                      "Security",
3818419cf30SArtem Dergachev                      "The bcmp() function is obsoleted by memcmp().",
3828419cf30SArtem Dergachev                      CELoc, CE->getCallee()->getSourceRange());
3838419cf30SArtem Dergachev }
3848419cf30SArtem Dergachev 
3858419cf30SArtem Dergachev //===----------------------------------------------------------------------===//
3868419cf30SArtem Dergachev // Check: Any use of bcopy.
3878419cf30SArtem Dergachev // CWE-477: Use of Obsolete Functions
3888419cf30SArtem Dergachev // bcopy was deprecated in POSIX.1-2008
3898419cf30SArtem Dergachev //===----------------------------------------------------------------------===//
3908419cf30SArtem Dergachev 
checkCall_bcopy(const CallExpr * CE,const FunctionDecl * FD)3918419cf30SArtem Dergachev void WalkAST::checkCall_bcopy(const CallExpr *CE, const FunctionDecl *FD) {
3928419cf30SArtem Dergachev   if (!filter.check_bcopy)
3938419cf30SArtem Dergachev     return;
3948419cf30SArtem Dergachev 
3958419cf30SArtem Dergachev   const FunctionProtoType *FPT = FD->getType()->getAs<FunctionProtoType>();
3968419cf30SArtem Dergachev   if (!FPT)
3978419cf30SArtem Dergachev     return;
3988419cf30SArtem Dergachev 
3998419cf30SArtem Dergachev   // Verify that the function takes three arguments.
4008419cf30SArtem Dergachev   if (FPT->getNumParams() != 3)
4018419cf30SArtem Dergachev     return;
4028419cf30SArtem Dergachev 
4038419cf30SArtem Dergachev   for (int i = 0; i < 2; i++) {
4048419cf30SArtem Dergachev     // Verify the first and second argument type is void*.
4058419cf30SArtem Dergachev     const PointerType *PT = FPT->getParamType(i)->getAs<PointerType>();
4068419cf30SArtem Dergachev     if (!PT)
4078419cf30SArtem Dergachev       return;
4088419cf30SArtem Dergachev 
4098419cf30SArtem Dergachev     if (PT->getPointeeType().getUnqualifiedType() != BR.getContext().VoidTy)
4108419cf30SArtem Dergachev       return;
4118419cf30SArtem Dergachev   }
4128419cf30SArtem Dergachev 
4138419cf30SArtem Dergachev   // Verify the third argument type is integer.
4148419cf30SArtem Dergachev   if (!FPT->getParamType(2)->isIntegralOrUnscopedEnumerationType())
4158419cf30SArtem Dergachev     return;
4168419cf30SArtem Dergachev 
4178419cf30SArtem Dergachev   // Issue a warning.
4188419cf30SArtem Dergachev   PathDiagnosticLocation CELoc =
4198419cf30SArtem Dergachev     PathDiagnosticLocation::createBegin(CE, BR.getSourceManager(), AC);
4208419cf30SArtem Dergachev   BR.EmitBasicReport(AC->getDecl(), filter.checkName_bcopy,
4218419cf30SArtem Dergachev                      "Use of deprecated function in call to 'bcopy()'",
4228419cf30SArtem Dergachev                      "Security",
4238419cf30SArtem Dergachev                      "The bcopy() function is obsoleted by memcpy() "
4248419cf30SArtem Dergachev                      "or memmove().",
4258419cf30SArtem Dergachev                      CELoc, CE->getCallee()->getSourceRange());
4268419cf30SArtem Dergachev }
4278419cf30SArtem Dergachev 
4288419cf30SArtem Dergachev //===----------------------------------------------------------------------===//
4298419cf30SArtem Dergachev // Check: Any use of bzero.
4308419cf30SArtem Dergachev // CWE-477: Use of Obsolete Functions
4318419cf30SArtem Dergachev // bzero was deprecated in POSIX.1-2008
4328419cf30SArtem Dergachev //===----------------------------------------------------------------------===//
4338419cf30SArtem Dergachev 
checkCall_bzero(const CallExpr * CE,const FunctionDecl * FD)4348419cf30SArtem Dergachev void WalkAST::checkCall_bzero(const CallExpr *CE, const FunctionDecl *FD) {
4358419cf30SArtem Dergachev   if (!filter.check_bzero)
4368419cf30SArtem Dergachev     return;
4378419cf30SArtem Dergachev 
4388419cf30SArtem Dergachev   const FunctionProtoType *FPT = FD->getType()->getAs<FunctionProtoType>();
4398419cf30SArtem Dergachev   if (!FPT)
4408419cf30SArtem Dergachev     return;
4418419cf30SArtem Dergachev 
4428419cf30SArtem Dergachev   // Verify that the function takes two arguments.
4438419cf30SArtem Dergachev   if (FPT->getNumParams() != 2)
4448419cf30SArtem Dergachev     return;
4458419cf30SArtem Dergachev 
4468419cf30SArtem Dergachev   // Verify the first argument type is void*.
4478419cf30SArtem Dergachev   const PointerType *PT = FPT->getParamType(0)->getAs<PointerType>();
4488419cf30SArtem Dergachev   if (!PT)
4498419cf30SArtem Dergachev     return;
4508419cf30SArtem Dergachev 
4518419cf30SArtem Dergachev   if (PT->getPointeeType().getUnqualifiedType() != BR.getContext().VoidTy)
4528419cf30SArtem Dergachev     return;
4538419cf30SArtem Dergachev 
4548419cf30SArtem Dergachev   // Verify the second argument type is integer.
4558419cf30SArtem Dergachev   if (!FPT->getParamType(1)->isIntegralOrUnscopedEnumerationType())
4568419cf30SArtem Dergachev     return;
4578419cf30SArtem Dergachev 
4588419cf30SArtem Dergachev   // Issue a warning.
4598419cf30SArtem Dergachev   PathDiagnosticLocation CELoc =
4608419cf30SArtem Dergachev     PathDiagnosticLocation::createBegin(CE, BR.getSourceManager(), AC);
4618419cf30SArtem Dergachev   BR.EmitBasicReport(AC->getDecl(), filter.checkName_bzero,
4628419cf30SArtem Dergachev                      "Use of deprecated function in call to 'bzero()'",
4638419cf30SArtem Dergachev                      "Security",
4648419cf30SArtem Dergachev                      "The bzero() function is obsoleted by memset().",
4658419cf30SArtem Dergachev                      CELoc, CE->getCallee()->getSourceRange());
4668419cf30SArtem Dergachev }
4678419cf30SArtem Dergachev 
4688419cf30SArtem Dergachev 
4698419cf30SArtem Dergachev //===----------------------------------------------------------------------===//
470d99bd55aSTed Kremenek // Check: Any use of 'gets' is insecure.
471d99bd55aSTed Kremenek // Originally: <rdar://problem/6335715>
472d99bd55aSTed Kremenek // Implements (part of): 300-BSI (buildsecurityin.us-cert.gov)
473d99bd55aSTed Kremenek // CWE-242: Use of Inherently Dangerous Function
474d99bd55aSTed Kremenek //===----------------------------------------------------------------------===//
475d99bd55aSTed Kremenek 
checkCall_gets(const CallExpr * CE,const FunctionDecl * FD)476de909e49SLenny Maiorani void WalkAST::checkCall_gets(const CallExpr *CE, const FunctionDecl *FD) {
477c54dc951STed Kremenek   if (!filter.check_gets)
478c54dc951STed Kremenek     return;
479c54dc951STed Kremenek 
48057d1f1c8SEli Friedman   const FunctionProtoType *FPT = FD->getType()->getAs<FunctionProtoType>();
481d99bd55aSTed Kremenek   if (!FPT)
482d99bd55aSTed Kremenek     return;
483d99bd55aSTed Kremenek 
484d99bd55aSTed Kremenek   // Verify that the function takes a single argument.
4859cacbabdSAlp Toker   if (FPT->getNumParams() != 1)
486d99bd55aSTed Kremenek     return;
487d99bd55aSTed Kremenek 
488d99bd55aSTed Kremenek   // Is the argument a 'char*'?
4899cacbabdSAlp Toker   const PointerType *PT = FPT->getParamType(0)->getAs<PointerType>();
490d99bd55aSTed Kremenek   if (!PT)
491d99bd55aSTed Kremenek     return;
492d99bd55aSTed Kremenek 
493d99bd55aSTed Kremenek   if (PT->getPointeeType().getUnqualifiedType() != BR.getContext().CharTy)
494d99bd55aSTed Kremenek     return;
495d99bd55aSTed Kremenek 
496d99bd55aSTed Kremenek   // Issue a warning.
497c29bed39SAnna Zaks   PathDiagnosticLocation CELoc =
498c29bed39SAnna Zaks     PathDiagnosticLocation::createBegin(CE, BR.getSourceManager(), AC);
4994aca9b1cSAlexander Kornienko   BR.EmitBasicReport(AC->getDecl(), filter.checkName_gets,
5005a10f08bSTed Kremenek                      "Potential buffer overflow in call to 'gets'",
501d99bd55aSTed Kremenek                      "Security",
502d99bd55aSTed Kremenek                      "Call to function 'gets' is extremely insecure as it can "
503d99bd55aSTed Kremenek                      "always result in a buffer overflow",
50442b4248fSJordan Rose                      CELoc, CE->getCallee()->getSourceRange());
505d99bd55aSTed Kremenek }
506d99bd55aSTed Kremenek 
507d99bd55aSTed Kremenek //===----------------------------------------------------------------------===//
508d99bd55aSTed Kremenek // Check: Any use of 'getpwd' is insecure.
509d99bd55aSTed Kremenek // CWE-477: Use of Obsolete Functions
510d99bd55aSTed Kremenek //===----------------------------------------------------------------------===//
511d99bd55aSTed Kremenek 
checkCall_getpw(const CallExpr * CE,const FunctionDecl * FD)512de909e49SLenny Maiorani void WalkAST::checkCall_getpw(const CallExpr *CE, const FunctionDecl *FD) {
513c54dc951STed Kremenek   if (!filter.check_getpw)
514c54dc951STed Kremenek     return;
515c54dc951STed Kremenek 
51657d1f1c8SEli Friedman   const FunctionProtoType *FPT = FD->getType()->getAs<FunctionProtoType>();
517d99bd55aSTed Kremenek   if (!FPT)
518d99bd55aSTed Kremenek     return;
519d99bd55aSTed Kremenek 
520d99bd55aSTed Kremenek   // Verify that the function takes two arguments.
5219cacbabdSAlp Toker   if (FPT->getNumParams() != 2)
522d99bd55aSTed Kremenek     return;
523d99bd55aSTed Kremenek 
524d99bd55aSTed Kremenek   // Verify the first argument type is integer.
5259cacbabdSAlp Toker   if (!FPT->getParamType(0)->isIntegralOrUnscopedEnumerationType())
526d99bd55aSTed Kremenek     return;
527d99bd55aSTed Kremenek 
528d99bd55aSTed Kremenek   // Verify the second argument type is char*.
5299cacbabdSAlp Toker   const PointerType *PT = FPT->getParamType(1)->getAs<PointerType>();
530d99bd55aSTed Kremenek   if (!PT)
531d99bd55aSTed Kremenek     return;
532d99bd55aSTed Kremenek 
533d99bd55aSTed Kremenek   if (PT->getPointeeType().getUnqualifiedType() != BR.getContext().CharTy)
534d99bd55aSTed Kremenek     return;
535d99bd55aSTed Kremenek 
536d99bd55aSTed Kremenek   // Issue a warning.
537c29bed39SAnna Zaks   PathDiagnosticLocation CELoc =
538c29bed39SAnna Zaks     PathDiagnosticLocation::createBegin(CE, BR.getSourceManager(), AC);
5394aca9b1cSAlexander Kornienko   BR.EmitBasicReport(AC->getDecl(), filter.checkName_getpw,
5405a10f08bSTed Kremenek                      "Potential buffer overflow in call to 'getpw'",
541d99bd55aSTed Kremenek                      "Security",
542d99bd55aSTed Kremenek                      "The getpw() function is dangerous as it may overflow the "
543d99bd55aSTed Kremenek                      "provided buffer. It is obsoleted by getpwuid().",
54442b4248fSJordan Rose                      CELoc, CE->getCallee()->getSourceRange());
545d99bd55aSTed Kremenek }
546d99bd55aSTed Kremenek 
547d99bd55aSTed Kremenek //===----------------------------------------------------------------------===//
548d99bd55aSTed Kremenek // Check: Any use of 'mktemp' is insecure.  It is obsoleted by mkstemp().
549d99bd55aSTed Kremenek // CWE-377: Insecure Temporary File
550d99bd55aSTed Kremenek //===----------------------------------------------------------------------===//
551d99bd55aSTed Kremenek 
checkCall_mktemp(const CallExpr * CE,const FunctionDecl * FD)552de909e49SLenny Maiorani void WalkAST::checkCall_mktemp(const CallExpr *CE, const FunctionDecl *FD) {
553afddb9c8STed Kremenek   if (!filter.check_mktemp) {
554afddb9c8STed Kremenek     // Fall back to the security check of looking for enough 'X's in the
555afddb9c8STed Kremenek     // format string, since that is a less severe warning.
556afddb9c8STed Kremenek     checkCall_mkstemp(CE, FD);
557afddb9c8STed Kremenek     return;
558afddb9c8STed Kremenek   }
559afddb9c8STed Kremenek 
56057d1f1c8SEli Friedman   const FunctionProtoType *FPT = FD->getType()->getAs<FunctionProtoType>();
561d99bd55aSTed Kremenek   if(!FPT)
562d99bd55aSTed Kremenek     return;
563d99bd55aSTed Kremenek 
56470568c2bSLenny Maiorani   // Verify that the function takes a single argument.
5659cacbabdSAlp Toker   if (FPT->getNumParams() != 1)
566d99bd55aSTed Kremenek     return;
567d99bd55aSTed Kremenek 
568d99bd55aSTed Kremenek   // Verify that the argument is Pointer Type.
5699cacbabdSAlp Toker   const PointerType *PT = FPT->getParamType(0)->getAs<PointerType>();
570d99bd55aSTed Kremenek   if (!PT)
571d99bd55aSTed Kremenek     return;
572d99bd55aSTed Kremenek 
573d99bd55aSTed Kremenek   // Verify that the argument is a 'char*'.
574d99bd55aSTed Kremenek   if (PT->getPointeeType().getUnqualifiedType() != BR.getContext().CharTy)
575d99bd55aSTed Kremenek     return;
576d99bd55aSTed Kremenek 
577c3f36af8SAlp Toker   // Issue a warning.
578c29bed39SAnna Zaks   PathDiagnosticLocation CELoc =
579c29bed39SAnna Zaks     PathDiagnosticLocation::createBegin(CE, BR.getSourceManager(), AC);
5804aca9b1cSAlexander Kornienko   BR.EmitBasicReport(AC->getDecl(), filter.checkName_mktemp,
5815a10f08bSTed Kremenek                      "Potential insecure temporary file in call 'mktemp'",
582d99bd55aSTed Kremenek                      "Security",
583d99bd55aSTed Kremenek                      "Call to function 'mktemp' is insecure as it always "
5845a10f08bSTed Kremenek                      "creates or uses insecure temporary file.  Use 'mkstemp' "
5855a10f08bSTed Kremenek                      "instead",
58642b4248fSJordan Rose                      CELoc, CE->getCallee()->getSourceRange());
587d99bd55aSTed Kremenek }
588d99bd55aSTed Kremenek 
58989eaf8d5STed Kremenek //===----------------------------------------------------------------------===//
59089eaf8d5STed Kremenek // Check: Use of 'mkstemp', 'mktemp', 'mkdtemp' should contain at least 6 X's.
59189eaf8d5STed Kremenek //===----------------------------------------------------------------------===//
59289eaf8d5STed Kremenek 
checkCall_mkstemp(const CallExpr * CE,const FunctionDecl * FD)59389eaf8d5STed Kremenek void WalkAST::checkCall_mkstemp(const CallExpr *CE, const FunctionDecl *FD) {
59489eaf8d5STed Kremenek   if (!filter.check_mkstemp)
59589eaf8d5STed Kremenek     return;
59689eaf8d5STed Kremenek 
59789eaf8d5STed Kremenek   StringRef Name = FD->getIdentifier()->getName();
59889eaf8d5STed Kremenek   std::pair<signed, signed> ArgSuffix =
59989eaf8d5STed Kremenek     llvm::StringSwitch<std::pair<signed, signed> >(Name)
60089eaf8d5STed Kremenek       .Case("mktemp", std::make_pair(0,-1))
60189eaf8d5STed Kremenek       .Case("mkstemp", std::make_pair(0,-1))
60289eaf8d5STed Kremenek       .Case("mkdtemp", std::make_pair(0,-1))
60389eaf8d5STed Kremenek       .Case("mkstemps", std::make_pair(0,1))
60489eaf8d5STed Kremenek       .Default(std::make_pair(-1, -1));
60589eaf8d5STed Kremenek 
60689eaf8d5STed Kremenek   assert(ArgSuffix.first >= 0 && "Unsupported function");
60789eaf8d5STed Kremenek 
60889eaf8d5STed Kremenek   // Check if the number of arguments is consistent with out expectations.
60989eaf8d5STed Kremenek   unsigned numArgs = CE->getNumArgs();
61089eaf8d5STed Kremenek   if ((signed) numArgs <= ArgSuffix.first)
61189eaf8d5STed Kremenek     return;
61289eaf8d5STed Kremenek 
61389eaf8d5STed Kremenek   const StringLiteral *strArg =
61489eaf8d5STed Kremenek     dyn_cast<StringLiteral>(CE->getArg((unsigned)ArgSuffix.first)
61589eaf8d5STed Kremenek                               ->IgnoreParenImpCasts());
61689eaf8d5STed Kremenek 
61789eaf8d5STed Kremenek   // Currently we only handle string literals.  It is possible to do better,
61889eaf8d5STed Kremenek   // either by looking at references to const variables, or by doing real
61989eaf8d5STed Kremenek   // flow analysis.
62089eaf8d5STed Kremenek   if (!strArg || strArg->getCharByteWidth() != 1)
62189eaf8d5STed Kremenek     return;
62289eaf8d5STed Kremenek 
62389eaf8d5STed Kremenek   // Count the number of X's, taking into account a possible cutoff suffix.
62489eaf8d5STed Kremenek   StringRef str = strArg->getString();
62589eaf8d5STed Kremenek   unsigned numX = 0;
62689eaf8d5STed Kremenek   unsigned n = str.size();
62789eaf8d5STed Kremenek 
62889eaf8d5STed Kremenek   // Take into account the suffix.
62989eaf8d5STed Kremenek   unsigned suffix = 0;
63089eaf8d5STed Kremenek   if (ArgSuffix.second >= 0) {
63189eaf8d5STed Kremenek     const Expr *suffixEx = CE->getArg((unsigned)ArgSuffix.second);
632407659abSFangrui Song     Expr::EvalResult EVResult;
633407659abSFangrui Song     if (!suffixEx->EvaluateAsInt(EVResult, BR.getContext()))
63489eaf8d5STed Kremenek       return;
635407659abSFangrui Song     llvm::APSInt Result = EVResult.Val.getInt();
63689eaf8d5STed Kremenek     // FIXME: Issue a warning.
63789eaf8d5STed Kremenek     if (Result.isNegative())
63889eaf8d5STed Kremenek       return;
63989eaf8d5STed Kremenek     suffix = (unsigned) Result.getZExtValue();
64089eaf8d5STed Kremenek     n = (n > suffix) ? n - suffix : 0;
64189eaf8d5STed Kremenek   }
64289eaf8d5STed Kremenek 
64389eaf8d5STed Kremenek   for (unsigned i = 0; i < n; ++i)
64489eaf8d5STed Kremenek     if (str[i] == 'X') ++numX;
64589eaf8d5STed Kremenek 
64689eaf8d5STed Kremenek   if (numX >= 6)
64789eaf8d5STed Kremenek     return;
64889eaf8d5STed Kremenek 
64989eaf8d5STed Kremenek   // Issue a warning.
65089eaf8d5STed Kremenek   PathDiagnosticLocation CELoc =
65189eaf8d5STed Kremenek     PathDiagnosticLocation::createBegin(CE, BR.getSourceManager(), AC);
6522c1dd271SDylan Noblesmith   SmallString<512> buf;
65389eaf8d5STed Kremenek   llvm::raw_svector_ostream out(buf);
65489eaf8d5STed Kremenek   out << "Call to '" << Name << "' should have at least 6 'X's in the"
65589eaf8d5STed Kremenek     " format string to be secure (" << numX << " 'X'";
65689eaf8d5STed Kremenek   if (numX != 1)
65789eaf8d5STed Kremenek     out << 's';
65889eaf8d5STed Kremenek   out << " seen";
65989eaf8d5STed Kremenek   if (suffix) {
66089eaf8d5STed Kremenek     out << ", " << suffix << " character";
66189eaf8d5STed Kremenek     if (suffix > 1)
66289eaf8d5STed Kremenek       out << 's';
66389eaf8d5STed Kremenek     out << " used as a suffix";
66489eaf8d5STed Kremenek   }
66589eaf8d5STed Kremenek   out << ')';
6664aca9b1cSAlexander Kornienko   BR.EmitBasicReport(AC->getDecl(), filter.checkName_mkstemp,
6675a10f08bSTed Kremenek                      "Insecure temporary file creation", "Security",
66842b4248fSJordan Rose                      out.str(), CELoc, strArg->getSourceRange());
66989eaf8d5STed Kremenek }
67089eaf8d5STed Kremenek 
671d99bd55aSTed Kremenek //===----------------------------------------------------------------------===//
6726ffe738fSLenny Maiorani // Check: Any use of 'strcpy' is insecure.
6736ffe738fSLenny Maiorani //
6746ffe738fSLenny Maiorani // CWE-119: Improper Restriction of Operations within
6756ffe738fSLenny Maiorani // the Bounds of a Memory Buffer
6766ffe738fSLenny Maiorani //===----------------------------------------------------------------------===//
6778d239996SKristof Umann 
checkCall_strcpy(const CallExpr * CE,const FunctionDecl * FD)678de909e49SLenny Maiorani void WalkAST::checkCall_strcpy(const CallExpr *CE, const FunctionDecl *FD) {
679c54dc951STed Kremenek   if (!filter.check_strcpy)
680c54dc951STed Kremenek     return;
681c54dc951STed Kremenek 
682de909e49SLenny Maiorani   if (!checkCall_strCommon(CE, FD))
6836ffe738fSLenny Maiorani     return;
6846ffe738fSLenny Maiorani 
6851ebd1c4fSArtem Dergachev   const auto *Target = CE->getArg(0)->IgnoreImpCasts(),
6861ebd1c4fSArtem Dergachev              *Source = CE->getArg(1)->IgnoreImpCasts();
687e2a8eec4SGeorge Karpenkov 
688e2a8eec4SGeorge Karpenkov   if (const auto *Array = dyn_cast<ConstantArrayType>(Target->getType())) {
6891ebd1c4fSArtem Dergachev     uint64_t ArraySize = BR.getContext().getTypeSize(Array) / 8;
6901ebd1c4fSArtem Dergachev     if (const auto *String = dyn_cast<StringLiteral>(Source)) {
6911ebd1c4fSArtem Dergachev       if (ArraySize >= String->getLength() + 1)
6921ebd1c4fSArtem Dergachev         return;
6931ebd1c4fSArtem Dergachev     }
6941ebd1c4fSArtem Dergachev   }
6951ebd1c4fSArtem Dergachev 
696de909e49SLenny Maiorani   // Issue a warning.
697c29bed39SAnna Zaks   PathDiagnosticLocation CELoc =
698c29bed39SAnna Zaks     PathDiagnosticLocation::createBegin(CE, BR.getSourceManager(), AC);
6994aca9b1cSAlexander Kornienko   BR.EmitBasicReport(AC->getDecl(), filter.checkName_strcpy,
7005a10f08bSTed Kremenek                      "Potential insecure memory buffer bounds restriction in "
7016ffe738fSLenny Maiorani                      "call 'strcpy'",
7026ffe738fSLenny Maiorani                      "Security",
7036ffe738fSLenny Maiorani                      "Call to function 'strcpy' is insecure as it does not "
7046ffe738fSLenny Maiorani                      "provide bounding of the memory buffer. Replace "
7056ffe738fSLenny Maiorani                      "unbounded copy functions with analogous functions that "
706ee5e8ae8SAnna Zaks                      "support length arguments such as 'strlcpy'. CWE-119.",
70742b4248fSJordan Rose                      CELoc, CE->getCallee()->getSourceRange());
7086ffe738fSLenny Maiorani }
7096ffe738fSLenny Maiorani 
7106ffe738fSLenny Maiorani //===----------------------------------------------------------------------===//
711de909e49SLenny Maiorani // Check: Any use of 'strcat' is insecure.
712de909e49SLenny Maiorani //
713de909e49SLenny Maiorani // CWE-119: Improper Restriction of Operations within
714de909e49SLenny Maiorani // the Bounds of a Memory Buffer
715de909e49SLenny Maiorani //===----------------------------------------------------------------------===//
7168d239996SKristof Umann 
checkCall_strcat(const CallExpr * CE,const FunctionDecl * FD)717de909e49SLenny Maiorani void WalkAST::checkCall_strcat(const CallExpr *CE, const FunctionDecl *FD) {
718c54dc951STed Kremenek   if (!filter.check_strcpy)
719c54dc951STed Kremenek     return;
720c54dc951STed Kremenek 
721de909e49SLenny Maiorani   if (!checkCall_strCommon(CE, FD))
722de909e49SLenny Maiorani     return;
723de909e49SLenny Maiorani 
724de909e49SLenny Maiorani   // Issue a warning.
725c29bed39SAnna Zaks   PathDiagnosticLocation CELoc =
726c29bed39SAnna Zaks     PathDiagnosticLocation::createBegin(CE, BR.getSourceManager(), AC);
7274aca9b1cSAlexander Kornienko   BR.EmitBasicReport(AC->getDecl(), filter.checkName_strcpy,
7285a10f08bSTed Kremenek                      "Potential insecure memory buffer bounds restriction in "
729de909e49SLenny Maiorani                      "call 'strcat'",
730de909e49SLenny Maiorani                      "Security",
731de909e49SLenny Maiorani                      "Call to function 'strcat' is insecure as it does not "
732de909e49SLenny Maiorani                      "provide bounding of the memory buffer. Replace "
733de909e49SLenny Maiorani                      "unbounded copy functions with analogous functions that "
734ee5e8ae8SAnna Zaks                      "support length arguments such as 'strlcat'. CWE-119.",
73542b4248fSJordan Rose                      CELoc, CE->getCallee()->getSourceRange());
736de909e49SLenny Maiorani }
737de909e49SLenny Maiorani 
738de909e49SLenny Maiorani //===----------------------------------------------------------------------===//
7398d239996SKristof Umann // Check: Any use of 'sprintf', 'vsprintf', 'scanf', 'wscanf', 'fscanf',
7408d239996SKristof Umann //        'fwscanf', 'vscanf', 'vwscanf', 'vfscanf', 'vfwscanf', 'sscanf',
7418d239996SKristof Umann //        'swscanf', 'vsscanf', 'vswscanf', 'swprintf', 'snprintf', 'vswprintf',
7428d239996SKristof Umann //        'vsnprintf', 'memcpy', 'memmove', 'strncpy', 'strncat', 'memset'
7438d239996SKristof Umann //        is deprecated since C11.
7448d239996SKristof Umann //
7458d239996SKristof Umann //        Use of 'sprintf', 'vsprintf', 'scanf', 'wscanf','fscanf',
7468d239996SKristof Umann //        'fwscanf', 'vscanf', 'vwscanf', 'vfscanf', 'vfwscanf', 'sscanf',
7478d239996SKristof Umann //        'swscanf', 'vsscanf', 'vswscanf' without buffer limitations
7488d239996SKristof Umann //        is insecure.
7498d239996SKristof Umann //
7508d239996SKristof Umann // CWE-119: Improper Restriction of Operations within
7518d239996SKristof Umann // the Bounds of a Memory Buffer
7528d239996SKristof Umann //===----------------------------------------------------------------------===//
7538d239996SKristof Umann 
checkDeprecatedOrUnsafeBufferHandling(const CallExpr * CE,const FunctionDecl * FD)7548d239996SKristof Umann void WalkAST::checkDeprecatedOrUnsafeBufferHandling(const CallExpr *CE,
7558d239996SKristof Umann                                                     const FunctionDecl *FD) {
7568d239996SKristof Umann   if (!filter.check_DeprecatedOrUnsafeBufferHandling)
7578d239996SKristof Umann     return;
7588d239996SKristof Umann 
7598d239996SKristof Umann   if (!BR.getContext().getLangOpts().C11)
7608d239996SKristof Umann     return;
7618d239996SKristof Umann 
7628d239996SKristof Umann   // Issue a warning. ArgIndex == -1: Deprecated but not unsafe (has size
7638d239996SKristof Umann   // restrictions).
7648d239996SKristof Umann   enum { DEPR_ONLY = -1, UNKNOWN_CALL = -2 };
76525e592e5SKristof Umann 
7668d239996SKristof Umann   StringRef Name = FD->getIdentifier()->getName();
76725e592e5SKristof Umann   if (Name.startswith("__builtin_"))
76825e592e5SKristof Umann     Name = Name.substr(10);
76925e592e5SKristof Umann 
7708d239996SKristof Umann   int ArgIndex =
7718d239996SKristof Umann       llvm::StringSwitch<int>(Name)
7728d239996SKristof Umann           .Cases("scanf", "wscanf", "vscanf", "vwscanf", 0)
7738d239996SKristof Umann           .Cases("sprintf", "vsprintf", "fscanf", "fwscanf", "vfscanf",
7748d239996SKristof Umann                  "vfwscanf", "sscanf", "swscanf", "vsscanf", "vswscanf", 1)
7758d239996SKristof Umann           .Cases("swprintf", "snprintf", "vswprintf", "vsnprintf", "memcpy",
7768d239996SKristof Umann                  "memmove", "memset", "strncpy", "strncat", DEPR_ONLY)
7778d239996SKristof Umann           .Default(UNKNOWN_CALL);
7788d239996SKristof Umann 
7798d239996SKristof Umann   assert(ArgIndex != UNKNOWN_CALL && "Unsupported function");
7808d239996SKristof Umann   bool BoundsProvided = ArgIndex == DEPR_ONLY;
7818d239996SKristof Umann 
7828d239996SKristof Umann   if (!BoundsProvided) {
7838d239996SKristof Umann     // Currently we only handle (not wide) string literals. It is possible to do
7848d239996SKristof Umann     // better, either by looking at references to const variables, or by doing
7858d239996SKristof Umann     // real flow analysis.
7868d239996SKristof Umann     auto FormatString =
7878d239996SKristof Umann         dyn_cast<StringLiteral>(CE->getArg(ArgIndex)->IgnoreParenImpCasts());
7880abb5d29SKazu Hirata     if (FormatString && !FormatString->getString().contains("%s") &&
7890abb5d29SKazu Hirata         !FormatString->getString().contains("%["))
7908d239996SKristof Umann       BoundsProvided = true;
7918d239996SKristof Umann   }
7928d239996SKristof Umann 
7938d239996SKristof Umann   SmallString<128> Buf1;
7948d239996SKristof Umann   SmallString<512> Buf2;
7958d239996SKristof Umann   llvm::raw_svector_ostream Out1(Buf1);
7968d239996SKristof Umann   llvm::raw_svector_ostream Out2(Buf2);
7978d239996SKristof Umann 
7988d239996SKristof Umann   Out1 << "Potential insecure memory buffer bounds restriction in call '"
7998d239996SKristof Umann        << Name << "'";
8008d239996SKristof Umann   Out2 << "Call to function '" << Name
8018d239996SKristof Umann        << "' is insecure as it does not provide ";
8028d239996SKristof Umann 
8038d239996SKristof Umann   if (!BoundsProvided) {
8048d239996SKristof Umann     Out2 << "bounding of the memory buffer or ";
8058d239996SKristof Umann   }
8068d239996SKristof Umann 
8078d239996SKristof Umann   Out2 << "security checks introduced "
8088d239996SKristof Umann           "in the C11 standard. Replace with analogous functions that "
8098d239996SKristof Umann           "support length arguments or provides boundary checks such as '"
8108d239996SKristof Umann        << Name << "_s' in case of C11";
8118d239996SKristof Umann 
8128d239996SKristof Umann   PathDiagnosticLocation CELoc =
8138d239996SKristof Umann       PathDiagnosticLocation::createBegin(CE, BR.getSourceManager(), AC);
8148d239996SKristof Umann   BR.EmitBasicReport(AC->getDecl(),
8158d239996SKristof Umann                      filter.checkName_DeprecatedOrUnsafeBufferHandling,
8168d239996SKristof Umann                      Out1.str(), "Security", Out2.str(), CELoc,
8178d239996SKristof Umann                      CE->getCallee()->getSourceRange());
8188d239996SKristof Umann }
8198d239996SKristof Umann 
8208d239996SKristof Umann //===----------------------------------------------------------------------===//
821de909e49SLenny Maiorani // Common check for str* functions with no bounds parameters.
822de909e49SLenny Maiorani //===----------------------------------------------------------------------===//
8238d239996SKristof Umann 
checkCall_strCommon(const CallExpr * CE,const FunctionDecl * FD)824de909e49SLenny Maiorani bool WalkAST::checkCall_strCommon(const CallExpr *CE, const FunctionDecl *FD) {
82557d1f1c8SEli Friedman   const FunctionProtoType *FPT = FD->getType()->getAs<FunctionProtoType>();
826de909e49SLenny Maiorani   if (!FPT)
827de909e49SLenny Maiorani     return false;
828de909e49SLenny Maiorani 
829de909e49SLenny Maiorani   // Verify the function takes two arguments, three in the _chk version.
8309cacbabdSAlp Toker   int numArgs = FPT->getNumParams();
831de909e49SLenny Maiorani   if (numArgs != 2 && numArgs != 3)
832de909e49SLenny Maiorani     return false;
833de909e49SLenny Maiorani 
834de909e49SLenny Maiorani   // Verify the type for both arguments.
835de909e49SLenny Maiorani   for (int i = 0; i < 2; i++) {
836de909e49SLenny Maiorani     // Verify that the arguments are pointers.
8379cacbabdSAlp Toker     const PointerType *PT = FPT->getParamType(i)->getAs<PointerType>();
838de909e49SLenny Maiorani     if (!PT)
839de909e49SLenny Maiorani       return false;
840de909e49SLenny Maiorani 
841de909e49SLenny Maiorani     // Verify that the argument is a 'char*'.
842de909e49SLenny Maiorani     if (PT->getPointeeType().getUnqualifiedType() != BR.getContext().CharTy)
843de909e49SLenny Maiorani       return false;
844de909e49SLenny Maiorani   }
845de909e49SLenny Maiorani 
846de909e49SLenny Maiorani   return true;
847de909e49SLenny Maiorani }
848de909e49SLenny Maiorani 
849de909e49SLenny Maiorani //===----------------------------------------------------------------------===//
850d99bd55aSTed Kremenek // Check: Linear congruent random number generators should not be used
851d99bd55aSTed Kremenek // Originally: <rdar://problem/63371000>
852d99bd55aSTed Kremenek // CWE-338: Use of cryptographically weak prng
853d99bd55aSTed Kremenek //===----------------------------------------------------------------------===//
854d99bd55aSTed Kremenek 
checkCall_rand(const CallExpr * CE,const FunctionDecl * FD)855de909e49SLenny Maiorani void WalkAST::checkCall_rand(const CallExpr *CE, const FunctionDecl *FD) {
856c54dc951STed Kremenek   if (!filter.check_rand || !CheckRand)
857d99bd55aSTed Kremenek     return;
858d99bd55aSTed Kremenek 
85957d1f1c8SEli Friedman   const FunctionProtoType *FTP = FD->getType()->getAs<FunctionProtoType>();
860d99bd55aSTed Kremenek   if (!FTP)
861d99bd55aSTed Kremenek     return;
862d99bd55aSTed Kremenek 
8639cacbabdSAlp Toker   if (FTP->getNumParams() == 1) {
864d99bd55aSTed Kremenek     // Is the argument an 'unsigned short *'?
865d99bd55aSTed Kremenek     // (Actually any integer type is allowed.)
8669cacbabdSAlp Toker     const PointerType *PT = FTP->getParamType(0)->getAs<PointerType>();
867d99bd55aSTed Kremenek     if (!PT)
868d99bd55aSTed Kremenek       return;
869d99bd55aSTed Kremenek 
87061e221f6SJordan Rose     if (! PT->getPointeeType()->isIntegralOrUnscopedEnumerationType())
871d99bd55aSTed Kremenek       return;
8729cacbabdSAlp Toker   } else if (FTP->getNumParams() != 0)
873d99bd55aSTed Kremenek     return;
874d99bd55aSTed Kremenek 
875d99bd55aSTed Kremenek   // Issue a warning.
8762c1dd271SDylan Noblesmith   SmallString<256> buf1;
877d99bd55aSTed Kremenek   llvm::raw_svector_ostream os1(buf1);
878b89514a9SBenjamin Kramer   os1 << '\'' << *FD << "' is a poor random number generator";
879d99bd55aSTed Kremenek 
8802c1dd271SDylan Noblesmith   SmallString<256> buf2;
881d99bd55aSTed Kremenek   llvm::raw_svector_ostream os2(buf2);
882b89514a9SBenjamin Kramer   os2 << "Function '" << *FD
883d99bd55aSTed Kremenek       << "' is obsolete because it implements a poor random number generator."
884d99bd55aSTed Kremenek       << "  Use 'arc4random' instead";
885d99bd55aSTed Kremenek 
886c29bed39SAnna Zaks   PathDiagnosticLocation CELoc =
887c29bed39SAnna Zaks     PathDiagnosticLocation::createBegin(CE, BR.getSourceManager(), AC);
8884aca9b1cSAlexander Kornienko   BR.EmitBasicReport(AC->getDecl(), filter.checkName_rand, os1.str(),
8894aca9b1cSAlexander Kornienko                      "Security", os2.str(), CELoc,
8904aca9b1cSAlexander Kornienko                      CE->getCallee()->getSourceRange());
891d99bd55aSTed Kremenek }
892d99bd55aSTed Kremenek 
893d99bd55aSTed Kremenek //===----------------------------------------------------------------------===//
894d99bd55aSTed Kremenek // Check: 'random' should not be used
895d99bd55aSTed Kremenek // Originally: <rdar://problem/63371000>
896d99bd55aSTed Kremenek //===----------------------------------------------------------------------===//
897d99bd55aSTed Kremenek 
checkCall_random(const CallExpr * CE,const FunctionDecl * FD)898de909e49SLenny Maiorani void WalkAST::checkCall_random(const CallExpr *CE, const FunctionDecl *FD) {
89989eaf8d5STed Kremenek   if (!CheckRand || !filter.check_rand)
900d99bd55aSTed Kremenek     return;
901d99bd55aSTed Kremenek 
90257d1f1c8SEli Friedman   const FunctionProtoType *FTP = FD->getType()->getAs<FunctionProtoType>();
903d99bd55aSTed Kremenek   if (!FTP)
904d99bd55aSTed Kremenek     return;
905d99bd55aSTed Kremenek 
906d99bd55aSTed Kremenek   // Verify that the function takes no argument.
9079cacbabdSAlp Toker   if (FTP->getNumParams() != 0)
908d99bd55aSTed Kremenek     return;
909d99bd55aSTed Kremenek 
910d99bd55aSTed Kremenek   // Issue a warning.
911c29bed39SAnna Zaks   PathDiagnosticLocation CELoc =
912c29bed39SAnna Zaks     PathDiagnosticLocation::createBegin(CE, BR.getSourceManager(), AC);
9134aca9b1cSAlexander Kornienko   BR.EmitBasicReport(AC->getDecl(), filter.checkName_rand,
9145a10f08bSTed Kremenek                      "'random' is not a secure random number generator",
915d99bd55aSTed Kremenek                      "Security",
916d99bd55aSTed Kremenek                      "The 'random' function produces a sequence of values that "
917d99bd55aSTed Kremenek                      "an adversary may be able to predict.  Use 'arc4random' "
91842b4248fSJordan Rose                      "instead", CELoc, CE->getCallee()->getSourceRange());
919d99bd55aSTed Kremenek }
920d99bd55aSTed Kremenek 
921d99bd55aSTed Kremenek //===----------------------------------------------------------------------===//
922fedf5dfcSAnna Zaks // Check: 'vfork' should not be used.
923fedf5dfcSAnna Zaks // POS33-C: Do not use vfork().
924fedf5dfcSAnna Zaks //===----------------------------------------------------------------------===//
925fedf5dfcSAnna Zaks 
checkCall_vfork(const CallExpr * CE,const FunctionDecl * FD)926fedf5dfcSAnna Zaks void WalkAST::checkCall_vfork(const CallExpr *CE, const FunctionDecl *FD) {
927c54dc951STed Kremenek   if (!filter.check_vfork)
928c54dc951STed Kremenek     return;
929c54dc951STed Kremenek 
930fedf5dfcSAnna Zaks   // All calls to vfork() are insecure, issue a warning.
931fedf5dfcSAnna Zaks   PathDiagnosticLocation CELoc =
932fedf5dfcSAnna Zaks     PathDiagnosticLocation::createBegin(CE, BR.getSourceManager(), AC);
9334aca9b1cSAlexander Kornienko   BR.EmitBasicReport(AC->getDecl(), filter.checkName_vfork,
9345a10f08bSTed Kremenek                      "Potential insecure implementation-specific behavior in "
935fedf5dfcSAnna Zaks                      "call 'vfork'",
936fedf5dfcSAnna Zaks                      "Security",
937fedf5dfcSAnna Zaks                      "Call to function 'vfork' is insecure as it can lead to "
938fedf5dfcSAnna Zaks                      "denial of service situations in the parent process. "
939fedf5dfcSAnna Zaks                      "Replace calls to vfork with calls to the safer "
940fedf5dfcSAnna Zaks                      "'posix_spawn' function",
94142b4248fSJordan Rose                      CELoc, CE->getCallee()->getSourceRange());
942fedf5dfcSAnna Zaks }
943fedf5dfcSAnna Zaks 
944fedf5dfcSAnna Zaks //===----------------------------------------------------------------------===//
945b2840050SArtem Dergachev // Check: '-decodeValueOfObjCType:at:' should not be used.
946b2840050SArtem Dergachev // It is deprecated in favor of '-decodeValueOfObjCType:at:size:' due to
947b2840050SArtem Dergachev // likelihood of buffer overflows.
948b2840050SArtem Dergachev //===----------------------------------------------------------------------===//
949b2840050SArtem Dergachev 
checkMsg_decodeValueOfObjCType(const ObjCMessageExpr * ME)950b2840050SArtem Dergachev void WalkAST::checkMsg_decodeValueOfObjCType(const ObjCMessageExpr *ME) {
951b2840050SArtem Dergachev   if (!filter.check_decodeValueOfObjCType)
952b2840050SArtem Dergachev     return;
953b2840050SArtem Dergachev 
954b2840050SArtem Dergachev   // Check availability of the secure alternative:
955b2840050SArtem Dergachev   // iOS 11+, macOS 10.13+, tvOS 11+, and watchOS 4.0+
956b2840050SArtem Dergachev   // FIXME: We probably shouldn't register the check if it's not available.
957b2840050SArtem Dergachev   const TargetInfo &TI = AC->getASTContext().getTargetInfo();
958b2840050SArtem Dergachev   const llvm::Triple &T = TI.getTriple();
959b2840050SArtem Dergachev   const VersionTuple &VT = TI.getPlatformMinVersion();
960b2840050SArtem Dergachev   switch (T.getOS()) {
961b2840050SArtem Dergachev   case llvm::Triple::IOS:
962b2840050SArtem Dergachev     if (VT < VersionTuple(11, 0))
963b2840050SArtem Dergachev       return;
964b2840050SArtem Dergachev     break;
965b2840050SArtem Dergachev   case llvm::Triple::MacOSX:
966b2840050SArtem Dergachev     if (VT < VersionTuple(10, 13))
967b2840050SArtem Dergachev       return;
968b2840050SArtem Dergachev     break;
969b2840050SArtem Dergachev   case llvm::Triple::WatchOS:
970b2840050SArtem Dergachev     if (VT < VersionTuple(4, 0))
971b2840050SArtem Dergachev       return;
972b2840050SArtem Dergachev     break;
973b2840050SArtem Dergachev   case llvm::Triple::TvOS:
974b2840050SArtem Dergachev     if (VT < VersionTuple(11, 0))
975b2840050SArtem Dergachev       return;
976b2840050SArtem Dergachev     break;
977b2840050SArtem Dergachev   default:
978b2840050SArtem Dergachev     return;
979b2840050SArtem Dergachev   }
980b2840050SArtem Dergachev 
981b2840050SArtem Dergachev   PathDiagnosticLocation MELoc =
982b2840050SArtem Dergachev       PathDiagnosticLocation::createBegin(ME, BR.getSourceManager(), AC);
983b2840050SArtem Dergachev   BR.EmitBasicReport(
984b2840050SArtem Dergachev       AC->getDecl(), filter.checkName_decodeValueOfObjCType,
985b2840050SArtem Dergachev       "Potential buffer overflow in '-decodeValueOfObjCType:at:'", "Security",
986b2840050SArtem Dergachev       "Deprecated method '-decodeValueOfObjCType:at:' is insecure "
987b2840050SArtem Dergachev       "as it can lead to potential buffer overflows. Use the safer "
988b2840050SArtem Dergachev       "'-decodeValueOfObjCType:at:size:' method.",
989b2840050SArtem Dergachev       MELoc, ME->getSourceRange());
990b2840050SArtem Dergachev }
991b2840050SArtem Dergachev 
992b2840050SArtem Dergachev //===----------------------------------------------------------------------===//
993d99bd55aSTed Kremenek // Check: Should check whether privileges are dropped successfully.
994d99bd55aSTed Kremenek // Originally: <rdar://problem/6337132>
995d99bd55aSTed Kremenek //===----------------------------------------------------------------------===//
996d99bd55aSTed Kremenek 
checkUncheckedReturnValue(CallExpr * CE)997de909e49SLenny Maiorani void WalkAST::checkUncheckedReturnValue(CallExpr *CE) {
99889eaf8d5STed Kremenek   if (!filter.check_UncheckedReturn)
99989eaf8d5STed Kremenek     return;
100089eaf8d5STed Kremenek 
1001d99bd55aSTed Kremenek   const FunctionDecl *FD = CE->getDirectCallee();
1002d99bd55aSTed Kremenek   if (!FD)
1003d99bd55aSTed Kremenek     return;
1004d99bd55aSTed Kremenek 
10050dbb783cSCraig Topper   if (II_setid[0] == nullptr) {
1006d99bd55aSTed Kremenek     static const char * const identifiers[num_setids] = {
1007d99bd55aSTed Kremenek       "setuid", "setgid", "seteuid", "setegid",
1008d99bd55aSTed Kremenek       "setreuid", "setregid"
1009d99bd55aSTed Kremenek     };
1010d99bd55aSTed Kremenek 
1011d99bd55aSTed Kremenek     for (size_t i = 0; i < num_setids; i++)
1012d99bd55aSTed Kremenek       II_setid[i] = &BR.getContext().Idents.get(identifiers[i]);
1013d99bd55aSTed Kremenek   }
1014d99bd55aSTed Kremenek 
1015d99bd55aSTed Kremenek   const IdentifierInfo *id = FD->getIdentifier();
1016d99bd55aSTed Kremenek   size_t identifierid;
1017d99bd55aSTed Kremenek 
1018d99bd55aSTed Kremenek   for (identifierid = 0; identifierid < num_setids; identifierid++)
1019d99bd55aSTed Kremenek     if (id == II_setid[identifierid])
1020d99bd55aSTed Kremenek       break;
1021d99bd55aSTed Kremenek 
1022d99bd55aSTed Kremenek   if (identifierid >= num_setids)
1023d99bd55aSTed Kremenek     return;
1024d99bd55aSTed Kremenek 
102557d1f1c8SEli Friedman   const FunctionProtoType *FTP = FD->getType()->getAs<FunctionProtoType>();
1026d99bd55aSTed Kremenek   if (!FTP)
1027d99bd55aSTed Kremenek     return;
1028d99bd55aSTed Kremenek 
1029d99bd55aSTed Kremenek   // Verify that the function takes one or two arguments (depending on
1030d99bd55aSTed Kremenek   //   the function).
10319cacbabdSAlp Toker   if (FTP->getNumParams() != (identifierid < 4 ? 1 : 2))
1032d99bd55aSTed Kremenek     return;
1033d99bd55aSTed Kremenek 
1034d99bd55aSTed Kremenek   // The arguments must be integers.
10359cacbabdSAlp Toker   for (unsigned i = 0; i < FTP->getNumParams(); i++)
10369cacbabdSAlp Toker     if (!FTP->getParamType(i)->isIntegralOrUnscopedEnumerationType())
1037d99bd55aSTed Kremenek       return;
1038d99bd55aSTed Kremenek 
1039d99bd55aSTed Kremenek   // Issue a warning.
10402c1dd271SDylan Noblesmith   SmallString<256> buf1;
1041d99bd55aSTed Kremenek   llvm::raw_svector_ostream os1(buf1);
1042b89514a9SBenjamin Kramer   os1 << "Return value is not checked in call to '" << *FD << '\'';
1043d99bd55aSTed Kremenek 
10442c1dd271SDylan Noblesmith   SmallString<256> buf2;
1045d99bd55aSTed Kremenek   llvm::raw_svector_ostream os2(buf2);
1046b89514a9SBenjamin Kramer   os2 << "The return value from the call to '" << *FD
1047b89514a9SBenjamin Kramer       << "' is not checked.  If an error occurs in '" << *FD
1048d99bd55aSTed Kremenek       << "', the following code may execute with unexpected privileges";
1049d99bd55aSTed Kremenek 
1050c29bed39SAnna Zaks   PathDiagnosticLocation CELoc =
1051c29bed39SAnna Zaks     PathDiagnosticLocation::createBegin(CE, BR.getSourceManager(), AC);
10524aca9b1cSAlexander Kornienko   BR.EmitBasicReport(AC->getDecl(), filter.checkName_UncheckedReturn, os1.str(),
10534aca9b1cSAlexander Kornienko                      "Security", os2.str(), CELoc,
10544aca9b1cSAlexander Kornienko                      CE->getCallee()->getSourceRange());
1055d99bd55aSTed Kremenek }
1056d99bd55aSTed Kremenek 
1057d99bd55aSTed Kremenek //===----------------------------------------------------------------------===//
1058af45aca6SArgyrios Kyrtzidis // SecuritySyntaxChecker
1059d99bd55aSTed Kremenek //===----------------------------------------------------------------------===//
1060d99bd55aSTed Kremenek 
1061af45aca6SArgyrios Kyrtzidis namespace {
10626a5674ffSArgyrios Kyrtzidis class SecuritySyntaxChecker : public Checker<check::ASTCodeBody> {
1063af45aca6SArgyrios Kyrtzidis public:
1064c54dc951STed Kremenek   ChecksFilter filter;
1065c54dc951STed Kremenek 
checkASTCodeBody(const Decl * D,AnalysisManager & mgr,BugReporter & BR) const1066af45aca6SArgyrios Kyrtzidis   void checkASTCodeBody(const Decl *D, AnalysisManager& mgr,
1067af45aca6SArgyrios Kyrtzidis                         BugReporter &BR) const {
1068c54dc951STed Kremenek     WalkAST walker(BR, mgr.getAnalysisDeclContext(D), filter);
1069d99bd55aSTed Kremenek     walker.Visit(D->getBody());
1070d99bd55aSTed Kremenek   }
1071af45aca6SArgyrios Kyrtzidis };
1072ab9db510SAlexander Kornienko }
1073af45aca6SArgyrios Kyrtzidis 
registerSecuritySyntaxChecker(CheckerManager & mgr)10748fd74ebfSKristof Umann void ento::registerSecuritySyntaxChecker(CheckerManager &mgr) {
10758fd74ebfSKristof Umann   mgr.registerChecker<SecuritySyntaxChecker>();
10768fd74ebfSKristof Umann }
10778fd74ebfSKristof Umann 
shouldRegisterSecuritySyntaxChecker(const CheckerManager & mgr)1078bda3dd0dSKirstóf Umann bool ento::shouldRegisterSecuritySyntaxChecker(const CheckerManager &mgr) {
10798fd74ebfSKristof Umann   return true;
10808fd74ebfSKristof Umann }
10818fd74ebfSKristof Umann 
1082c54dc951STed Kremenek #define REGISTER_CHECKER(name)                                                 \
1083c54dc951STed Kremenek   void ento::register##name(CheckerManager &mgr) {                             \
1084204bf2bbSKristof Umann     SecuritySyntaxChecker *checker = mgr.getChecker<SecuritySyntaxChecker>();  \
10854aca9b1cSAlexander Kornienko     checker->filter.check_##name = true;                                       \
108672649423SKristof Umann     checker->filter.checkName_##name = mgr.getCurrentCheckerName();            \
1087058a7a45SKristof Umann   }                                                                            \
1088058a7a45SKristof Umann                                                                                \
1089bda3dd0dSKirstóf Umann   bool ento::shouldRegister##name(const CheckerManager &mgr) { return true; }
1090c54dc951STed Kremenek 
10918419cf30SArtem Dergachev REGISTER_CHECKER(bcmp)
10928419cf30SArtem Dergachev REGISTER_CHECKER(bcopy)
10938419cf30SArtem Dergachev REGISTER_CHECKER(bzero)
1094c54dc951STed Kremenek REGISTER_CHECKER(gets)
1095c54dc951STed Kremenek REGISTER_CHECKER(getpw)
109689eaf8d5STed Kremenek REGISTER_CHECKER(mkstemp)
1097c54dc951STed Kremenek REGISTER_CHECKER(mktemp)
1098c54dc951STed Kremenek REGISTER_CHECKER(strcpy)
1099c54dc951STed Kremenek REGISTER_CHECKER(rand)
1100c54dc951STed Kremenek REGISTER_CHECKER(vfork)
1101c54dc951STed Kremenek REGISTER_CHECKER(FloatLoopCounter)
110289eaf8d5STed Kremenek REGISTER_CHECKER(UncheckedReturn)
11038d239996SKristof Umann REGISTER_CHECKER(DeprecatedOrUnsafeBufferHandling)
1104b2840050SArtem Dergachev REGISTER_CHECKER(decodeValueOfObjCType)
1105