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