xref: /openbsd-src/gnu/llvm/clang/lib/StaticAnalyzer/Checkers/CheckSecuritySyntaxOnly.cpp (revision 12c855180aad702bbcca06e0398d774beeafb155)
1e5dd7070Spatrick //==- CheckSecuritySyntaxOnly.cpp - Basic security checks --------*- C++ -*-==//
2e5dd7070Spatrick //
3e5dd7070Spatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4e5dd7070Spatrick // See https://llvm.org/LICENSE.txt for license information.
5e5dd7070Spatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6e5dd7070Spatrick //
7e5dd7070Spatrick //===----------------------------------------------------------------------===//
8e5dd7070Spatrick //
9e5dd7070Spatrick //  This file defines a set of flow-insensitive security checks.
10e5dd7070Spatrick //
11e5dd7070Spatrick //===----------------------------------------------------------------------===//
12e5dd7070Spatrick 
13e5dd7070Spatrick #include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h"
14e5dd7070Spatrick #include "clang/AST/StmtVisitor.h"
15e5dd7070Spatrick #include "clang/Analysis/AnalysisDeclContext.h"
16e5dd7070Spatrick #include "clang/Basic/TargetInfo.h"
17e5dd7070Spatrick #include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h"
18e5dd7070Spatrick #include "clang/StaticAnalyzer/Core/Checker.h"
19e5dd7070Spatrick #include "clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h"
20e5dd7070Spatrick #include "llvm/ADT/SmallString.h"
21e5dd7070Spatrick #include "llvm/ADT/StringSwitch.h"
22e5dd7070Spatrick #include "llvm/Support/raw_ostream.h"
23e5dd7070Spatrick 
24e5dd7070Spatrick using namespace clang;
25e5dd7070Spatrick using namespace ento;
26e5dd7070Spatrick 
isArc4RandomAvailable(const ASTContext & Ctx)27e5dd7070Spatrick static bool isArc4RandomAvailable(const ASTContext &Ctx) {
28e5dd7070Spatrick   const llvm::Triple &T = Ctx.getTargetInfo().getTriple();
29e5dd7070Spatrick   return T.getVendor() == llvm::Triple::Apple ||
30e5dd7070Spatrick          T.getOS() == llvm::Triple::CloudABI ||
31e5dd7070Spatrick          T.isOSFreeBSD() ||
32e5dd7070Spatrick          T.isOSNetBSD() ||
33e5dd7070Spatrick          T.isOSOpenBSD() ||
34e5dd7070Spatrick          T.isOSDragonFly();
35e5dd7070Spatrick }
36e5dd7070Spatrick 
37e5dd7070Spatrick namespace {
38e5dd7070Spatrick struct ChecksFilter {
39*12c85518Srobert   bool check_bcmp = false;
40*12c85518Srobert   bool check_bcopy = false;
41*12c85518Srobert   bool check_bzero = false;
42*12c85518Srobert   bool check_gets = false;
43*12c85518Srobert   bool check_getpw = false;
44*12c85518Srobert   bool check_mktemp = false;
45*12c85518Srobert   bool check_mkstemp = false;
46*12c85518Srobert   bool check_strcpy = false;
47*12c85518Srobert   bool check_DeprecatedOrUnsafeBufferHandling = false;
48*12c85518Srobert   bool check_rand = false;
49*12c85518Srobert   bool check_vfork = false;
50*12c85518Srobert   bool check_FloatLoopCounter = false;
51*12c85518Srobert   bool check_UncheckedReturn = false;
52*12c85518Srobert   bool check_decodeValueOfObjCType = false;
53e5dd7070Spatrick 
54e5dd7070Spatrick   CheckerNameRef checkName_bcmp;
55e5dd7070Spatrick   CheckerNameRef checkName_bcopy;
56e5dd7070Spatrick   CheckerNameRef checkName_bzero;
57e5dd7070Spatrick   CheckerNameRef checkName_gets;
58e5dd7070Spatrick   CheckerNameRef checkName_getpw;
59e5dd7070Spatrick   CheckerNameRef checkName_mktemp;
60e5dd7070Spatrick   CheckerNameRef checkName_mkstemp;
61e5dd7070Spatrick   CheckerNameRef checkName_strcpy;
62e5dd7070Spatrick   CheckerNameRef checkName_DeprecatedOrUnsafeBufferHandling;
63e5dd7070Spatrick   CheckerNameRef checkName_rand;
64e5dd7070Spatrick   CheckerNameRef checkName_vfork;
65e5dd7070Spatrick   CheckerNameRef checkName_FloatLoopCounter;
66e5dd7070Spatrick   CheckerNameRef checkName_UncheckedReturn;
67e5dd7070Spatrick   CheckerNameRef checkName_decodeValueOfObjCType;
68e5dd7070Spatrick };
69e5dd7070Spatrick 
70e5dd7070Spatrick class WalkAST : public StmtVisitor<WalkAST> {
71e5dd7070Spatrick   BugReporter &BR;
72e5dd7070Spatrick   AnalysisDeclContext* AC;
73e5dd7070Spatrick   enum { num_setids = 6 };
74e5dd7070Spatrick   IdentifierInfo *II_setid[num_setids];
75e5dd7070Spatrick 
76e5dd7070Spatrick   const bool CheckRand;
77e5dd7070Spatrick   const ChecksFilter &filter;
78e5dd7070Spatrick 
79e5dd7070Spatrick public:
WalkAST(BugReporter & br,AnalysisDeclContext * ac,const ChecksFilter & f)80e5dd7070Spatrick   WalkAST(BugReporter &br, AnalysisDeclContext* ac,
81e5dd7070Spatrick           const ChecksFilter &f)
82e5dd7070Spatrick   : BR(br), AC(ac), II_setid(),
83e5dd7070Spatrick     CheckRand(isArc4RandomAvailable(BR.getContext())),
84e5dd7070Spatrick     filter(f) {}
85e5dd7070Spatrick 
86e5dd7070Spatrick   // Statement visitor methods.
87e5dd7070Spatrick   void VisitCallExpr(CallExpr *CE);
88e5dd7070Spatrick   void VisitObjCMessageExpr(ObjCMessageExpr *CE);
89e5dd7070Spatrick   void VisitForStmt(ForStmt *S);
90e5dd7070Spatrick   void VisitCompoundStmt (CompoundStmt *S);
VisitStmt(Stmt * S)91e5dd7070Spatrick   void VisitStmt(Stmt *S) { VisitChildren(S); }
92e5dd7070Spatrick 
93e5dd7070Spatrick   void VisitChildren(Stmt *S);
94e5dd7070Spatrick 
95e5dd7070Spatrick   // Helpers.
96e5dd7070Spatrick   bool checkCall_strCommon(const CallExpr *CE, const FunctionDecl *FD);
97e5dd7070Spatrick 
98e5dd7070Spatrick   typedef void (WalkAST::*FnCheck)(const CallExpr *, const FunctionDecl *);
99e5dd7070Spatrick   typedef void (WalkAST::*MsgCheck)(const ObjCMessageExpr *);
100e5dd7070Spatrick 
101e5dd7070Spatrick   // Checker-specific methods.
102e5dd7070Spatrick   void checkLoopConditionForFloat(const ForStmt *FS);
103e5dd7070Spatrick   void checkCall_bcmp(const CallExpr *CE, const FunctionDecl *FD);
104e5dd7070Spatrick   void checkCall_bcopy(const CallExpr *CE, const FunctionDecl *FD);
105e5dd7070Spatrick   void checkCall_bzero(const CallExpr *CE, const FunctionDecl *FD);
106e5dd7070Spatrick   void checkCall_gets(const CallExpr *CE, const FunctionDecl *FD);
107e5dd7070Spatrick   void checkCall_getpw(const CallExpr *CE, const FunctionDecl *FD);
108e5dd7070Spatrick   void checkCall_mktemp(const CallExpr *CE, const FunctionDecl *FD);
109e5dd7070Spatrick   void checkCall_mkstemp(const CallExpr *CE, const FunctionDecl *FD);
110e5dd7070Spatrick   void checkCall_strcpy(const CallExpr *CE, const FunctionDecl *FD);
111e5dd7070Spatrick   void checkCall_strcat(const CallExpr *CE, const FunctionDecl *FD);
112e5dd7070Spatrick   void checkDeprecatedOrUnsafeBufferHandling(const CallExpr *CE,
113e5dd7070Spatrick                                              const FunctionDecl *FD);
114e5dd7070Spatrick   void checkCall_rand(const CallExpr *CE, const FunctionDecl *FD);
115e5dd7070Spatrick   void checkCall_random(const CallExpr *CE, const FunctionDecl *FD);
116e5dd7070Spatrick   void checkCall_vfork(const CallExpr *CE, const FunctionDecl *FD);
117e5dd7070Spatrick   void checkMsg_decodeValueOfObjCType(const ObjCMessageExpr *ME);
118e5dd7070Spatrick   void checkUncheckedReturnValue(CallExpr *CE);
119e5dd7070Spatrick };
120e5dd7070Spatrick } // end anonymous namespace
121e5dd7070Spatrick 
122e5dd7070Spatrick //===----------------------------------------------------------------------===//
123e5dd7070Spatrick // AST walking.
124e5dd7070Spatrick //===----------------------------------------------------------------------===//
125e5dd7070Spatrick 
VisitChildren(Stmt * S)126e5dd7070Spatrick void WalkAST::VisitChildren(Stmt *S) {
127e5dd7070Spatrick   for (Stmt *Child : S->children())
128e5dd7070Spatrick     if (Child)
129e5dd7070Spatrick       Visit(Child);
130e5dd7070Spatrick }
131e5dd7070Spatrick 
VisitCallExpr(CallExpr * CE)132e5dd7070Spatrick void WalkAST::VisitCallExpr(CallExpr *CE) {
133e5dd7070Spatrick   // Get the callee.
134e5dd7070Spatrick   const FunctionDecl *FD = CE->getDirectCallee();
135e5dd7070Spatrick 
136e5dd7070Spatrick   if (!FD)
137e5dd7070Spatrick     return;
138e5dd7070Spatrick 
139e5dd7070Spatrick   // Get the name of the callee. If it's a builtin, strip off the prefix.
140e5dd7070Spatrick   IdentifierInfo *II = FD->getIdentifier();
141e5dd7070Spatrick   if (!II)   // if no identifier, not a simple C function
142e5dd7070Spatrick     return;
143e5dd7070Spatrick   StringRef Name = II->getName();
144e5dd7070Spatrick   if (Name.startswith("__builtin_"))
145e5dd7070Spatrick     Name = Name.substr(10);
146e5dd7070Spatrick 
147e5dd7070Spatrick   // Set the evaluation function by switching on the callee name.
148e5dd7070Spatrick   FnCheck evalFunction = llvm::StringSwitch<FnCheck>(Name)
149e5dd7070Spatrick     .Case("bcmp", &WalkAST::checkCall_bcmp)
150e5dd7070Spatrick     .Case("bcopy", &WalkAST::checkCall_bcopy)
151e5dd7070Spatrick     .Case("bzero", &WalkAST::checkCall_bzero)
152e5dd7070Spatrick     .Case("gets", &WalkAST::checkCall_gets)
153e5dd7070Spatrick     .Case("getpw", &WalkAST::checkCall_getpw)
154e5dd7070Spatrick     .Case("mktemp", &WalkAST::checkCall_mktemp)
155e5dd7070Spatrick     .Case("mkstemp", &WalkAST::checkCall_mkstemp)
156e5dd7070Spatrick     .Case("mkdtemp", &WalkAST::checkCall_mkstemp)
157e5dd7070Spatrick     .Case("mkstemps", &WalkAST::checkCall_mkstemp)
158e5dd7070Spatrick     .Cases("strcpy", "__strcpy_chk", &WalkAST::checkCall_strcpy)
159e5dd7070Spatrick     .Cases("strcat", "__strcat_chk", &WalkAST::checkCall_strcat)
160e5dd7070Spatrick     .Cases("sprintf", "vsprintf", "scanf", "wscanf", "fscanf", "fwscanf",
161e5dd7070Spatrick            "vscanf", "vwscanf", "vfscanf", "vfwscanf",
162e5dd7070Spatrick            &WalkAST::checkDeprecatedOrUnsafeBufferHandling)
163e5dd7070Spatrick     .Cases("sscanf", "swscanf", "vsscanf", "vswscanf", "swprintf",
164e5dd7070Spatrick            "snprintf", "vswprintf", "vsnprintf", "memcpy", "memmove",
165e5dd7070Spatrick            &WalkAST::checkDeprecatedOrUnsafeBufferHandling)
166e5dd7070Spatrick     .Cases("strncpy", "strncat", "memset",
167e5dd7070Spatrick            &WalkAST::checkDeprecatedOrUnsafeBufferHandling)
168e5dd7070Spatrick     .Case("drand48", &WalkAST::checkCall_rand)
169e5dd7070Spatrick     .Case("erand48", &WalkAST::checkCall_rand)
170e5dd7070Spatrick     .Case("jrand48", &WalkAST::checkCall_rand)
171e5dd7070Spatrick     .Case("lrand48", &WalkAST::checkCall_rand)
172e5dd7070Spatrick     .Case("mrand48", &WalkAST::checkCall_rand)
173e5dd7070Spatrick     .Case("nrand48", &WalkAST::checkCall_rand)
174e5dd7070Spatrick     .Case("lcong48", &WalkAST::checkCall_rand)
175e5dd7070Spatrick     .Case("rand", &WalkAST::checkCall_rand)
176e5dd7070Spatrick     .Case("rand_r", &WalkAST::checkCall_rand)
177e5dd7070Spatrick     .Case("random", &WalkAST::checkCall_random)
178e5dd7070Spatrick     .Case("vfork", &WalkAST::checkCall_vfork)
179e5dd7070Spatrick     .Default(nullptr);
180e5dd7070Spatrick 
181e5dd7070Spatrick   // If the callee isn't defined, it is not of security concern.
182e5dd7070Spatrick   // Check and evaluate the call.
183e5dd7070Spatrick   if (evalFunction)
184e5dd7070Spatrick     (this->*evalFunction)(CE, FD);
185e5dd7070Spatrick 
186e5dd7070Spatrick   // Recurse and check children.
187e5dd7070Spatrick   VisitChildren(CE);
188e5dd7070Spatrick }
189e5dd7070Spatrick 
VisitObjCMessageExpr(ObjCMessageExpr * ME)190e5dd7070Spatrick void WalkAST::VisitObjCMessageExpr(ObjCMessageExpr *ME) {
191e5dd7070Spatrick   MsgCheck evalFunction =
192e5dd7070Spatrick       llvm::StringSwitch<MsgCheck>(ME->getSelector().getAsString())
193e5dd7070Spatrick           .Case("decodeValueOfObjCType:at:",
194e5dd7070Spatrick                 &WalkAST::checkMsg_decodeValueOfObjCType)
195e5dd7070Spatrick           .Default(nullptr);
196e5dd7070Spatrick 
197e5dd7070Spatrick   if (evalFunction)
198e5dd7070Spatrick     (this->*evalFunction)(ME);
199e5dd7070Spatrick 
200e5dd7070Spatrick   // Recurse and check children.
201e5dd7070Spatrick   VisitChildren(ME);
202e5dd7070Spatrick }
203e5dd7070Spatrick 
VisitCompoundStmt(CompoundStmt * S)204e5dd7070Spatrick void WalkAST::VisitCompoundStmt(CompoundStmt *S) {
205e5dd7070Spatrick   for (Stmt *Child : S->children())
206e5dd7070Spatrick     if (Child) {
207e5dd7070Spatrick       if (CallExpr *CE = dyn_cast<CallExpr>(Child))
208e5dd7070Spatrick         checkUncheckedReturnValue(CE);
209e5dd7070Spatrick       Visit(Child);
210e5dd7070Spatrick     }
211e5dd7070Spatrick }
212e5dd7070Spatrick 
VisitForStmt(ForStmt * FS)213e5dd7070Spatrick void WalkAST::VisitForStmt(ForStmt *FS) {
214e5dd7070Spatrick   checkLoopConditionForFloat(FS);
215e5dd7070Spatrick 
216e5dd7070Spatrick   // Recurse and check children.
217e5dd7070Spatrick   VisitChildren(FS);
218e5dd7070Spatrick }
219e5dd7070Spatrick 
220e5dd7070Spatrick //===----------------------------------------------------------------------===//
221e5dd7070Spatrick // Check: floating point variable used as loop counter.
222e5dd7070Spatrick // Originally: <rdar://problem/6336718>
223e5dd7070Spatrick // Implements: CERT security coding advisory FLP-30.
224e5dd7070Spatrick //===----------------------------------------------------------------------===//
225e5dd7070Spatrick 
226e5dd7070Spatrick // Returns either 'x' or 'y', depending on which one of them is incremented
227e5dd7070Spatrick // in 'expr', or nullptr if none of them is incremented.
228e5dd7070Spatrick static const DeclRefExpr*
getIncrementedVar(const Expr * expr,const VarDecl * x,const VarDecl * y)229e5dd7070Spatrick getIncrementedVar(const Expr *expr, const VarDecl *x, const VarDecl *y) {
230e5dd7070Spatrick   expr = expr->IgnoreParenCasts();
231e5dd7070Spatrick 
232e5dd7070Spatrick   if (const BinaryOperator *B = dyn_cast<BinaryOperator>(expr)) {
233e5dd7070Spatrick     if (!(B->isAssignmentOp() || B->isCompoundAssignmentOp() ||
234e5dd7070Spatrick           B->getOpcode() == BO_Comma))
235e5dd7070Spatrick       return nullptr;
236e5dd7070Spatrick 
237e5dd7070Spatrick     if (const DeclRefExpr *lhs = getIncrementedVar(B->getLHS(), x, y))
238e5dd7070Spatrick       return lhs;
239e5dd7070Spatrick 
240e5dd7070Spatrick     if (const DeclRefExpr *rhs = getIncrementedVar(B->getRHS(), x, y))
241e5dd7070Spatrick       return rhs;
242e5dd7070Spatrick 
243e5dd7070Spatrick     return nullptr;
244e5dd7070Spatrick   }
245e5dd7070Spatrick 
246e5dd7070Spatrick   if (const DeclRefExpr *DR = dyn_cast<DeclRefExpr>(expr)) {
247e5dd7070Spatrick     const NamedDecl *ND = DR->getDecl();
248e5dd7070Spatrick     return ND == x || ND == y ? DR : nullptr;
249e5dd7070Spatrick   }
250e5dd7070Spatrick 
251e5dd7070Spatrick   if (const UnaryOperator *U = dyn_cast<UnaryOperator>(expr))
252e5dd7070Spatrick     return U->isIncrementDecrementOp()
253e5dd7070Spatrick       ? getIncrementedVar(U->getSubExpr(), x, y) : nullptr;
254e5dd7070Spatrick 
255e5dd7070Spatrick   return nullptr;
256e5dd7070Spatrick }
257e5dd7070Spatrick 
258e5dd7070Spatrick /// CheckLoopConditionForFloat - This check looks for 'for' statements that
259e5dd7070Spatrick ///  use a floating point variable as a loop counter.
260e5dd7070Spatrick ///  CERT: FLP30-C, FLP30-CPP.
261e5dd7070Spatrick ///
checkLoopConditionForFloat(const ForStmt * FS)262e5dd7070Spatrick void WalkAST::checkLoopConditionForFloat(const ForStmt *FS) {
263e5dd7070Spatrick   if (!filter.check_FloatLoopCounter)
264e5dd7070Spatrick     return;
265e5dd7070Spatrick 
266e5dd7070Spatrick   // Does the loop have a condition?
267e5dd7070Spatrick   const Expr *condition = FS->getCond();
268e5dd7070Spatrick 
269e5dd7070Spatrick   if (!condition)
270e5dd7070Spatrick     return;
271e5dd7070Spatrick 
272e5dd7070Spatrick   // Does the loop have an increment?
273e5dd7070Spatrick   const Expr *increment = FS->getInc();
274e5dd7070Spatrick 
275e5dd7070Spatrick   if (!increment)
276e5dd7070Spatrick     return;
277e5dd7070Spatrick 
278e5dd7070Spatrick   // Strip away '()' and casts.
279e5dd7070Spatrick   condition = condition->IgnoreParenCasts();
280e5dd7070Spatrick   increment = increment->IgnoreParenCasts();
281e5dd7070Spatrick 
282e5dd7070Spatrick   // Is the loop condition a comparison?
283e5dd7070Spatrick   const BinaryOperator *B = dyn_cast<BinaryOperator>(condition);
284e5dd7070Spatrick 
285e5dd7070Spatrick   if (!B)
286e5dd7070Spatrick     return;
287e5dd7070Spatrick 
288e5dd7070Spatrick   // Is this a comparison?
289e5dd7070Spatrick   if (!(B->isRelationalOp() || B->isEqualityOp()))
290e5dd7070Spatrick     return;
291e5dd7070Spatrick 
292e5dd7070Spatrick   // Are we comparing variables?
293e5dd7070Spatrick   const DeclRefExpr *drLHS =
294e5dd7070Spatrick     dyn_cast<DeclRefExpr>(B->getLHS()->IgnoreParenLValueCasts());
295e5dd7070Spatrick   const DeclRefExpr *drRHS =
296e5dd7070Spatrick     dyn_cast<DeclRefExpr>(B->getRHS()->IgnoreParenLValueCasts());
297e5dd7070Spatrick 
298e5dd7070Spatrick   // Does at least one of the variables have a floating point type?
299e5dd7070Spatrick   drLHS = drLHS && drLHS->getType()->isRealFloatingType() ? drLHS : nullptr;
300e5dd7070Spatrick   drRHS = drRHS && drRHS->getType()->isRealFloatingType() ? drRHS : nullptr;
301e5dd7070Spatrick 
302e5dd7070Spatrick   if (!drLHS && !drRHS)
303e5dd7070Spatrick     return;
304e5dd7070Spatrick 
305e5dd7070Spatrick   const VarDecl *vdLHS = drLHS ? dyn_cast<VarDecl>(drLHS->getDecl()) : nullptr;
306e5dd7070Spatrick   const VarDecl *vdRHS = drRHS ? dyn_cast<VarDecl>(drRHS->getDecl()) : nullptr;
307e5dd7070Spatrick 
308e5dd7070Spatrick   if (!vdLHS && !vdRHS)
309e5dd7070Spatrick     return;
310e5dd7070Spatrick 
311e5dd7070Spatrick   // Does either variable appear in increment?
312e5dd7070Spatrick   const DeclRefExpr *drInc = getIncrementedVar(increment, vdLHS, vdRHS);
313e5dd7070Spatrick   if (!drInc)
314e5dd7070Spatrick     return;
315e5dd7070Spatrick 
316e5dd7070Spatrick   const VarDecl *vdInc = cast<VarDecl>(drInc->getDecl());
317e5dd7070Spatrick   assert(vdInc && (vdInc == vdLHS || vdInc == vdRHS));
318e5dd7070Spatrick 
319e5dd7070Spatrick   // Emit the error.  First figure out which DeclRefExpr in the condition
320e5dd7070Spatrick   // referenced the compared variable.
321e5dd7070Spatrick   const DeclRefExpr *drCond = vdLHS == vdInc ? drLHS : drRHS;
322e5dd7070Spatrick 
323e5dd7070Spatrick   SmallVector<SourceRange, 2> ranges;
324e5dd7070Spatrick   SmallString<256> sbuf;
325e5dd7070Spatrick   llvm::raw_svector_ostream os(sbuf);
326e5dd7070Spatrick 
327e5dd7070Spatrick   os << "Variable '" << drCond->getDecl()->getName()
328*12c85518Srobert      << "' with floating point type '" << drCond->getType()
329e5dd7070Spatrick      << "' should not be used as a loop counter";
330e5dd7070Spatrick 
331e5dd7070Spatrick   ranges.push_back(drCond->getSourceRange());
332e5dd7070Spatrick   ranges.push_back(drInc->getSourceRange());
333e5dd7070Spatrick 
334e5dd7070Spatrick   const char *bugType = "Floating point variable used as loop counter";
335e5dd7070Spatrick 
336e5dd7070Spatrick   PathDiagnosticLocation FSLoc =
337e5dd7070Spatrick     PathDiagnosticLocation::createBegin(FS, BR.getSourceManager(), AC);
338e5dd7070Spatrick   BR.EmitBasicReport(AC->getDecl(), filter.checkName_FloatLoopCounter,
339e5dd7070Spatrick                      bugType, "Security", os.str(),
340e5dd7070Spatrick                      FSLoc, ranges);
341e5dd7070Spatrick }
342e5dd7070Spatrick 
343e5dd7070Spatrick //===----------------------------------------------------------------------===//
344e5dd7070Spatrick // Check: Any use of bcmp.
345e5dd7070Spatrick // CWE-477: Use of Obsolete Functions
346e5dd7070Spatrick // bcmp was deprecated in POSIX.1-2008
347e5dd7070Spatrick //===----------------------------------------------------------------------===//
348e5dd7070Spatrick 
checkCall_bcmp(const CallExpr * CE,const FunctionDecl * FD)349e5dd7070Spatrick void WalkAST::checkCall_bcmp(const CallExpr *CE, const FunctionDecl *FD) {
350e5dd7070Spatrick   if (!filter.check_bcmp)
351e5dd7070Spatrick     return;
352e5dd7070Spatrick 
353e5dd7070Spatrick   const FunctionProtoType *FPT = FD->getType()->getAs<FunctionProtoType>();
354e5dd7070Spatrick   if (!FPT)
355e5dd7070Spatrick     return;
356e5dd7070Spatrick 
357e5dd7070Spatrick   // Verify that the function takes three arguments.
358e5dd7070Spatrick   if (FPT->getNumParams() != 3)
359e5dd7070Spatrick     return;
360e5dd7070Spatrick 
361e5dd7070Spatrick   for (int i = 0; i < 2; i++) {
362e5dd7070Spatrick     // Verify the first and second argument type is void*.
363e5dd7070Spatrick     const PointerType *PT = FPT->getParamType(i)->getAs<PointerType>();
364e5dd7070Spatrick     if (!PT)
365e5dd7070Spatrick       return;
366e5dd7070Spatrick 
367e5dd7070Spatrick     if (PT->getPointeeType().getUnqualifiedType() != BR.getContext().VoidTy)
368e5dd7070Spatrick       return;
369e5dd7070Spatrick   }
370e5dd7070Spatrick 
371e5dd7070Spatrick   // Verify the third argument type is integer.
372e5dd7070Spatrick   if (!FPT->getParamType(2)->isIntegralOrUnscopedEnumerationType())
373e5dd7070Spatrick     return;
374e5dd7070Spatrick 
375e5dd7070Spatrick   // Issue a warning.
376e5dd7070Spatrick   PathDiagnosticLocation CELoc =
377e5dd7070Spatrick     PathDiagnosticLocation::createBegin(CE, BR.getSourceManager(), AC);
378e5dd7070Spatrick   BR.EmitBasicReport(AC->getDecl(), filter.checkName_bcmp,
379e5dd7070Spatrick                      "Use of deprecated function in call to 'bcmp()'",
380e5dd7070Spatrick                      "Security",
381e5dd7070Spatrick                      "The bcmp() function is obsoleted by memcmp().",
382e5dd7070Spatrick                      CELoc, CE->getCallee()->getSourceRange());
383e5dd7070Spatrick }
384e5dd7070Spatrick 
385e5dd7070Spatrick //===----------------------------------------------------------------------===//
386e5dd7070Spatrick // Check: Any use of bcopy.
387e5dd7070Spatrick // CWE-477: Use of Obsolete Functions
388e5dd7070Spatrick // bcopy was deprecated in POSIX.1-2008
389e5dd7070Spatrick //===----------------------------------------------------------------------===//
390e5dd7070Spatrick 
checkCall_bcopy(const CallExpr * CE,const FunctionDecl * FD)391e5dd7070Spatrick void WalkAST::checkCall_bcopy(const CallExpr *CE, const FunctionDecl *FD) {
392e5dd7070Spatrick   if (!filter.check_bcopy)
393e5dd7070Spatrick     return;
394e5dd7070Spatrick 
395e5dd7070Spatrick   const FunctionProtoType *FPT = FD->getType()->getAs<FunctionProtoType>();
396e5dd7070Spatrick   if (!FPT)
397e5dd7070Spatrick     return;
398e5dd7070Spatrick 
399e5dd7070Spatrick   // Verify that the function takes three arguments.
400e5dd7070Spatrick   if (FPT->getNumParams() != 3)
401e5dd7070Spatrick     return;
402e5dd7070Spatrick 
403e5dd7070Spatrick   for (int i = 0; i < 2; i++) {
404e5dd7070Spatrick     // Verify the first and second argument type is void*.
405e5dd7070Spatrick     const PointerType *PT = FPT->getParamType(i)->getAs<PointerType>();
406e5dd7070Spatrick     if (!PT)
407e5dd7070Spatrick       return;
408e5dd7070Spatrick 
409e5dd7070Spatrick     if (PT->getPointeeType().getUnqualifiedType() != BR.getContext().VoidTy)
410e5dd7070Spatrick       return;
411e5dd7070Spatrick   }
412e5dd7070Spatrick 
413e5dd7070Spatrick   // Verify the third argument type is integer.
414e5dd7070Spatrick   if (!FPT->getParamType(2)->isIntegralOrUnscopedEnumerationType())
415e5dd7070Spatrick     return;
416e5dd7070Spatrick 
417e5dd7070Spatrick   // Issue a warning.
418e5dd7070Spatrick   PathDiagnosticLocation CELoc =
419e5dd7070Spatrick     PathDiagnosticLocation::createBegin(CE, BR.getSourceManager(), AC);
420e5dd7070Spatrick   BR.EmitBasicReport(AC->getDecl(), filter.checkName_bcopy,
421e5dd7070Spatrick                      "Use of deprecated function in call to 'bcopy()'",
422e5dd7070Spatrick                      "Security",
423e5dd7070Spatrick                      "The bcopy() function is obsoleted by memcpy() "
424e5dd7070Spatrick                      "or memmove().",
425e5dd7070Spatrick                      CELoc, CE->getCallee()->getSourceRange());
426e5dd7070Spatrick }
427e5dd7070Spatrick 
428e5dd7070Spatrick //===----------------------------------------------------------------------===//
429e5dd7070Spatrick // Check: Any use of bzero.
430e5dd7070Spatrick // CWE-477: Use of Obsolete Functions
431e5dd7070Spatrick // bzero was deprecated in POSIX.1-2008
432e5dd7070Spatrick //===----------------------------------------------------------------------===//
433e5dd7070Spatrick 
checkCall_bzero(const CallExpr * CE,const FunctionDecl * FD)434e5dd7070Spatrick void WalkAST::checkCall_bzero(const CallExpr *CE, const FunctionDecl *FD) {
435e5dd7070Spatrick   if (!filter.check_bzero)
436e5dd7070Spatrick     return;
437e5dd7070Spatrick 
438e5dd7070Spatrick   const FunctionProtoType *FPT = FD->getType()->getAs<FunctionProtoType>();
439e5dd7070Spatrick   if (!FPT)
440e5dd7070Spatrick     return;
441e5dd7070Spatrick 
442e5dd7070Spatrick   // Verify that the function takes two arguments.
443e5dd7070Spatrick   if (FPT->getNumParams() != 2)
444e5dd7070Spatrick     return;
445e5dd7070Spatrick 
446e5dd7070Spatrick   // Verify the first argument type is void*.
447e5dd7070Spatrick   const PointerType *PT = FPT->getParamType(0)->getAs<PointerType>();
448e5dd7070Spatrick   if (!PT)
449e5dd7070Spatrick     return;
450e5dd7070Spatrick 
451e5dd7070Spatrick   if (PT->getPointeeType().getUnqualifiedType() != BR.getContext().VoidTy)
452e5dd7070Spatrick     return;
453e5dd7070Spatrick 
454e5dd7070Spatrick   // Verify the second argument type is integer.
455e5dd7070Spatrick   if (!FPT->getParamType(1)->isIntegralOrUnscopedEnumerationType())
456e5dd7070Spatrick     return;
457e5dd7070Spatrick 
458e5dd7070Spatrick   // Issue a warning.
459e5dd7070Spatrick   PathDiagnosticLocation CELoc =
460e5dd7070Spatrick     PathDiagnosticLocation::createBegin(CE, BR.getSourceManager(), AC);
461e5dd7070Spatrick   BR.EmitBasicReport(AC->getDecl(), filter.checkName_bzero,
462e5dd7070Spatrick                      "Use of deprecated function in call to 'bzero()'",
463e5dd7070Spatrick                      "Security",
464e5dd7070Spatrick                      "The bzero() function is obsoleted by memset().",
465e5dd7070Spatrick                      CELoc, CE->getCallee()->getSourceRange());
466e5dd7070Spatrick }
467e5dd7070Spatrick 
468e5dd7070Spatrick 
469e5dd7070Spatrick //===----------------------------------------------------------------------===//
470e5dd7070Spatrick // Check: Any use of 'gets' is insecure.
471e5dd7070Spatrick // Originally: <rdar://problem/6335715>
472e5dd7070Spatrick // Implements (part of): 300-BSI (buildsecurityin.us-cert.gov)
473e5dd7070Spatrick // CWE-242: Use of Inherently Dangerous Function
474e5dd7070Spatrick //===----------------------------------------------------------------------===//
475e5dd7070Spatrick 
checkCall_gets(const CallExpr * CE,const FunctionDecl * FD)476e5dd7070Spatrick void WalkAST::checkCall_gets(const CallExpr *CE, const FunctionDecl *FD) {
477e5dd7070Spatrick   if (!filter.check_gets)
478e5dd7070Spatrick     return;
479e5dd7070Spatrick 
480e5dd7070Spatrick   const FunctionProtoType *FPT = FD->getType()->getAs<FunctionProtoType>();
481e5dd7070Spatrick   if (!FPT)
482e5dd7070Spatrick     return;
483e5dd7070Spatrick 
484e5dd7070Spatrick   // Verify that the function takes a single argument.
485e5dd7070Spatrick   if (FPT->getNumParams() != 1)
486e5dd7070Spatrick     return;
487e5dd7070Spatrick 
488e5dd7070Spatrick   // Is the argument a 'char*'?
489e5dd7070Spatrick   const PointerType *PT = FPT->getParamType(0)->getAs<PointerType>();
490e5dd7070Spatrick   if (!PT)
491e5dd7070Spatrick     return;
492e5dd7070Spatrick 
493e5dd7070Spatrick   if (PT->getPointeeType().getUnqualifiedType() != BR.getContext().CharTy)
494e5dd7070Spatrick     return;
495e5dd7070Spatrick 
496e5dd7070Spatrick   // Issue a warning.
497e5dd7070Spatrick   PathDiagnosticLocation CELoc =
498e5dd7070Spatrick     PathDiagnosticLocation::createBegin(CE, BR.getSourceManager(), AC);
499e5dd7070Spatrick   BR.EmitBasicReport(AC->getDecl(), filter.checkName_gets,
500e5dd7070Spatrick                      "Potential buffer overflow in call to 'gets'",
501e5dd7070Spatrick                      "Security",
502e5dd7070Spatrick                      "Call to function 'gets' is extremely insecure as it can "
503e5dd7070Spatrick                      "always result in a buffer overflow",
504e5dd7070Spatrick                      CELoc, CE->getCallee()->getSourceRange());
505e5dd7070Spatrick }
506e5dd7070Spatrick 
507e5dd7070Spatrick //===----------------------------------------------------------------------===//
508e5dd7070Spatrick // Check: Any use of 'getpwd' is insecure.
509e5dd7070Spatrick // CWE-477: Use of Obsolete Functions
510e5dd7070Spatrick //===----------------------------------------------------------------------===//
511e5dd7070Spatrick 
checkCall_getpw(const CallExpr * CE,const FunctionDecl * FD)512e5dd7070Spatrick void WalkAST::checkCall_getpw(const CallExpr *CE, const FunctionDecl *FD) {
513e5dd7070Spatrick   if (!filter.check_getpw)
514e5dd7070Spatrick     return;
515e5dd7070Spatrick 
516e5dd7070Spatrick   const FunctionProtoType *FPT = FD->getType()->getAs<FunctionProtoType>();
517e5dd7070Spatrick   if (!FPT)
518e5dd7070Spatrick     return;
519e5dd7070Spatrick 
520e5dd7070Spatrick   // Verify that the function takes two arguments.
521e5dd7070Spatrick   if (FPT->getNumParams() != 2)
522e5dd7070Spatrick     return;
523e5dd7070Spatrick 
524e5dd7070Spatrick   // Verify the first argument type is integer.
525e5dd7070Spatrick   if (!FPT->getParamType(0)->isIntegralOrUnscopedEnumerationType())
526e5dd7070Spatrick     return;
527e5dd7070Spatrick 
528e5dd7070Spatrick   // Verify the second argument type is char*.
529e5dd7070Spatrick   const PointerType *PT = FPT->getParamType(1)->getAs<PointerType>();
530e5dd7070Spatrick   if (!PT)
531e5dd7070Spatrick     return;
532e5dd7070Spatrick 
533e5dd7070Spatrick   if (PT->getPointeeType().getUnqualifiedType() != BR.getContext().CharTy)
534e5dd7070Spatrick     return;
535e5dd7070Spatrick 
536e5dd7070Spatrick   // Issue a warning.
537e5dd7070Spatrick   PathDiagnosticLocation CELoc =
538e5dd7070Spatrick     PathDiagnosticLocation::createBegin(CE, BR.getSourceManager(), AC);
539e5dd7070Spatrick   BR.EmitBasicReport(AC->getDecl(), filter.checkName_getpw,
540e5dd7070Spatrick                      "Potential buffer overflow in call to 'getpw'",
541e5dd7070Spatrick                      "Security",
542e5dd7070Spatrick                      "The getpw() function is dangerous as it may overflow the "
543e5dd7070Spatrick                      "provided buffer. It is obsoleted by getpwuid().",
544e5dd7070Spatrick                      CELoc, CE->getCallee()->getSourceRange());
545e5dd7070Spatrick }
546e5dd7070Spatrick 
547e5dd7070Spatrick //===----------------------------------------------------------------------===//
548e5dd7070Spatrick // Check: Any use of 'mktemp' is insecure.  It is obsoleted by mkstemp().
549e5dd7070Spatrick // CWE-377: Insecure Temporary File
550e5dd7070Spatrick //===----------------------------------------------------------------------===//
551e5dd7070Spatrick 
checkCall_mktemp(const CallExpr * CE,const FunctionDecl * FD)552e5dd7070Spatrick void WalkAST::checkCall_mktemp(const CallExpr *CE, const FunctionDecl *FD) {
553e5dd7070Spatrick   if (!filter.check_mktemp) {
554e5dd7070Spatrick     // Fall back to the security check of looking for enough 'X's in the
555e5dd7070Spatrick     // format string, since that is a less severe warning.
556e5dd7070Spatrick     checkCall_mkstemp(CE, FD);
557e5dd7070Spatrick     return;
558e5dd7070Spatrick   }
559e5dd7070Spatrick 
560e5dd7070Spatrick   const FunctionProtoType *FPT = FD->getType()->getAs<FunctionProtoType>();
561e5dd7070Spatrick   if(!FPT)
562e5dd7070Spatrick     return;
563e5dd7070Spatrick 
564e5dd7070Spatrick   // Verify that the function takes a single argument.
565e5dd7070Spatrick   if (FPT->getNumParams() != 1)
566e5dd7070Spatrick     return;
567e5dd7070Spatrick 
568e5dd7070Spatrick   // Verify that the argument is Pointer Type.
569e5dd7070Spatrick   const PointerType *PT = FPT->getParamType(0)->getAs<PointerType>();
570e5dd7070Spatrick   if (!PT)
571e5dd7070Spatrick     return;
572e5dd7070Spatrick 
573e5dd7070Spatrick   // Verify that the argument is a 'char*'.
574e5dd7070Spatrick   if (PT->getPointeeType().getUnqualifiedType() != BR.getContext().CharTy)
575e5dd7070Spatrick     return;
576e5dd7070Spatrick 
577e5dd7070Spatrick   // Issue a warning.
578e5dd7070Spatrick   PathDiagnosticLocation CELoc =
579e5dd7070Spatrick     PathDiagnosticLocation::createBegin(CE, BR.getSourceManager(), AC);
580e5dd7070Spatrick   BR.EmitBasicReport(AC->getDecl(), filter.checkName_mktemp,
581e5dd7070Spatrick                      "Potential insecure temporary file in call 'mktemp'",
582e5dd7070Spatrick                      "Security",
583e5dd7070Spatrick                      "Call to function 'mktemp' is insecure as it always "
584e5dd7070Spatrick                      "creates or uses insecure temporary file.  Use 'mkstemp' "
585e5dd7070Spatrick                      "instead",
586e5dd7070Spatrick                      CELoc, CE->getCallee()->getSourceRange());
587e5dd7070Spatrick }
588e5dd7070Spatrick 
589e5dd7070Spatrick //===----------------------------------------------------------------------===//
590e5dd7070Spatrick // Check: Use of 'mkstemp', 'mktemp', 'mkdtemp' should contain at least 6 X's.
591e5dd7070Spatrick //===----------------------------------------------------------------------===//
592e5dd7070Spatrick 
checkCall_mkstemp(const CallExpr * CE,const FunctionDecl * FD)593e5dd7070Spatrick void WalkAST::checkCall_mkstemp(const CallExpr *CE, const FunctionDecl *FD) {
594e5dd7070Spatrick   if (!filter.check_mkstemp)
595e5dd7070Spatrick     return;
596e5dd7070Spatrick 
597e5dd7070Spatrick   StringRef Name = FD->getIdentifier()->getName();
598e5dd7070Spatrick   std::pair<signed, signed> ArgSuffix =
599e5dd7070Spatrick     llvm::StringSwitch<std::pair<signed, signed> >(Name)
600e5dd7070Spatrick       .Case("mktemp", std::make_pair(0,-1))
601e5dd7070Spatrick       .Case("mkstemp", std::make_pair(0,-1))
602e5dd7070Spatrick       .Case("mkdtemp", std::make_pair(0,-1))
603e5dd7070Spatrick       .Case("mkstemps", std::make_pair(0,1))
604e5dd7070Spatrick       .Default(std::make_pair(-1, -1));
605e5dd7070Spatrick 
606e5dd7070Spatrick   assert(ArgSuffix.first >= 0 && "Unsupported function");
607e5dd7070Spatrick 
608e5dd7070Spatrick   // Check if the number of arguments is consistent with out expectations.
609e5dd7070Spatrick   unsigned numArgs = CE->getNumArgs();
610e5dd7070Spatrick   if ((signed) numArgs <= ArgSuffix.first)
611e5dd7070Spatrick     return;
612e5dd7070Spatrick 
613e5dd7070Spatrick   const StringLiteral *strArg =
614e5dd7070Spatrick     dyn_cast<StringLiteral>(CE->getArg((unsigned)ArgSuffix.first)
615e5dd7070Spatrick                               ->IgnoreParenImpCasts());
616e5dd7070Spatrick 
617e5dd7070Spatrick   // Currently we only handle string literals.  It is possible to do better,
618e5dd7070Spatrick   // either by looking at references to const variables, or by doing real
619e5dd7070Spatrick   // flow analysis.
620e5dd7070Spatrick   if (!strArg || strArg->getCharByteWidth() != 1)
621e5dd7070Spatrick     return;
622e5dd7070Spatrick 
623e5dd7070Spatrick   // Count the number of X's, taking into account a possible cutoff suffix.
624e5dd7070Spatrick   StringRef str = strArg->getString();
625e5dd7070Spatrick   unsigned numX = 0;
626e5dd7070Spatrick   unsigned n = str.size();
627e5dd7070Spatrick 
628e5dd7070Spatrick   // Take into account the suffix.
629e5dd7070Spatrick   unsigned suffix = 0;
630e5dd7070Spatrick   if (ArgSuffix.second >= 0) {
631e5dd7070Spatrick     const Expr *suffixEx = CE->getArg((unsigned)ArgSuffix.second);
632e5dd7070Spatrick     Expr::EvalResult EVResult;
633e5dd7070Spatrick     if (!suffixEx->EvaluateAsInt(EVResult, BR.getContext()))
634e5dd7070Spatrick       return;
635e5dd7070Spatrick     llvm::APSInt Result = EVResult.Val.getInt();
636e5dd7070Spatrick     // FIXME: Issue a warning.
637e5dd7070Spatrick     if (Result.isNegative())
638e5dd7070Spatrick       return;
639e5dd7070Spatrick     suffix = (unsigned) Result.getZExtValue();
640e5dd7070Spatrick     n = (n > suffix) ? n - suffix : 0;
641e5dd7070Spatrick   }
642e5dd7070Spatrick 
643e5dd7070Spatrick   for (unsigned i = 0; i < n; ++i)
644e5dd7070Spatrick     if (str[i] == 'X') ++numX;
645e5dd7070Spatrick 
646e5dd7070Spatrick   if (numX >= 6)
647e5dd7070Spatrick     return;
648e5dd7070Spatrick 
649e5dd7070Spatrick   // Issue a warning.
650e5dd7070Spatrick   PathDiagnosticLocation CELoc =
651e5dd7070Spatrick     PathDiagnosticLocation::createBegin(CE, BR.getSourceManager(), AC);
652e5dd7070Spatrick   SmallString<512> buf;
653e5dd7070Spatrick   llvm::raw_svector_ostream out(buf);
654e5dd7070Spatrick   out << "Call to '" << Name << "' should have at least 6 'X's in the"
655e5dd7070Spatrick     " format string to be secure (" << numX << " 'X'";
656e5dd7070Spatrick   if (numX != 1)
657e5dd7070Spatrick     out << 's';
658e5dd7070Spatrick   out << " seen";
659e5dd7070Spatrick   if (suffix) {
660e5dd7070Spatrick     out << ", " << suffix << " character";
661e5dd7070Spatrick     if (suffix > 1)
662e5dd7070Spatrick       out << 's';
663e5dd7070Spatrick     out << " used as a suffix";
664e5dd7070Spatrick   }
665e5dd7070Spatrick   out << ')';
666e5dd7070Spatrick   BR.EmitBasicReport(AC->getDecl(), filter.checkName_mkstemp,
667e5dd7070Spatrick                      "Insecure temporary file creation", "Security",
668e5dd7070Spatrick                      out.str(), CELoc, strArg->getSourceRange());
669e5dd7070Spatrick }
670e5dd7070Spatrick 
671e5dd7070Spatrick //===----------------------------------------------------------------------===//
672e5dd7070Spatrick // Check: Any use of 'strcpy' is insecure.
673e5dd7070Spatrick //
674e5dd7070Spatrick // CWE-119: Improper Restriction of Operations within
675e5dd7070Spatrick // the Bounds of a Memory Buffer
676e5dd7070Spatrick //===----------------------------------------------------------------------===//
677e5dd7070Spatrick 
checkCall_strcpy(const CallExpr * CE,const FunctionDecl * FD)678e5dd7070Spatrick void WalkAST::checkCall_strcpy(const CallExpr *CE, const FunctionDecl *FD) {
679e5dd7070Spatrick   if (!filter.check_strcpy)
680e5dd7070Spatrick     return;
681e5dd7070Spatrick 
682e5dd7070Spatrick   if (!checkCall_strCommon(CE, FD))
683e5dd7070Spatrick     return;
684e5dd7070Spatrick 
685e5dd7070Spatrick   const auto *Target = CE->getArg(0)->IgnoreImpCasts(),
686e5dd7070Spatrick              *Source = CE->getArg(1)->IgnoreImpCasts();
687e5dd7070Spatrick 
688e5dd7070Spatrick   if (const auto *Array = dyn_cast<ConstantArrayType>(Target->getType())) {
689e5dd7070Spatrick     uint64_t ArraySize = BR.getContext().getTypeSize(Array) / 8;
690e5dd7070Spatrick     if (const auto *String = dyn_cast<StringLiteral>(Source)) {
691e5dd7070Spatrick       if (ArraySize >= String->getLength() + 1)
692e5dd7070Spatrick         return;
693e5dd7070Spatrick     }
694e5dd7070Spatrick   }
695e5dd7070Spatrick 
696e5dd7070Spatrick   // Issue a warning.
697e5dd7070Spatrick   PathDiagnosticLocation CELoc =
698e5dd7070Spatrick     PathDiagnosticLocation::createBegin(CE, BR.getSourceManager(), AC);
699e5dd7070Spatrick   BR.EmitBasicReport(AC->getDecl(), filter.checkName_strcpy,
700e5dd7070Spatrick                      "Potential insecure memory buffer bounds restriction in "
701e5dd7070Spatrick                      "call 'strcpy'",
702e5dd7070Spatrick                      "Security",
703e5dd7070Spatrick                      "Call to function 'strcpy' is insecure as it does not "
704e5dd7070Spatrick                      "provide bounding of the memory buffer. Replace "
705e5dd7070Spatrick                      "unbounded copy functions with analogous functions that "
706e5dd7070Spatrick                      "support length arguments such as 'strlcpy'. CWE-119.",
707e5dd7070Spatrick                      CELoc, CE->getCallee()->getSourceRange());
708e5dd7070Spatrick }
709e5dd7070Spatrick 
710e5dd7070Spatrick //===----------------------------------------------------------------------===//
711e5dd7070Spatrick // Check: Any use of 'strcat' is insecure.
712e5dd7070Spatrick //
713e5dd7070Spatrick // CWE-119: Improper Restriction of Operations within
714e5dd7070Spatrick // the Bounds of a Memory Buffer
715e5dd7070Spatrick //===----------------------------------------------------------------------===//
716e5dd7070Spatrick 
checkCall_strcat(const CallExpr * CE,const FunctionDecl * FD)717e5dd7070Spatrick void WalkAST::checkCall_strcat(const CallExpr *CE, const FunctionDecl *FD) {
718e5dd7070Spatrick   if (!filter.check_strcpy)
719e5dd7070Spatrick     return;
720e5dd7070Spatrick 
721e5dd7070Spatrick   if (!checkCall_strCommon(CE, FD))
722e5dd7070Spatrick     return;
723e5dd7070Spatrick 
724e5dd7070Spatrick   // Issue a warning.
725e5dd7070Spatrick   PathDiagnosticLocation CELoc =
726e5dd7070Spatrick     PathDiagnosticLocation::createBegin(CE, BR.getSourceManager(), AC);
727e5dd7070Spatrick   BR.EmitBasicReport(AC->getDecl(), filter.checkName_strcpy,
728e5dd7070Spatrick                      "Potential insecure memory buffer bounds restriction in "
729e5dd7070Spatrick                      "call 'strcat'",
730e5dd7070Spatrick                      "Security",
731e5dd7070Spatrick                      "Call to function 'strcat' is insecure as it does not "
732e5dd7070Spatrick                      "provide bounding of the memory buffer. Replace "
733e5dd7070Spatrick                      "unbounded copy functions with analogous functions that "
734e5dd7070Spatrick                      "support length arguments such as 'strlcat'. CWE-119.",
735e5dd7070Spatrick                      CELoc, CE->getCallee()->getSourceRange());
736e5dd7070Spatrick }
737e5dd7070Spatrick 
738e5dd7070Spatrick //===----------------------------------------------------------------------===//
739e5dd7070Spatrick // Check: Any use of 'sprintf', 'vsprintf', 'scanf', 'wscanf', 'fscanf',
740e5dd7070Spatrick //        'fwscanf', 'vscanf', 'vwscanf', 'vfscanf', 'vfwscanf', 'sscanf',
741e5dd7070Spatrick //        'swscanf', 'vsscanf', 'vswscanf', 'swprintf', 'snprintf', 'vswprintf',
742e5dd7070Spatrick //        'vsnprintf', 'memcpy', 'memmove', 'strncpy', 'strncat', 'memset'
743e5dd7070Spatrick //        is deprecated since C11.
744e5dd7070Spatrick //
745e5dd7070Spatrick //        Use of 'sprintf', 'vsprintf', 'scanf', 'wscanf','fscanf',
746e5dd7070Spatrick //        'fwscanf', 'vscanf', 'vwscanf', 'vfscanf', 'vfwscanf', 'sscanf',
747e5dd7070Spatrick //        'swscanf', 'vsscanf', 'vswscanf' without buffer limitations
748e5dd7070Spatrick //        is insecure.
749e5dd7070Spatrick //
750e5dd7070Spatrick // CWE-119: Improper Restriction of Operations within
751e5dd7070Spatrick // the Bounds of a Memory Buffer
752e5dd7070Spatrick //===----------------------------------------------------------------------===//
753e5dd7070Spatrick 
checkDeprecatedOrUnsafeBufferHandling(const CallExpr * CE,const FunctionDecl * FD)754e5dd7070Spatrick void WalkAST::checkDeprecatedOrUnsafeBufferHandling(const CallExpr *CE,
755e5dd7070Spatrick                                                     const FunctionDecl *FD) {
756e5dd7070Spatrick   if (!filter.check_DeprecatedOrUnsafeBufferHandling)
757e5dd7070Spatrick     return;
758e5dd7070Spatrick 
759e5dd7070Spatrick   if (!BR.getContext().getLangOpts().C11)
760e5dd7070Spatrick     return;
761e5dd7070Spatrick 
762e5dd7070Spatrick   // Issue a warning. ArgIndex == -1: Deprecated but not unsafe (has size
763e5dd7070Spatrick   // restrictions).
764e5dd7070Spatrick   enum { DEPR_ONLY = -1, UNKNOWN_CALL = -2 };
765e5dd7070Spatrick 
766e5dd7070Spatrick   StringRef Name = FD->getIdentifier()->getName();
767e5dd7070Spatrick   if (Name.startswith("__builtin_"))
768e5dd7070Spatrick     Name = Name.substr(10);
769e5dd7070Spatrick 
770e5dd7070Spatrick   int ArgIndex =
771e5dd7070Spatrick       llvm::StringSwitch<int>(Name)
772e5dd7070Spatrick           .Cases("scanf", "wscanf", "vscanf", "vwscanf", 0)
773e5dd7070Spatrick           .Cases("sprintf", "vsprintf", "fscanf", "fwscanf", "vfscanf",
774e5dd7070Spatrick                  "vfwscanf", "sscanf", "swscanf", "vsscanf", "vswscanf", 1)
775e5dd7070Spatrick           .Cases("swprintf", "snprintf", "vswprintf", "vsnprintf", "memcpy",
776e5dd7070Spatrick                  "memmove", "memset", "strncpy", "strncat", DEPR_ONLY)
777e5dd7070Spatrick           .Default(UNKNOWN_CALL);
778e5dd7070Spatrick 
779e5dd7070Spatrick   assert(ArgIndex != UNKNOWN_CALL && "Unsupported function");
780e5dd7070Spatrick   bool BoundsProvided = ArgIndex == DEPR_ONLY;
781e5dd7070Spatrick 
782e5dd7070Spatrick   if (!BoundsProvided) {
783e5dd7070Spatrick     // Currently we only handle (not wide) string literals. It is possible to do
784e5dd7070Spatrick     // better, either by looking at references to const variables, or by doing
785e5dd7070Spatrick     // real flow analysis.
786e5dd7070Spatrick     auto FormatString =
787e5dd7070Spatrick         dyn_cast<StringLiteral>(CE->getArg(ArgIndex)->IgnoreParenImpCasts());
788*12c85518Srobert     if (FormatString && !FormatString->getString().contains("%s") &&
789*12c85518Srobert         !FormatString->getString().contains("%["))
790e5dd7070Spatrick       BoundsProvided = true;
791e5dd7070Spatrick   }
792e5dd7070Spatrick 
793e5dd7070Spatrick   SmallString<128> Buf1;
794e5dd7070Spatrick   SmallString<512> Buf2;
795e5dd7070Spatrick   llvm::raw_svector_ostream Out1(Buf1);
796e5dd7070Spatrick   llvm::raw_svector_ostream Out2(Buf2);
797e5dd7070Spatrick 
798e5dd7070Spatrick   Out1 << "Potential insecure memory buffer bounds restriction in call '"
799e5dd7070Spatrick        << Name << "'";
800e5dd7070Spatrick   Out2 << "Call to function '" << Name
801e5dd7070Spatrick        << "' is insecure as it does not provide ";
802e5dd7070Spatrick 
803e5dd7070Spatrick   if (!BoundsProvided) {
804e5dd7070Spatrick     Out2 << "bounding of the memory buffer or ";
805e5dd7070Spatrick   }
806e5dd7070Spatrick 
807e5dd7070Spatrick   Out2 << "security checks introduced "
808e5dd7070Spatrick           "in the C11 standard. Replace with analogous functions that "
809e5dd7070Spatrick           "support length arguments or provides boundary checks such as '"
810e5dd7070Spatrick        << Name << "_s' in case of C11";
811e5dd7070Spatrick 
812e5dd7070Spatrick   PathDiagnosticLocation CELoc =
813e5dd7070Spatrick       PathDiagnosticLocation::createBegin(CE, BR.getSourceManager(), AC);
814e5dd7070Spatrick   BR.EmitBasicReport(AC->getDecl(),
815e5dd7070Spatrick                      filter.checkName_DeprecatedOrUnsafeBufferHandling,
816e5dd7070Spatrick                      Out1.str(), "Security", Out2.str(), CELoc,
817e5dd7070Spatrick                      CE->getCallee()->getSourceRange());
818e5dd7070Spatrick }
819e5dd7070Spatrick 
820e5dd7070Spatrick //===----------------------------------------------------------------------===//
821e5dd7070Spatrick // Common check for str* functions with no bounds parameters.
822e5dd7070Spatrick //===----------------------------------------------------------------------===//
823e5dd7070Spatrick 
checkCall_strCommon(const CallExpr * CE,const FunctionDecl * FD)824e5dd7070Spatrick bool WalkAST::checkCall_strCommon(const CallExpr *CE, const FunctionDecl *FD) {
825e5dd7070Spatrick   const FunctionProtoType *FPT = FD->getType()->getAs<FunctionProtoType>();
826e5dd7070Spatrick   if (!FPT)
827e5dd7070Spatrick     return false;
828e5dd7070Spatrick 
829e5dd7070Spatrick   // Verify the function takes two arguments, three in the _chk version.
830e5dd7070Spatrick   int numArgs = FPT->getNumParams();
831e5dd7070Spatrick   if (numArgs != 2 && numArgs != 3)
832e5dd7070Spatrick     return false;
833e5dd7070Spatrick 
834e5dd7070Spatrick   // Verify the type for both arguments.
835e5dd7070Spatrick   for (int i = 0; i < 2; i++) {
836e5dd7070Spatrick     // Verify that the arguments are pointers.
837e5dd7070Spatrick     const PointerType *PT = FPT->getParamType(i)->getAs<PointerType>();
838e5dd7070Spatrick     if (!PT)
839e5dd7070Spatrick       return false;
840e5dd7070Spatrick 
841e5dd7070Spatrick     // Verify that the argument is a 'char*'.
842e5dd7070Spatrick     if (PT->getPointeeType().getUnqualifiedType() != BR.getContext().CharTy)
843e5dd7070Spatrick       return false;
844e5dd7070Spatrick   }
845e5dd7070Spatrick 
846e5dd7070Spatrick   return true;
847e5dd7070Spatrick }
848e5dd7070Spatrick 
849e5dd7070Spatrick //===----------------------------------------------------------------------===//
850e5dd7070Spatrick // Check: Linear congruent random number generators should not be used
851e5dd7070Spatrick // Originally: <rdar://problem/63371000>
852e5dd7070Spatrick // CWE-338: Use of cryptographically weak prng
853e5dd7070Spatrick //===----------------------------------------------------------------------===//
854e5dd7070Spatrick 
checkCall_rand(const CallExpr * CE,const FunctionDecl * FD)855e5dd7070Spatrick void WalkAST::checkCall_rand(const CallExpr *CE, const FunctionDecl *FD) {
856e5dd7070Spatrick   if (!filter.check_rand || !CheckRand)
857e5dd7070Spatrick     return;
858e5dd7070Spatrick 
859e5dd7070Spatrick   const FunctionProtoType *FTP = FD->getType()->getAs<FunctionProtoType>();
860e5dd7070Spatrick   if (!FTP)
861e5dd7070Spatrick     return;
862e5dd7070Spatrick 
863e5dd7070Spatrick   if (FTP->getNumParams() == 1) {
864e5dd7070Spatrick     // Is the argument an 'unsigned short *'?
865e5dd7070Spatrick     // (Actually any integer type is allowed.)
866e5dd7070Spatrick     const PointerType *PT = FTP->getParamType(0)->getAs<PointerType>();
867e5dd7070Spatrick     if (!PT)
868e5dd7070Spatrick       return;
869e5dd7070Spatrick 
870e5dd7070Spatrick     if (! PT->getPointeeType()->isIntegralOrUnscopedEnumerationType())
871e5dd7070Spatrick       return;
872e5dd7070Spatrick   } else if (FTP->getNumParams() != 0)
873e5dd7070Spatrick     return;
874e5dd7070Spatrick 
875e5dd7070Spatrick   // Issue a warning.
876e5dd7070Spatrick   SmallString<256> buf1;
877e5dd7070Spatrick   llvm::raw_svector_ostream os1(buf1);
878e5dd7070Spatrick   os1 << '\'' << *FD << "' is a poor random number generator";
879e5dd7070Spatrick 
880e5dd7070Spatrick   SmallString<256> buf2;
881e5dd7070Spatrick   llvm::raw_svector_ostream os2(buf2);
882e5dd7070Spatrick   os2 << "Function '" << *FD
883e5dd7070Spatrick       << "' is obsolete because it implements a poor random number generator."
884e5dd7070Spatrick       << "  Use 'arc4random' instead";
885e5dd7070Spatrick 
886e5dd7070Spatrick   PathDiagnosticLocation CELoc =
887e5dd7070Spatrick     PathDiagnosticLocation::createBegin(CE, BR.getSourceManager(), AC);
888e5dd7070Spatrick   BR.EmitBasicReport(AC->getDecl(), filter.checkName_rand, os1.str(),
889e5dd7070Spatrick                      "Security", os2.str(), CELoc,
890e5dd7070Spatrick                      CE->getCallee()->getSourceRange());
891e5dd7070Spatrick }
892e5dd7070Spatrick 
893e5dd7070Spatrick //===----------------------------------------------------------------------===//
894e5dd7070Spatrick // Check: 'random' should not be used
895e5dd7070Spatrick // Originally: <rdar://problem/63371000>
896e5dd7070Spatrick //===----------------------------------------------------------------------===//
897e5dd7070Spatrick 
checkCall_random(const CallExpr * CE,const FunctionDecl * FD)898e5dd7070Spatrick void WalkAST::checkCall_random(const CallExpr *CE, const FunctionDecl *FD) {
899e5dd7070Spatrick   if (!CheckRand || !filter.check_rand)
900e5dd7070Spatrick     return;
901e5dd7070Spatrick 
902e5dd7070Spatrick   const FunctionProtoType *FTP = FD->getType()->getAs<FunctionProtoType>();
903e5dd7070Spatrick   if (!FTP)
904e5dd7070Spatrick     return;
905e5dd7070Spatrick 
906e5dd7070Spatrick   // Verify that the function takes no argument.
907e5dd7070Spatrick   if (FTP->getNumParams() != 0)
908e5dd7070Spatrick     return;
909e5dd7070Spatrick 
910e5dd7070Spatrick   // Issue a warning.
911e5dd7070Spatrick   PathDiagnosticLocation CELoc =
912e5dd7070Spatrick     PathDiagnosticLocation::createBegin(CE, BR.getSourceManager(), AC);
913e5dd7070Spatrick   BR.EmitBasicReport(AC->getDecl(), filter.checkName_rand,
914e5dd7070Spatrick                      "'random' is not a secure random number generator",
915e5dd7070Spatrick                      "Security",
916e5dd7070Spatrick                      "The 'random' function produces a sequence of values that "
917e5dd7070Spatrick                      "an adversary may be able to predict.  Use 'arc4random' "
918e5dd7070Spatrick                      "instead", CELoc, CE->getCallee()->getSourceRange());
919e5dd7070Spatrick }
920e5dd7070Spatrick 
921e5dd7070Spatrick //===----------------------------------------------------------------------===//
922e5dd7070Spatrick // Check: 'vfork' should not be used.
923e5dd7070Spatrick // POS33-C: Do not use vfork().
924e5dd7070Spatrick //===----------------------------------------------------------------------===//
925e5dd7070Spatrick 
checkCall_vfork(const CallExpr * CE,const FunctionDecl * FD)926e5dd7070Spatrick void WalkAST::checkCall_vfork(const CallExpr *CE, const FunctionDecl *FD) {
927e5dd7070Spatrick   if (!filter.check_vfork)
928e5dd7070Spatrick     return;
929e5dd7070Spatrick 
930e5dd7070Spatrick   // All calls to vfork() are insecure, issue a warning.
931e5dd7070Spatrick   PathDiagnosticLocation CELoc =
932e5dd7070Spatrick     PathDiagnosticLocation::createBegin(CE, BR.getSourceManager(), AC);
933e5dd7070Spatrick   BR.EmitBasicReport(AC->getDecl(), filter.checkName_vfork,
934e5dd7070Spatrick                      "Potential insecure implementation-specific behavior in "
935e5dd7070Spatrick                      "call 'vfork'",
936e5dd7070Spatrick                      "Security",
937e5dd7070Spatrick                      "Call to function 'vfork' is insecure as it can lead to "
938e5dd7070Spatrick                      "denial of service situations in the parent process. "
939e5dd7070Spatrick                      "Replace calls to vfork with calls to the safer "
940e5dd7070Spatrick                      "'posix_spawn' function",
941e5dd7070Spatrick                      CELoc, CE->getCallee()->getSourceRange());
942e5dd7070Spatrick }
943e5dd7070Spatrick 
944e5dd7070Spatrick //===----------------------------------------------------------------------===//
945e5dd7070Spatrick // Check: '-decodeValueOfObjCType:at:' should not be used.
946e5dd7070Spatrick // It is deprecated in favor of '-decodeValueOfObjCType:at:size:' due to
947e5dd7070Spatrick // likelihood of buffer overflows.
948e5dd7070Spatrick //===----------------------------------------------------------------------===//
949e5dd7070Spatrick 
checkMsg_decodeValueOfObjCType(const ObjCMessageExpr * ME)950e5dd7070Spatrick void WalkAST::checkMsg_decodeValueOfObjCType(const ObjCMessageExpr *ME) {
951e5dd7070Spatrick   if (!filter.check_decodeValueOfObjCType)
952e5dd7070Spatrick     return;
953e5dd7070Spatrick 
954e5dd7070Spatrick   // Check availability of the secure alternative:
955e5dd7070Spatrick   // iOS 11+, macOS 10.13+, tvOS 11+, and watchOS 4.0+
956e5dd7070Spatrick   // FIXME: We probably shouldn't register the check if it's not available.
957e5dd7070Spatrick   const TargetInfo &TI = AC->getASTContext().getTargetInfo();
958e5dd7070Spatrick   const llvm::Triple &T = TI.getTriple();
959e5dd7070Spatrick   const VersionTuple &VT = TI.getPlatformMinVersion();
960e5dd7070Spatrick   switch (T.getOS()) {
961e5dd7070Spatrick   case llvm::Triple::IOS:
962e5dd7070Spatrick     if (VT < VersionTuple(11, 0))
963e5dd7070Spatrick       return;
964e5dd7070Spatrick     break;
965e5dd7070Spatrick   case llvm::Triple::MacOSX:
966e5dd7070Spatrick     if (VT < VersionTuple(10, 13))
967e5dd7070Spatrick       return;
968e5dd7070Spatrick     break;
969e5dd7070Spatrick   case llvm::Triple::WatchOS:
970e5dd7070Spatrick     if (VT < VersionTuple(4, 0))
971e5dd7070Spatrick       return;
972e5dd7070Spatrick     break;
973e5dd7070Spatrick   case llvm::Triple::TvOS:
974e5dd7070Spatrick     if (VT < VersionTuple(11, 0))
975e5dd7070Spatrick       return;
976e5dd7070Spatrick     break;
977e5dd7070Spatrick   default:
978e5dd7070Spatrick     return;
979e5dd7070Spatrick   }
980e5dd7070Spatrick 
981e5dd7070Spatrick   PathDiagnosticLocation MELoc =
982e5dd7070Spatrick       PathDiagnosticLocation::createBegin(ME, BR.getSourceManager(), AC);
983e5dd7070Spatrick   BR.EmitBasicReport(
984e5dd7070Spatrick       AC->getDecl(), filter.checkName_decodeValueOfObjCType,
985e5dd7070Spatrick       "Potential buffer overflow in '-decodeValueOfObjCType:at:'", "Security",
986e5dd7070Spatrick       "Deprecated method '-decodeValueOfObjCType:at:' is insecure "
987e5dd7070Spatrick       "as it can lead to potential buffer overflows. Use the safer "
988e5dd7070Spatrick       "'-decodeValueOfObjCType:at:size:' method.",
989e5dd7070Spatrick       MELoc, ME->getSourceRange());
990e5dd7070Spatrick }
991e5dd7070Spatrick 
992e5dd7070Spatrick //===----------------------------------------------------------------------===//
993e5dd7070Spatrick // Check: Should check whether privileges are dropped successfully.
994e5dd7070Spatrick // Originally: <rdar://problem/6337132>
995e5dd7070Spatrick //===----------------------------------------------------------------------===//
996e5dd7070Spatrick 
checkUncheckedReturnValue(CallExpr * CE)997e5dd7070Spatrick void WalkAST::checkUncheckedReturnValue(CallExpr *CE) {
998e5dd7070Spatrick   if (!filter.check_UncheckedReturn)
999e5dd7070Spatrick     return;
1000e5dd7070Spatrick 
1001e5dd7070Spatrick   const FunctionDecl *FD = CE->getDirectCallee();
1002e5dd7070Spatrick   if (!FD)
1003e5dd7070Spatrick     return;
1004e5dd7070Spatrick 
1005e5dd7070Spatrick   if (II_setid[0] == nullptr) {
1006e5dd7070Spatrick     static const char * const identifiers[num_setids] = {
1007e5dd7070Spatrick       "setuid", "setgid", "seteuid", "setegid",
1008e5dd7070Spatrick       "setreuid", "setregid"
1009e5dd7070Spatrick     };
1010e5dd7070Spatrick 
1011e5dd7070Spatrick     for (size_t i = 0; i < num_setids; i++)
1012e5dd7070Spatrick       II_setid[i] = &BR.getContext().Idents.get(identifiers[i]);
1013e5dd7070Spatrick   }
1014e5dd7070Spatrick 
1015e5dd7070Spatrick   const IdentifierInfo *id = FD->getIdentifier();
1016e5dd7070Spatrick   size_t identifierid;
1017e5dd7070Spatrick 
1018e5dd7070Spatrick   for (identifierid = 0; identifierid < num_setids; identifierid++)
1019e5dd7070Spatrick     if (id == II_setid[identifierid])
1020e5dd7070Spatrick       break;
1021e5dd7070Spatrick 
1022e5dd7070Spatrick   if (identifierid >= num_setids)
1023e5dd7070Spatrick     return;
1024e5dd7070Spatrick 
1025e5dd7070Spatrick   const FunctionProtoType *FTP = FD->getType()->getAs<FunctionProtoType>();
1026e5dd7070Spatrick   if (!FTP)
1027e5dd7070Spatrick     return;
1028e5dd7070Spatrick 
1029e5dd7070Spatrick   // Verify that the function takes one or two arguments (depending on
1030e5dd7070Spatrick   //   the function).
1031e5dd7070Spatrick   if (FTP->getNumParams() != (identifierid < 4 ? 1 : 2))
1032e5dd7070Spatrick     return;
1033e5dd7070Spatrick 
1034e5dd7070Spatrick   // The arguments must be integers.
1035e5dd7070Spatrick   for (unsigned i = 0; i < FTP->getNumParams(); i++)
1036e5dd7070Spatrick     if (!FTP->getParamType(i)->isIntegralOrUnscopedEnumerationType())
1037e5dd7070Spatrick       return;
1038e5dd7070Spatrick 
1039e5dd7070Spatrick   // Issue a warning.
1040e5dd7070Spatrick   SmallString<256> buf1;
1041e5dd7070Spatrick   llvm::raw_svector_ostream os1(buf1);
1042e5dd7070Spatrick   os1 << "Return value is not checked in call to '" << *FD << '\'';
1043e5dd7070Spatrick 
1044e5dd7070Spatrick   SmallString<256> buf2;
1045e5dd7070Spatrick   llvm::raw_svector_ostream os2(buf2);
1046e5dd7070Spatrick   os2 << "The return value from the call to '" << *FD
1047e5dd7070Spatrick       << "' is not checked.  If an error occurs in '" << *FD
1048e5dd7070Spatrick       << "', the following code may execute with unexpected privileges";
1049e5dd7070Spatrick 
1050e5dd7070Spatrick   PathDiagnosticLocation CELoc =
1051e5dd7070Spatrick     PathDiagnosticLocation::createBegin(CE, BR.getSourceManager(), AC);
1052e5dd7070Spatrick   BR.EmitBasicReport(AC->getDecl(), filter.checkName_UncheckedReturn, os1.str(),
1053e5dd7070Spatrick                      "Security", os2.str(), CELoc,
1054e5dd7070Spatrick                      CE->getCallee()->getSourceRange());
1055e5dd7070Spatrick }
1056e5dd7070Spatrick 
1057e5dd7070Spatrick //===----------------------------------------------------------------------===//
1058e5dd7070Spatrick // SecuritySyntaxChecker
1059e5dd7070Spatrick //===----------------------------------------------------------------------===//
1060e5dd7070Spatrick 
1061e5dd7070Spatrick namespace {
1062e5dd7070Spatrick class SecuritySyntaxChecker : public Checker<check::ASTCodeBody> {
1063e5dd7070Spatrick public:
1064e5dd7070Spatrick   ChecksFilter filter;
1065e5dd7070Spatrick 
checkASTCodeBody(const Decl * D,AnalysisManager & mgr,BugReporter & BR) const1066e5dd7070Spatrick   void checkASTCodeBody(const Decl *D, AnalysisManager& mgr,
1067e5dd7070Spatrick                         BugReporter &BR) const {
1068e5dd7070Spatrick     WalkAST walker(BR, mgr.getAnalysisDeclContext(D), filter);
1069e5dd7070Spatrick     walker.Visit(D->getBody());
1070e5dd7070Spatrick   }
1071e5dd7070Spatrick };
1072e5dd7070Spatrick }
1073e5dd7070Spatrick 
registerSecuritySyntaxChecker(CheckerManager & mgr)1074e5dd7070Spatrick void ento::registerSecuritySyntaxChecker(CheckerManager &mgr) {
1075e5dd7070Spatrick   mgr.registerChecker<SecuritySyntaxChecker>();
1076e5dd7070Spatrick }
1077e5dd7070Spatrick 
shouldRegisterSecuritySyntaxChecker(const CheckerManager & mgr)1078ec727ea7Spatrick bool ento::shouldRegisterSecuritySyntaxChecker(const CheckerManager &mgr) {
1079e5dd7070Spatrick   return true;
1080e5dd7070Spatrick }
1081e5dd7070Spatrick 
1082e5dd7070Spatrick #define REGISTER_CHECKER(name)                                                 \
1083e5dd7070Spatrick   void ento::register##name(CheckerManager &mgr) {                             \
1084e5dd7070Spatrick     SecuritySyntaxChecker *checker = mgr.getChecker<SecuritySyntaxChecker>();  \
1085e5dd7070Spatrick     checker->filter.check_##name = true;                                       \
1086e5dd7070Spatrick     checker->filter.checkName_##name = mgr.getCurrentCheckerName();            \
1087e5dd7070Spatrick   }                                                                            \
1088e5dd7070Spatrick                                                                                \
1089ec727ea7Spatrick   bool ento::shouldRegister##name(const CheckerManager &mgr) { return true; }
1090e5dd7070Spatrick 
1091e5dd7070Spatrick REGISTER_CHECKER(bcmp)
1092e5dd7070Spatrick REGISTER_CHECKER(bcopy)
1093e5dd7070Spatrick REGISTER_CHECKER(bzero)
1094e5dd7070Spatrick REGISTER_CHECKER(gets)
1095e5dd7070Spatrick REGISTER_CHECKER(getpw)
1096e5dd7070Spatrick REGISTER_CHECKER(mkstemp)
1097e5dd7070Spatrick REGISTER_CHECKER(mktemp)
1098e5dd7070Spatrick REGISTER_CHECKER(strcpy)
1099e5dd7070Spatrick REGISTER_CHECKER(rand)
1100e5dd7070Spatrick REGISTER_CHECKER(vfork)
1101e5dd7070Spatrick REGISTER_CHECKER(FloatLoopCounter)
1102e5dd7070Spatrick REGISTER_CHECKER(UncheckedReturn)
1103e5dd7070Spatrick REGISTER_CHECKER(DeprecatedOrUnsafeBufferHandling)
1104e5dd7070Spatrick REGISTER_CHECKER(decodeValueOfObjCType)
1105