xref: /aosp_15_r20/external/clang/lib/StaticAnalyzer/Checkers/CheckSecuritySyntaxOnly.cpp (revision 67e74705e28f6214e480b399dd47ea732279e315)
1*67e74705SXin Li //==- CheckSecuritySyntaxOnly.cpp - Basic security checks --------*- C++ -*-==//
2*67e74705SXin Li //
3*67e74705SXin Li //                     The LLVM Compiler Infrastructure
4*67e74705SXin Li //
5*67e74705SXin Li // This file is distributed under the University of Illinois Open Source
6*67e74705SXin Li // License. See LICENSE.TXT for details.
7*67e74705SXin Li //
8*67e74705SXin Li //===----------------------------------------------------------------------===//
9*67e74705SXin Li //
10*67e74705SXin Li //  This file defines a set of flow-insensitive security checks.
11*67e74705SXin Li //
12*67e74705SXin Li //===----------------------------------------------------------------------===//
13*67e74705SXin Li 
14*67e74705SXin Li #include "ClangSACheckers.h"
15*67e74705SXin Li #include "clang/AST/StmtVisitor.h"
16*67e74705SXin Li #include "clang/Analysis/AnalysisContext.h"
17*67e74705SXin Li #include "clang/Basic/TargetInfo.h"
18*67e74705SXin Li #include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h"
19*67e74705SXin Li #include "clang/StaticAnalyzer/Core/Checker.h"
20*67e74705SXin Li #include "clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h"
21*67e74705SXin Li #include "llvm/ADT/SmallString.h"
22*67e74705SXin Li #include "llvm/ADT/StringSwitch.h"
23*67e74705SXin Li #include "llvm/Support/raw_ostream.h"
24*67e74705SXin Li 
25*67e74705SXin Li using namespace clang;
26*67e74705SXin Li using namespace ento;
27*67e74705SXin Li 
isArc4RandomAvailable(const ASTContext & Ctx)28*67e74705SXin Li static bool isArc4RandomAvailable(const ASTContext &Ctx) {
29*67e74705SXin Li   const llvm::Triple &T = Ctx.getTargetInfo().getTriple();
30*67e74705SXin Li   return T.getVendor() == llvm::Triple::Apple ||
31*67e74705SXin Li          T.getOS() == llvm::Triple::CloudABI ||
32*67e74705SXin Li          T.getOS() == llvm::Triple::FreeBSD ||
33*67e74705SXin Li          T.getOS() == llvm::Triple::NetBSD ||
34*67e74705SXin Li          T.getOS() == llvm::Triple::OpenBSD ||
35*67e74705SXin Li          T.getOS() == llvm::Triple::Bitrig ||
36*67e74705SXin Li          T.getOS() == llvm::Triple::DragonFly;
37*67e74705SXin Li }
38*67e74705SXin Li 
39*67e74705SXin Li namespace {
40*67e74705SXin Li struct ChecksFilter {
41*67e74705SXin Li   DefaultBool check_gets;
42*67e74705SXin Li   DefaultBool check_getpw;
43*67e74705SXin Li   DefaultBool check_mktemp;
44*67e74705SXin Li   DefaultBool check_mkstemp;
45*67e74705SXin Li   DefaultBool check_strcpy;
46*67e74705SXin Li   DefaultBool check_rand;
47*67e74705SXin Li   DefaultBool check_vfork;
48*67e74705SXin Li   DefaultBool check_FloatLoopCounter;
49*67e74705SXin Li   DefaultBool check_UncheckedReturn;
50*67e74705SXin Li 
51*67e74705SXin Li   CheckName checkName_gets;
52*67e74705SXin Li   CheckName checkName_getpw;
53*67e74705SXin Li   CheckName checkName_mktemp;
54*67e74705SXin Li   CheckName checkName_mkstemp;
55*67e74705SXin Li   CheckName checkName_strcpy;
56*67e74705SXin Li   CheckName checkName_rand;
57*67e74705SXin Li   CheckName checkName_vfork;
58*67e74705SXin Li   CheckName checkName_FloatLoopCounter;
59*67e74705SXin Li   CheckName checkName_UncheckedReturn;
60*67e74705SXin Li };
61*67e74705SXin Li 
62*67e74705SXin Li class WalkAST : public StmtVisitor<WalkAST> {
63*67e74705SXin Li   BugReporter &BR;
64*67e74705SXin Li   AnalysisDeclContext* AC;
65*67e74705SXin Li   enum { num_setids = 6 };
66*67e74705SXin Li   IdentifierInfo *II_setid[num_setids];
67*67e74705SXin Li 
68*67e74705SXin Li   const bool CheckRand;
69*67e74705SXin Li   const ChecksFilter &filter;
70*67e74705SXin Li 
71*67e74705SXin Li public:
WalkAST(BugReporter & br,AnalysisDeclContext * ac,const ChecksFilter & f)72*67e74705SXin Li   WalkAST(BugReporter &br, AnalysisDeclContext* ac,
73*67e74705SXin Li           const ChecksFilter &f)
74*67e74705SXin Li   : BR(br), AC(ac), II_setid(),
75*67e74705SXin Li     CheckRand(isArc4RandomAvailable(BR.getContext())),
76*67e74705SXin Li     filter(f) {}
77*67e74705SXin Li 
78*67e74705SXin Li   // Statement visitor methods.
79*67e74705SXin Li   void VisitCallExpr(CallExpr *CE);
80*67e74705SXin Li   void VisitForStmt(ForStmt *S);
81*67e74705SXin Li   void VisitCompoundStmt (CompoundStmt *S);
VisitStmt(Stmt * S)82*67e74705SXin Li   void VisitStmt(Stmt *S) { VisitChildren(S); }
83*67e74705SXin Li 
84*67e74705SXin Li   void VisitChildren(Stmt *S);
85*67e74705SXin Li 
86*67e74705SXin Li   // Helpers.
87*67e74705SXin Li   bool checkCall_strCommon(const CallExpr *CE, const FunctionDecl *FD);
88*67e74705SXin Li 
89*67e74705SXin Li   typedef void (WalkAST::*FnCheck)(const CallExpr *, const FunctionDecl *);
90*67e74705SXin Li 
91*67e74705SXin Li   // Checker-specific methods.
92*67e74705SXin Li   void checkLoopConditionForFloat(const ForStmt *FS);
93*67e74705SXin Li   void checkCall_gets(const CallExpr *CE, const FunctionDecl *FD);
94*67e74705SXin Li   void checkCall_getpw(const CallExpr *CE, const FunctionDecl *FD);
95*67e74705SXin Li   void checkCall_mktemp(const CallExpr *CE, const FunctionDecl *FD);
96*67e74705SXin Li   void checkCall_mkstemp(const CallExpr *CE, const FunctionDecl *FD);
97*67e74705SXin Li   void checkCall_strcpy(const CallExpr *CE, const FunctionDecl *FD);
98*67e74705SXin Li   void checkCall_strcat(const CallExpr *CE, const FunctionDecl *FD);
99*67e74705SXin Li   void checkCall_rand(const CallExpr *CE, const FunctionDecl *FD);
100*67e74705SXin Li   void checkCall_random(const CallExpr *CE, const FunctionDecl *FD);
101*67e74705SXin Li   void checkCall_vfork(const CallExpr *CE, const FunctionDecl *FD);
102*67e74705SXin Li   void checkUncheckedReturnValue(CallExpr *CE);
103*67e74705SXin Li };
104*67e74705SXin Li } // end anonymous namespace
105*67e74705SXin Li 
106*67e74705SXin Li //===----------------------------------------------------------------------===//
107*67e74705SXin Li // AST walking.
108*67e74705SXin Li //===----------------------------------------------------------------------===//
109*67e74705SXin Li 
VisitChildren(Stmt * S)110*67e74705SXin Li void WalkAST::VisitChildren(Stmt *S) {
111*67e74705SXin Li   for (Stmt *Child : S->children())
112*67e74705SXin Li     if (Child)
113*67e74705SXin Li       Visit(Child);
114*67e74705SXin Li }
115*67e74705SXin Li 
VisitCallExpr(CallExpr * CE)116*67e74705SXin Li void WalkAST::VisitCallExpr(CallExpr *CE) {
117*67e74705SXin Li   // Get the callee.
118*67e74705SXin Li   const FunctionDecl *FD = CE->getDirectCallee();
119*67e74705SXin Li 
120*67e74705SXin Li   if (!FD)
121*67e74705SXin Li     return;
122*67e74705SXin Li 
123*67e74705SXin Li   // Get the name of the callee. If it's a builtin, strip off the prefix.
124*67e74705SXin Li   IdentifierInfo *II = FD->getIdentifier();
125*67e74705SXin Li   if (!II)   // if no identifier, not a simple C function
126*67e74705SXin Li     return;
127*67e74705SXin Li   StringRef Name = II->getName();
128*67e74705SXin Li   if (Name.startswith("__builtin_"))
129*67e74705SXin Li     Name = Name.substr(10);
130*67e74705SXin Li 
131*67e74705SXin Li   // Set the evaluation function by switching on the callee name.
132*67e74705SXin Li   FnCheck evalFunction = llvm::StringSwitch<FnCheck>(Name)
133*67e74705SXin Li     .Case("gets", &WalkAST::checkCall_gets)
134*67e74705SXin Li     .Case("getpw", &WalkAST::checkCall_getpw)
135*67e74705SXin Li     .Case("mktemp", &WalkAST::checkCall_mktemp)
136*67e74705SXin Li     .Case("mkstemp", &WalkAST::checkCall_mkstemp)
137*67e74705SXin Li     .Case("mkdtemp", &WalkAST::checkCall_mkstemp)
138*67e74705SXin Li     .Case("mkstemps", &WalkAST::checkCall_mkstemp)
139*67e74705SXin Li     .Cases("strcpy", "__strcpy_chk", &WalkAST::checkCall_strcpy)
140*67e74705SXin Li     .Cases("strcat", "__strcat_chk", &WalkAST::checkCall_strcat)
141*67e74705SXin Li     .Case("drand48", &WalkAST::checkCall_rand)
142*67e74705SXin Li     .Case("erand48", &WalkAST::checkCall_rand)
143*67e74705SXin Li     .Case("jrand48", &WalkAST::checkCall_rand)
144*67e74705SXin Li     .Case("lrand48", &WalkAST::checkCall_rand)
145*67e74705SXin Li     .Case("mrand48", &WalkAST::checkCall_rand)
146*67e74705SXin Li     .Case("nrand48", &WalkAST::checkCall_rand)
147*67e74705SXin Li     .Case("lcong48", &WalkAST::checkCall_rand)
148*67e74705SXin Li     .Case("rand", &WalkAST::checkCall_rand)
149*67e74705SXin Li     .Case("rand_r", &WalkAST::checkCall_rand)
150*67e74705SXin Li     .Case("random", &WalkAST::checkCall_random)
151*67e74705SXin Li     .Case("vfork", &WalkAST::checkCall_vfork)
152*67e74705SXin Li     .Default(nullptr);
153*67e74705SXin Li 
154*67e74705SXin Li   // If the callee isn't defined, it is not of security concern.
155*67e74705SXin Li   // Check and evaluate the call.
156*67e74705SXin Li   if (evalFunction)
157*67e74705SXin Li     (this->*evalFunction)(CE, FD);
158*67e74705SXin Li 
159*67e74705SXin Li   // Recurse and check children.
160*67e74705SXin Li   VisitChildren(CE);
161*67e74705SXin Li }
162*67e74705SXin Li 
VisitCompoundStmt(CompoundStmt * S)163*67e74705SXin Li void WalkAST::VisitCompoundStmt(CompoundStmt *S) {
164*67e74705SXin Li   for (Stmt *Child : S->children())
165*67e74705SXin Li     if (Child) {
166*67e74705SXin Li       if (CallExpr *CE = dyn_cast<CallExpr>(Child))
167*67e74705SXin Li         checkUncheckedReturnValue(CE);
168*67e74705SXin Li       Visit(Child);
169*67e74705SXin Li     }
170*67e74705SXin Li }
171*67e74705SXin Li 
VisitForStmt(ForStmt * FS)172*67e74705SXin Li void WalkAST::VisitForStmt(ForStmt *FS) {
173*67e74705SXin Li   checkLoopConditionForFloat(FS);
174*67e74705SXin Li 
175*67e74705SXin Li   // Recurse and check children.
176*67e74705SXin Li   VisitChildren(FS);
177*67e74705SXin Li }
178*67e74705SXin Li 
179*67e74705SXin Li //===----------------------------------------------------------------------===//
180*67e74705SXin Li // Check: floating poing variable used as loop counter.
181*67e74705SXin Li // Originally: <rdar://problem/6336718>
182*67e74705SXin Li // Implements: CERT security coding advisory FLP-30.
183*67e74705SXin Li //===----------------------------------------------------------------------===//
184*67e74705SXin Li 
185*67e74705SXin Li static const DeclRefExpr*
getIncrementedVar(const Expr * expr,const VarDecl * x,const VarDecl * y)186*67e74705SXin Li getIncrementedVar(const Expr *expr, const VarDecl *x, const VarDecl *y) {
187*67e74705SXin Li   expr = expr->IgnoreParenCasts();
188*67e74705SXin Li 
189*67e74705SXin Li   if (const BinaryOperator *B = dyn_cast<BinaryOperator>(expr)) {
190*67e74705SXin Li     if (!(B->isAssignmentOp() || B->isCompoundAssignmentOp() ||
191*67e74705SXin Li           B->getOpcode() == BO_Comma))
192*67e74705SXin Li       return nullptr;
193*67e74705SXin Li 
194*67e74705SXin Li     if (const DeclRefExpr *lhs = getIncrementedVar(B->getLHS(), x, y))
195*67e74705SXin Li       return lhs;
196*67e74705SXin Li 
197*67e74705SXin Li     if (const DeclRefExpr *rhs = getIncrementedVar(B->getRHS(), x, y))
198*67e74705SXin Li       return rhs;
199*67e74705SXin Li 
200*67e74705SXin Li     return nullptr;
201*67e74705SXin Li   }
202*67e74705SXin Li 
203*67e74705SXin Li   if (const DeclRefExpr *DR = dyn_cast<DeclRefExpr>(expr)) {
204*67e74705SXin Li     const NamedDecl *ND = DR->getDecl();
205*67e74705SXin Li     return ND == x || ND == y ? DR : nullptr;
206*67e74705SXin Li   }
207*67e74705SXin Li 
208*67e74705SXin Li   if (const UnaryOperator *U = dyn_cast<UnaryOperator>(expr))
209*67e74705SXin Li     return U->isIncrementDecrementOp()
210*67e74705SXin Li       ? getIncrementedVar(U->getSubExpr(), x, y) : nullptr;
211*67e74705SXin Li 
212*67e74705SXin Li   return nullptr;
213*67e74705SXin Li }
214*67e74705SXin Li 
215*67e74705SXin Li /// CheckLoopConditionForFloat - This check looks for 'for' statements that
216*67e74705SXin Li ///  use a floating point variable as a loop counter.
217*67e74705SXin Li ///  CERT: FLP30-C, FLP30-CPP.
218*67e74705SXin Li ///
checkLoopConditionForFloat(const ForStmt * FS)219*67e74705SXin Li void WalkAST::checkLoopConditionForFloat(const ForStmt *FS) {
220*67e74705SXin Li   if (!filter.check_FloatLoopCounter)
221*67e74705SXin Li     return;
222*67e74705SXin Li 
223*67e74705SXin Li   // Does the loop have a condition?
224*67e74705SXin Li   const Expr *condition = FS->getCond();
225*67e74705SXin Li 
226*67e74705SXin Li   if (!condition)
227*67e74705SXin Li     return;
228*67e74705SXin Li 
229*67e74705SXin Li   // Does the loop have an increment?
230*67e74705SXin Li   const Expr *increment = FS->getInc();
231*67e74705SXin Li 
232*67e74705SXin Li   if (!increment)
233*67e74705SXin Li     return;
234*67e74705SXin Li 
235*67e74705SXin Li   // Strip away '()' and casts.
236*67e74705SXin Li   condition = condition->IgnoreParenCasts();
237*67e74705SXin Li   increment = increment->IgnoreParenCasts();
238*67e74705SXin Li 
239*67e74705SXin Li   // Is the loop condition a comparison?
240*67e74705SXin Li   const BinaryOperator *B = dyn_cast<BinaryOperator>(condition);
241*67e74705SXin Li 
242*67e74705SXin Li   if (!B)
243*67e74705SXin Li     return;
244*67e74705SXin Li 
245*67e74705SXin Li   // Is this a comparison?
246*67e74705SXin Li   if (!(B->isRelationalOp() || B->isEqualityOp()))
247*67e74705SXin Li     return;
248*67e74705SXin Li 
249*67e74705SXin Li   // Are we comparing variables?
250*67e74705SXin Li   const DeclRefExpr *drLHS =
251*67e74705SXin Li     dyn_cast<DeclRefExpr>(B->getLHS()->IgnoreParenLValueCasts());
252*67e74705SXin Li   const DeclRefExpr *drRHS =
253*67e74705SXin Li     dyn_cast<DeclRefExpr>(B->getRHS()->IgnoreParenLValueCasts());
254*67e74705SXin Li 
255*67e74705SXin Li   // Does at least one of the variables have a floating point type?
256*67e74705SXin Li   drLHS = drLHS && drLHS->getType()->isRealFloatingType() ? drLHS : nullptr;
257*67e74705SXin Li   drRHS = drRHS && drRHS->getType()->isRealFloatingType() ? drRHS : nullptr;
258*67e74705SXin Li 
259*67e74705SXin Li   if (!drLHS && !drRHS)
260*67e74705SXin Li     return;
261*67e74705SXin Li 
262*67e74705SXin Li   const VarDecl *vdLHS = drLHS ? dyn_cast<VarDecl>(drLHS->getDecl()) : nullptr;
263*67e74705SXin Li   const VarDecl *vdRHS = drRHS ? dyn_cast<VarDecl>(drRHS->getDecl()) : nullptr;
264*67e74705SXin Li 
265*67e74705SXin Li   if (!vdLHS && !vdRHS)
266*67e74705SXin Li     return;
267*67e74705SXin Li 
268*67e74705SXin Li   // Does either variable appear in increment?
269*67e74705SXin Li   const DeclRefExpr *drInc = getIncrementedVar(increment, vdLHS, vdRHS);
270*67e74705SXin Li 
271*67e74705SXin Li   if (!drInc)
272*67e74705SXin Li     return;
273*67e74705SXin Li 
274*67e74705SXin Li   // Emit the error.  First figure out which DeclRefExpr in the condition
275*67e74705SXin Li   // referenced the compared variable.
276*67e74705SXin Li   assert(drInc->getDecl());
277*67e74705SXin Li   const DeclRefExpr *drCond = vdLHS == drInc->getDecl() ? drLHS : drRHS;
278*67e74705SXin Li 
279*67e74705SXin Li   SmallVector<SourceRange, 2> ranges;
280*67e74705SXin Li   SmallString<256> sbuf;
281*67e74705SXin Li   llvm::raw_svector_ostream os(sbuf);
282*67e74705SXin Li 
283*67e74705SXin Li   os << "Variable '" << drCond->getDecl()->getName()
284*67e74705SXin Li      << "' with floating point type '" << drCond->getType().getAsString()
285*67e74705SXin Li      << "' should not be used as a loop counter";
286*67e74705SXin Li 
287*67e74705SXin Li   ranges.push_back(drCond->getSourceRange());
288*67e74705SXin Li   ranges.push_back(drInc->getSourceRange());
289*67e74705SXin Li 
290*67e74705SXin Li   const char *bugType = "Floating point variable used as loop counter";
291*67e74705SXin Li 
292*67e74705SXin Li   PathDiagnosticLocation FSLoc =
293*67e74705SXin Li     PathDiagnosticLocation::createBegin(FS, BR.getSourceManager(), AC);
294*67e74705SXin Li   BR.EmitBasicReport(AC->getDecl(), filter.checkName_FloatLoopCounter,
295*67e74705SXin Li                      bugType, "Security", os.str(),
296*67e74705SXin Li                      FSLoc, ranges);
297*67e74705SXin Li }
298*67e74705SXin Li 
299*67e74705SXin Li //===----------------------------------------------------------------------===//
300*67e74705SXin Li // Check: Any use of 'gets' is insecure.
301*67e74705SXin Li // Originally: <rdar://problem/6335715>
302*67e74705SXin Li // Implements (part of): 300-BSI (buildsecurityin.us-cert.gov)
303*67e74705SXin Li // CWE-242: Use of Inherently Dangerous Function
304*67e74705SXin Li //===----------------------------------------------------------------------===//
305*67e74705SXin Li 
checkCall_gets(const CallExpr * CE,const FunctionDecl * FD)306*67e74705SXin Li void WalkAST::checkCall_gets(const CallExpr *CE, const FunctionDecl *FD) {
307*67e74705SXin Li   if (!filter.check_gets)
308*67e74705SXin Li     return;
309*67e74705SXin Li 
310*67e74705SXin Li   const FunctionProtoType *FPT = FD->getType()->getAs<FunctionProtoType>();
311*67e74705SXin Li   if (!FPT)
312*67e74705SXin Li     return;
313*67e74705SXin Li 
314*67e74705SXin Li   // Verify that the function takes a single argument.
315*67e74705SXin Li   if (FPT->getNumParams() != 1)
316*67e74705SXin Li     return;
317*67e74705SXin Li 
318*67e74705SXin Li   // Is the argument a 'char*'?
319*67e74705SXin Li   const PointerType *PT = FPT->getParamType(0)->getAs<PointerType>();
320*67e74705SXin Li   if (!PT)
321*67e74705SXin Li     return;
322*67e74705SXin Li 
323*67e74705SXin Li   if (PT->getPointeeType().getUnqualifiedType() != BR.getContext().CharTy)
324*67e74705SXin Li     return;
325*67e74705SXin Li 
326*67e74705SXin Li   // Issue a warning.
327*67e74705SXin Li   PathDiagnosticLocation CELoc =
328*67e74705SXin Li     PathDiagnosticLocation::createBegin(CE, BR.getSourceManager(), AC);
329*67e74705SXin Li   BR.EmitBasicReport(AC->getDecl(), filter.checkName_gets,
330*67e74705SXin Li                      "Potential buffer overflow in call to 'gets'",
331*67e74705SXin Li                      "Security",
332*67e74705SXin Li                      "Call to function 'gets' is extremely insecure as it can "
333*67e74705SXin Li                      "always result in a buffer overflow",
334*67e74705SXin Li                      CELoc, CE->getCallee()->getSourceRange());
335*67e74705SXin Li }
336*67e74705SXin Li 
337*67e74705SXin Li //===----------------------------------------------------------------------===//
338*67e74705SXin Li // Check: Any use of 'getpwd' is insecure.
339*67e74705SXin Li // CWE-477: Use of Obsolete Functions
340*67e74705SXin Li //===----------------------------------------------------------------------===//
341*67e74705SXin Li 
checkCall_getpw(const CallExpr * CE,const FunctionDecl * FD)342*67e74705SXin Li void WalkAST::checkCall_getpw(const CallExpr *CE, const FunctionDecl *FD) {
343*67e74705SXin Li   if (!filter.check_getpw)
344*67e74705SXin Li     return;
345*67e74705SXin Li 
346*67e74705SXin Li   const FunctionProtoType *FPT = FD->getType()->getAs<FunctionProtoType>();
347*67e74705SXin Li   if (!FPT)
348*67e74705SXin Li     return;
349*67e74705SXin Li 
350*67e74705SXin Li   // Verify that the function takes two arguments.
351*67e74705SXin Li   if (FPT->getNumParams() != 2)
352*67e74705SXin Li     return;
353*67e74705SXin Li 
354*67e74705SXin Li   // Verify the first argument type is integer.
355*67e74705SXin Li   if (!FPT->getParamType(0)->isIntegralOrUnscopedEnumerationType())
356*67e74705SXin Li     return;
357*67e74705SXin Li 
358*67e74705SXin Li   // Verify the second argument type is char*.
359*67e74705SXin Li   const PointerType *PT = FPT->getParamType(1)->getAs<PointerType>();
360*67e74705SXin Li   if (!PT)
361*67e74705SXin Li     return;
362*67e74705SXin Li 
363*67e74705SXin Li   if (PT->getPointeeType().getUnqualifiedType() != BR.getContext().CharTy)
364*67e74705SXin Li     return;
365*67e74705SXin Li 
366*67e74705SXin Li   // Issue a warning.
367*67e74705SXin Li   PathDiagnosticLocation CELoc =
368*67e74705SXin Li     PathDiagnosticLocation::createBegin(CE, BR.getSourceManager(), AC);
369*67e74705SXin Li   BR.EmitBasicReport(AC->getDecl(), filter.checkName_getpw,
370*67e74705SXin Li                      "Potential buffer overflow in call to 'getpw'",
371*67e74705SXin Li                      "Security",
372*67e74705SXin Li                      "The getpw() function is dangerous as it may overflow the "
373*67e74705SXin Li                      "provided buffer. It is obsoleted by getpwuid().",
374*67e74705SXin Li                      CELoc, CE->getCallee()->getSourceRange());
375*67e74705SXin Li }
376*67e74705SXin Li 
377*67e74705SXin Li //===----------------------------------------------------------------------===//
378*67e74705SXin Li // Check: Any use of 'mktemp' is insecure.  It is obsoleted by mkstemp().
379*67e74705SXin Li // CWE-377: Insecure Temporary File
380*67e74705SXin Li //===----------------------------------------------------------------------===//
381*67e74705SXin Li 
checkCall_mktemp(const CallExpr * CE,const FunctionDecl * FD)382*67e74705SXin Li void WalkAST::checkCall_mktemp(const CallExpr *CE, const FunctionDecl *FD) {
383*67e74705SXin Li   if (!filter.check_mktemp) {
384*67e74705SXin Li     // Fall back to the security check of looking for enough 'X's in the
385*67e74705SXin Li     // format string, since that is a less severe warning.
386*67e74705SXin Li     checkCall_mkstemp(CE, FD);
387*67e74705SXin Li     return;
388*67e74705SXin Li   }
389*67e74705SXin Li 
390*67e74705SXin Li   const FunctionProtoType *FPT = FD->getType()->getAs<FunctionProtoType>();
391*67e74705SXin Li   if(!FPT)
392*67e74705SXin Li     return;
393*67e74705SXin Li 
394*67e74705SXin Li   // Verify that the function takes a single argument.
395*67e74705SXin Li   if (FPT->getNumParams() != 1)
396*67e74705SXin Li     return;
397*67e74705SXin Li 
398*67e74705SXin Li   // Verify that the argument is Pointer Type.
399*67e74705SXin Li   const PointerType *PT = FPT->getParamType(0)->getAs<PointerType>();
400*67e74705SXin Li   if (!PT)
401*67e74705SXin Li     return;
402*67e74705SXin Li 
403*67e74705SXin Li   // Verify that the argument is a 'char*'.
404*67e74705SXin Li   if (PT->getPointeeType().getUnqualifiedType() != BR.getContext().CharTy)
405*67e74705SXin Li     return;
406*67e74705SXin Li 
407*67e74705SXin Li   // Issue a warning.
408*67e74705SXin Li   PathDiagnosticLocation CELoc =
409*67e74705SXin Li     PathDiagnosticLocation::createBegin(CE, BR.getSourceManager(), AC);
410*67e74705SXin Li   BR.EmitBasicReport(AC->getDecl(), filter.checkName_mktemp,
411*67e74705SXin Li                      "Potential insecure temporary file in call 'mktemp'",
412*67e74705SXin Li                      "Security",
413*67e74705SXin Li                      "Call to function 'mktemp' is insecure as it always "
414*67e74705SXin Li                      "creates or uses insecure temporary file.  Use 'mkstemp' "
415*67e74705SXin Li                      "instead",
416*67e74705SXin Li                      CELoc, CE->getCallee()->getSourceRange());
417*67e74705SXin Li }
418*67e74705SXin Li 
419*67e74705SXin Li 
420*67e74705SXin Li //===----------------------------------------------------------------------===//
421*67e74705SXin Li // Check: Use of 'mkstemp', 'mktemp', 'mkdtemp' should contain at least 6 X's.
422*67e74705SXin Li //===----------------------------------------------------------------------===//
423*67e74705SXin Li 
checkCall_mkstemp(const CallExpr * CE,const FunctionDecl * FD)424*67e74705SXin Li void WalkAST::checkCall_mkstemp(const CallExpr *CE, const FunctionDecl *FD) {
425*67e74705SXin Li   if (!filter.check_mkstemp)
426*67e74705SXin Li     return;
427*67e74705SXin Li 
428*67e74705SXin Li   StringRef Name = FD->getIdentifier()->getName();
429*67e74705SXin Li   std::pair<signed, signed> ArgSuffix =
430*67e74705SXin Li     llvm::StringSwitch<std::pair<signed, signed> >(Name)
431*67e74705SXin Li       .Case("mktemp", std::make_pair(0,-1))
432*67e74705SXin Li       .Case("mkstemp", std::make_pair(0,-1))
433*67e74705SXin Li       .Case("mkdtemp", std::make_pair(0,-1))
434*67e74705SXin Li       .Case("mkstemps", std::make_pair(0,1))
435*67e74705SXin Li       .Default(std::make_pair(-1, -1));
436*67e74705SXin Li 
437*67e74705SXin Li   assert(ArgSuffix.first >= 0 && "Unsupported function");
438*67e74705SXin Li 
439*67e74705SXin Li   // Check if the number of arguments is consistent with out expectations.
440*67e74705SXin Li   unsigned numArgs = CE->getNumArgs();
441*67e74705SXin Li   if ((signed) numArgs <= ArgSuffix.first)
442*67e74705SXin Li     return;
443*67e74705SXin Li 
444*67e74705SXin Li   const StringLiteral *strArg =
445*67e74705SXin Li     dyn_cast<StringLiteral>(CE->getArg((unsigned)ArgSuffix.first)
446*67e74705SXin Li                               ->IgnoreParenImpCasts());
447*67e74705SXin Li 
448*67e74705SXin Li   // Currently we only handle string literals.  It is possible to do better,
449*67e74705SXin Li   // either by looking at references to const variables, or by doing real
450*67e74705SXin Li   // flow analysis.
451*67e74705SXin Li   if (!strArg || strArg->getCharByteWidth() != 1)
452*67e74705SXin Li     return;
453*67e74705SXin Li 
454*67e74705SXin Li   // Count the number of X's, taking into account a possible cutoff suffix.
455*67e74705SXin Li   StringRef str = strArg->getString();
456*67e74705SXin Li   unsigned numX = 0;
457*67e74705SXin Li   unsigned n = str.size();
458*67e74705SXin Li 
459*67e74705SXin Li   // Take into account the suffix.
460*67e74705SXin Li   unsigned suffix = 0;
461*67e74705SXin Li   if (ArgSuffix.second >= 0) {
462*67e74705SXin Li     const Expr *suffixEx = CE->getArg((unsigned)ArgSuffix.second);
463*67e74705SXin Li     llvm::APSInt Result;
464*67e74705SXin Li     if (!suffixEx->EvaluateAsInt(Result, BR.getContext()))
465*67e74705SXin Li       return;
466*67e74705SXin Li     // FIXME: Issue a warning.
467*67e74705SXin Li     if (Result.isNegative())
468*67e74705SXin Li       return;
469*67e74705SXin Li     suffix = (unsigned) Result.getZExtValue();
470*67e74705SXin Li     n = (n > suffix) ? n - suffix : 0;
471*67e74705SXin Li   }
472*67e74705SXin Li 
473*67e74705SXin Li   for (unsigned i = 0; i < n; ++i)
474*67e74705SXin Li     if (str[i] == 'X') ++numX;
475*67e74705SXin Li 
476*67e74705SXin Li   if (numX >= 6)
477*67e74705SXin Li     return;
478*67e74705SXin Li 
479*67e74705SXin Li   // Issue a warning.
480*67e74705SXin Li   PathDiagnosticLocation CELoc =
481*67e74705SXin Li     PathDiagnosticLocation::createBegin(CE, BR.getSourceManager(), AC);
482*67e74705SXin Li   SmallString<512> buf;
483*67e74705SXin Li   llvm::raw_svector_ostream out(buf);
484*67e74705SXin Li   out << "Call to '" << Name << "' should have at least 6 'X's in the"
485*67e74705SXin Li     " format string to be secure (" << numX << " 'X'";
486*67e74705SXin Li   if (numX != 1)
487*67e74705SXin Li     out << 's';
488*67e74705SXin Li   out << " seen";
489*67e74705SXin Li   if (suffix) {
490*67e74705SXin Li     out << ", " << suffix << " character";
491*67e74705SXin Li     if (suffix > 1)
492*67e74705SXin Li       out << 's';
493*67e74705SXin Li     out << " used as a suffix";
494*67e74705SXin Li   }
495*67e74705SXin Li   out << ')';
496*67e74705SXin Li   BR.EmitBasicReport(AC->getDecl(), filter.checkName_mkstemp,
497*67e74705SXin Li                      "Insecure temporary file creation", "Security",
498*67e74705SXin Li                      out.str(), CELoc, strArg->getSourceRange());
499*67e74705SXin Li }
500*67e74705SXin Li 
501*67e74705SXin Li //===----------------------------------------------------------------------===//
502*67e74705SXin Li // Check: Any use of 'strcpy' is insecure.
503*67e74705SXin Li //
504*67e74705SXin Li // CWE-119: Improper Restriction of Operations within
505*67e74705SXin Li // the Bounds of a Memory Buffer
506*67e74705SXin Li //===----------------------------------------------------------------------===//
checkCall_strcpy(const CallExpr * CE,const FunctionDecl * FD)507*67e74705SXin Li void WalkAST::checkCall_strcpy(const CallExpr *CE, const FunctionDecl *FD) {
508*67e74705SXin Li   if (!filter.check_strcpy)
509*67e74705SXin Li     return;
510*67e74705SXin Li 
511*67e74705SXin Li   if (!checkCall_strCommon(CE, FD))
512*67e74705SXin Li     return;
513*67e74705SXin Li 
514*67e74705SXin Li   // Issue a warning.
515*67e74705SXin Li   PathDiagnosticLocation CELoc =
516*67e74705SXin Li     PathDiagnosticLocation::createBegin(CE, BR.getSourceManager(), AC);
517*67e74705SXin Li   BR.EmitBasicReport(AC->getDecl(), filter.checkName_strcpy,
518*67e74705SXin Li                      "Potential insecure memory buffer bounds restriction in "
519*67e74705SXin Li                      "call 'strcpy'",
520*67e74705SXin Li                      "Security",
521*67e74705SXin Li                      "Call to function 'strcpy' is insecure as it does not "
522*67e74705SXin Li                      "provide bounding of the memory buffer. Replace "
523*67e74705SXin Li                      "unbounded copy functions with analogous functions that "
524*67e74705SXin Li                      "support length arguments such as 'strlcpy'. CWE-119.",
525*67e74705SXin Li                      CELoc, CE->getCallee()->getSourceRange());
526*67e74705SXin Li }
527*67e74705SXin Li 
528*67e74705SXin Li //===----------------------------------------------------------------------===//
529*67e74705SXin Li // Check: Any use of 'strcat' is insecure.
530*67e74705SXin Li //
531*67e74705SXin Li // CWE-119: Improper Restriction of Operations within
532*67e74705SXin Li // the Bounds of a Memory Buffer
533*67e74705SXin Li //===----------------------------------------------------------------------===//
checkCall_strcat(const CallExpr * CE,const FunctionDecl * FD)534*67e74705SXin Li void WalkAST::checkCall_strcat(const CallExpr *CE, const FunctionDecl *FD) {
535*67e74705SXin Li   if (!filter.check_strcpy)
536*67e74705SXin Li     return;
537*67e74705SXin Li 
538*67e74705SXin Li   if (!checkCall_strCommon(CE, FD))
539*67e74705SXin Li     return;
540*67e74705SXin Li 
541*67e74705SXin Li   // Issue a warning.
542*67e74705SXin Li   PathDiagnosticLocation CELoc =
543*67e74705SXin Li     PathDiagnosticLocation::createBegin(CE, BR.getSourceManager(), AC);
544*67e74705SXin Li   BR.EmitBasicReport(AC->getDecl(), filter.checkName_strcpy,
545*67e74705SXin Li                      "Potential insecure memory buffer bounds restriction in "
546*67e74705SXin Li                      "call 'strcat'",
547*67e74705SXin Li                      "Security",
548*67e74705SXin Li                      "Call to function 'strcat' is insecure as it does not "
549*67e74705SXin Li                      "provide bounding of the memory buffer. Replace "
550*67e74705SXin Li                      "unbounded copy functions with analogous functions that "
551*67e74705SXin Li                      "support length arguments such as 'strlcat'. CWE-119.",
552*67e74705SXin Li                      CELoc, CE->getCallee()->getSourceRange());
553*67e74705SXin Li }
554*67e74705SXin Li 
555*67e74705SXin Li //===----------------------------------------------------------------------===//
556*67e74705SXin Li // Common check for str* functions with no bounds parameters.
557*67e74705SXin Li //===----------------------------------------------------------------------===//
checkCall_strCommon(const CallExpr * CE,const FunctionDecl * FD)558*67e74705SXin Li bool WalkAST::checkCall_strCommon(const CallExpr *CE, const FunctionDecl *FD) {
559*67e74705SXin Li   const FunctionProtoType *FPT = FD->getType()->getAs<FunctionProtoType>();
560*67e74705SXin Li   if (!FPT)
561*67e74705SXin Li     return false;
562*67e74705SXin Li 
563*67e74705SXin Li   // Verify the function takes two arguments, three in the _chk version.
564*67e74705SXin Li   int numArgs = FPT->getNumParams();
565*67e74705SXin Li   if (numArgs != 2 && numArgs != 3)
566*67e74705SXin Li     return false;
567*67e74705SXin Li 
568*67e74705SXin Li   // Verify the type for both arguments.
569*67e74705SXin Li   for (int i = 0; i < 2; i++) {
570*67e74705SXin Li     // Verify that the arguments are pointers.
571*67e74705SXin Li     const PointerType *PT = FPT->getParamType(i)->getAs<PointerType>();
572*67e74705SXin Li     if (!PT)
573*67e74705SXin Li       return false;
574*67e74705SXin Li 
575*67e74705SXin Li     // Verify that the argument is a 'char*'.
576*67e74705SXin Li     if (PT->getPointeeType().getUnqualifiedType() != BR.getContext().CharTy)
577*67e74705SXin Li       return false;
578*67e74705SXin Li   }
579*67e74705SXin Li 
580*67e74705SXin Li   return true;
581*67e74705SXin Li }
582*67e74705SXin Li 
583*67e74705SXin Li //===----------------------------------------------------------------------===//
584*67e74705SXin Li // Check: Linear congruent random number generators should not be used
585*67e74705SXin Li // Originally: <rdar://problem/63371000>
586*67e74705SXin Li // CWE-338: Use of cryptographically weak prng
587*67e74705SXin Li //===----------------------------------------------------------------------===//
588*67e74705SXin Li 
checkCall_rand(const CallExpr * CE,const FunctionDecl * FD)589*67e74705SXin Li void WalkAST::checkCall_rand(const CallExpr *CE, const FunctionDecl *FD) {
590*67e74705SXin Li   if (!filter.check_rand || !CheckRand)
591*67e74705SXin Li     return;
592*67e74705SXin Li 
593*67e74705SXin Li   const FunctionProtoType *FTP = FD->getType()->getAs<FunctionProtoType>();
594*67e74705SXin Li   if (!FTP)
595*67e74705SXin Li     return;
596*67e74705SXin Li 
597*67e74705SXin Li   if (FTP->getNumParams() == 1) {
598*67e74705SXin Li     // Is the argument an 'unsigned short *'?
599*67e74705SXin Li     // (Actually any integer type is allowed.)
600*67e74705SXin Li     const PointerType *PT = FTP->getParamType(0)->getAs<PointerType>();
601*67e74705SXin Li     if (!PT)
602*67e74705SXin Li       return;
603*67e74705SXin Li 
604*67e74705SXin Li     if (! PT->getPointeeType()->isIntegralOrUnscopedEnumerationType())
605*67e74705SXin Li       return;
606*67e74705SXin Li   } else if (FTP->getNumParams() != 0)
607*67e74705SXin Li     return;
608*67e74705SXin Li 
609*67e74705SXin Li   // Issue a warning.
610*67e74705SXin Li   SmallString<256> buf1;
611*67e74705SXin Li   llvm::raw_svector_ostream os1(buf1);
612*67e74705SXin Li   os1 << '\'' << *FD << "' is a poor random number generator";
613*67e74705SXin Li 
614*67e74705SXin Li   SmallString<256> buf2;
615*67e74705SXin Li   llvm::raw_svector_ostream os2(buf2);
616*67e74705SXin Li   os2 << "Function '" << *FD
617*67e74705SXin Li       << "' is obsolete because it implements a poor random number generator."
618*67e74705SXin Li       << "  Use 'arc4random' instead";
619*67e74705SXin Li 
620*67e74705SXin Li   PathDiagnosticLocation CELoc =
621*67e74705SXin Li     PathDiagnosticLocation::createBegin(CE, BR.getSourceManager(), AC);
622*67e74705SXin Li   BR.EmitBasicReport(AC->getDecl(), filter.checkName_rand, os1.str(),
623*67e74705SXin Li                      "Security", os2.str(), CELoc,
624*67e74705SXin Li                      CE->getCallee()->getSourceRange());
625*67e74705SXin Li }
626*67e74705SXin Li 
627*67e74705SXin Li //===----------------------------------------------------------------------===//
628*67e74705SXin Li // Check: 'random' should not be used
629*67e74705SXin Li // Originally: <rdar://problem/63371000>
630*67e74705SXin Li //===----------------------------------------------------------------------===//
631*67e74705SXin Li 
checkCall_random(const CallExpr * CE,const FunctionDecl * FD)632*67e74705SXin Li void WalkAST::checkCall_random(const CallExpr *CE, const FunctionDecl *FD) {
633*67e74705SXin Li   if (!CheckRand || !filter.check_rand)
634*67e74705SXin Li     return;
635*67e74705SXin Li 
636*67e74705SXin Li   const FunctionProtoType *FTP = FD->getType()->getAs<FunctionProtoType>();
637*67e74705SXin Li   if (!FTP)
638*67e74705SXin Li     return;
639*67e74705SXin Li 
640*67e74705SXin Li   // Verify that the function takes no argument.
641*67e74705SXin Li   if (FTP->getNumParams() != 0)
642*67e74705SXin Li     return;
643*67e74705SXin Li 
644*67e74705SXin Li   // Issue a warning.
645*67e74705SXin Li   PathDiagnosticLocation CELoc =
646*67e74705SXin Li     PathDiagnosticLocation::createBegin(CE, BR.getSourceManager(), AC);
647*67e74705SXin Li   BR.EmitBasicReport(AC->getDecl(), filter.checkName_rand,
648*67e74705SXin Li                      "'random' is not a secure random number generator",
649*67e74705SXin Li                      "Security",
650*67e74705SXin Li                      "The 'random' function produces a sequence of values that "
651*67e74705SXin Li                      "an adversary may be able to predict.  Use 'arc4random' "
652*67e74705SXin Li                      "instead", CELoc, CE->getCallee()->getSourceRange());
653*67e74705SXin Li }
654*67e74705SXin Li 
655*67e74705SXin Li //===----------------------------------------------------------------------===//
656*67e74705SXin Li // Check: 'vfork' should not be used.
657*67e74705SXin Li // POS33-C: Do not use vfork().
658*67e74705SXin Li //===----------------------------------------------------------------------===//
659*67e74705SXin Li 
checkCall_vfork(const CallExpr * CE,const FunctionDecl * FD)660*67e74705SXin Li void WalkAST::checkCall_vfork(const CallExpr *CE, const FunctionDecl *FD) {
661*67e74705SXin Li   if (!filter.check_vfork)
662*67e74705SXin Li     return;
663*67e74705SXin Li 
664*67e74705SXin Li   // All calls to vfork() are insecure, issue a warning.
665*67e74705SXin Li   PathDiagnosticLocation CELoc =
666*67e74705SXin Li     PathDiagnosticLocation::createBegin(CE, BR.getSourceManager(), AC);
667*67e74705SXin Li   BR.EmitBasicReport(AC->getDecl(), filter.checkName_vfork,
668*67e74705SXin Li                      "Potential insecure implementation-specific behavior in "
669*67e74705SXin Li                      "call 'vfork'",
670*67e74705SXin Li                      "Security",
671*67e74705SXin Li                      "Call to function 'vfork' is insecure as it can lead to "
672*67e74705SXin Li                      "denial of service situations in the parent process. "
673*67e74705SXin Li                      "Replace calls to vfork with calls to the safer "
674*67e74705SXin Li                      "'posix_spawn' function",
675*67e74705SXin Li                      CELoc, CE->getCallee()->getSourceRange());
676*67e74705SXin Li }
677*67e74705SXin Li 
678*67e74705SXin Li //===----------------------------------------------------------------------===//
679*67e74705SXin Li // Check: Should check whether privileges are dropped successfully.
680*67e74705SXin Li // Originally: <rdar://problem/6337132>
681*67e74705SXin Li //===----------------------------------------------------------------------===//
682*67e74705SXin Li 
checkUncheckedReturnValue(CallExpr * CE)683*67e74705SXin Li void WalkAST::checkUncheckedReturnValue(CallExpr *CE) {
684*67e74705SXin Li   if (!filter.check_UncheckedReturn)
685*67e74705SXin Li     return;
686*67e74705SXin Li 
687*67e74705SXin Li   const FunctionDecl *FD = CE->getDirectCallee();
688*67e74705SXin Li   if (!FD)
689*67e74705SXin Li     return;
690*67e74705SXin Li 
691*67e74705SXin Li   if (II_setid[0] == nullptr) {
692*67e74705SXin Li     static const char * const identifiers[num_setids] = {
693*67e74705SXin Li       "setuid", "setgid", "seteuid", "setegid",
694*67e74705SXin Li       "setreuid", "setregid"
695*67e74705SXin Li     };
696*67e74705SXin Li 
697*67e74705SXin Li     for (size_t i = 0; i < num_setids; i++)
698*67e74705SXin Li       II_setid[i] = &BR.getContext().Idents.get(identifiers[i]);
699*67e74705SXin Li   }
700*67e74705SXin Li 
701*67e74705SXin Li   const IdentifierInfo *id = FD->getIdentifier();
702*67e74705SXin Li   size_t identifierid;
703*67e74705SXin Li 
704*67e74705SXin Li   for (identifierid = 0; identifierid < num_setids; identifierid++)
705*67e74705SXin Li     if (id == II_setid[identifierid])
706*67e74705SXin Li       break;
707*67e74705SXin Li 
708*67e74705SXin Li   if (identifierid >= num_setids)
709*67e74705SXin Li     return;
710*67e74705SXin Li 
711*67e74705SXin Li   const FunctionProtoType *FTP = FD->getType()->getAs<FunctionProtoType>();
712*67e74705SXin Li   if (!FTP)
713*67e74705SXin Li     return;
714*67e74705SXin Li 
715*67e74705SXin Li   // Verify that the function takes one or two arguments (depending on
716*67e74705SXin Li   //   the function).
717*67e74705SXin Li   if (FTP->getNumParams() != (identifierid < 4 ? 1 : 2))
718*67e74705SXin Li     return;
719*67e74705SXin Li 
720*67e74705SXin Li   // The arguments must be integers.
721*67e74705SXin Li   for (unsigned i = 0; i < FTP->getNumParams(); i++)
722*67e74705SXin Li     if (!FTP->getParamType(i)->isIntegralOrUnscopedEnumerationType())
723*67e74705SXin Li       return;
724*67e74705SXin Li 
725*67e74705SXin Li   // Issue a warning.
726*67e74705SXin Li   SmallString<256> buf1;
727*67e74705SXin Li   llvm::raw_svector_ostream os1(buf1);
728*67e74705SXin Li   os1 << "Return value is not checked in call to '" << *FD << '\'';
729*67e74705SXin Li 
730*67e74705SXin Li   SmallString<256> buf2;
731*67e74705SXin Li   llvm::raw_svector_ostream os2(buf2);
732*67e74705SXin Li   os2 << "The return value from the call to '" << *FD
733*67e74705SXin Li       << "' is not checked.  If an error occurs in '" << *FD
734*67e74705SXin Li       << "', the following code may execute with unexpected privileges";
735*67e74705SXin Li 
736*67e74705SXin Li   PathDiagnosticLocation CELoc =
737*67e74705SXin Li     PathDiagnosticLocation::createBegin(CE, BR.getSourceManager(), AC);
738*67e74705SXin Li   BR.EmitBasicReport(AC->getDecl(), filter.checkName_UncheckedReturn, os1.str(),
739*67e74705SXin Li                      "Security", os2.str(), CELoc,
740*67e74705SXin Li                      CE->getCallee()->getSourceRange());
741*67e74705SXin Li }
742*67e74705SXin Li 
743*67e74705SXin Li //===----------------------------------------------------------------------===//
744*67e74705SXin Li // SecuritySyntaxChecker
745*67e74705SXin Li //===----------------------------------------------------------------------===//
746*67e74705SXin Li 
747*67e74705SXin Li namespace {
748*67e74705SXin Li class SecuritySyntaxChecker : public Checker<check::ASTCodeBody> {
749*67e74705SXin Li public:
750*67e74705SXin Li   ChecksFilter filter;
751*67e74705SXin Li 
checkASTCodeBody(const Decl * D,AnalysisManager & mgr,BugReporter & BR) const752*67e74705SXin Li   void checkASTCodeBody(const Decl *D, AnalysisManager& mgr,
753*67e74705SXin Li                         BugReporter &BR) const {
754*67e74705SXin Li     WalkAST walker(BR, mgr.getAnalysisDeclContext(D), filter);
755*67e74705SXin Li     walker.Visit(D->getBody());
756*67e74705SXin Li   }
757*67e74705SXin Li };
758*67e74705SXin Li }
759*67e74705SXin Li 
760*67e74705SXin Li #define REGISTER_CHECKER(name)                                                 \
761*67e74705SXin Li   void ento::register##name(CheckerManager &mgr) {                             \
762*67e74705SXin Li     SecuritySyntaxChecker *checker =                                           \
763*67e74705SXin Li         mgr.registerChecker<SecuritySyntaxChecker>();                          \
764*67e74705SXin Li     checker->filter.check_##name = true;                                       \
765*67e74705SXin Li     checker->filter.checkName_##name = mgr.getCurrentCheckName();              \
766*67e74705SXin Li   }
767*67e74705SXin Li 
768*67e74705SXin Li REGISTER_CHECKER(gets)
769*67e74705SXin Li REGISTER_CHECKER(getpw)
770*67e74705SXin Li REGISTER_CHECKER(mkstemp)
771*67e74705SXin Li REGISTER_CHECKER(mktemp)
772*67e74705SXin Li REGISTER_CHECKER(strcpy)
773*67e74705SXin Li REGISTER_CHECKER(rand)
774*67e74705SXin Li REGISTER_CHECKER(vfork)
775*67e74705SXin Li REGISTER_CHECKER(FloatLoopCounter)
776*67e74705SXin Li REGISTER_CHECKER(UncheckedReturn)
777*67e74705SXin Li 
778*67e74705SXin Li 
779