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