]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/CheckSecuritySyntaxOnly.cpp
MFV r338519:
[FreeBSD/FreeBSD.git] / contrib / llvm / tools / clang / lib / StaticAnalyzer / Checkers / CheckSecuritySyntaxOnly.cpp
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   // Issue a warning.
514   PathDiagnosticLocation CELoc =
515     PathDiagnosticLocation::createBegin(CE, BR.getSourceManager(), AC);
516   BR.EmitBasicReport(AC->getDecl(), filter.checkName_strcpy,
517                      "Potential insecure memory buffer bounds restriction in "
518                      "call 'strcpy'",
519                      "Security",
520                      "Call to function 'strcpy' is insecure as it does not "
521                      "provide bounding of the memory buffer. Replace "
522                      "unbounded copy functions with analogous functions that "
523                      "support length arguments such as 'strlcpy'. CWE-119.",
524                      CELoc, CE->getCallee()->getSourceRange());
525 }
526
527 //===----------------------------------------------------------------------===//
528 // Check: Any use of 'strcat' is insecure.
529 //
530 // CWE-119: Improper Restriction of Operations within
531 // the Bounds of a Memory Buffer
532 //===----------------------------------------------------------------------===//
533 void WalkAST::checkCall_strcat(const CallExpr *CE, const FunctionDecl *FD) {
534   if (!filter.check_strcpy)
535     return;
536
537   if (!checkCall_strCommon(CE, FD))
538     return;
539
540   // Issue a warning.
541   PathDiagnosticLocation CELoc =
542     PathDiagnosticLocation::createBegin(CE, BR.getSourceManager(), AC);
543   BR.EmitBasicReport(AC->getDecl(), filter.checkName_strcpy,
544                      "Potential insecure memory buffer bounds restriction in "
545                      "call 'strcat'",
546                      "Security",
547                      "Call to function 'strcat' is insecure as it does not "
548                      "provide bounding of the memory buffer. Replace "
549                      "unbounded copy functions with analogous functions that "
550                      "support length arguments such as 'strlcat'. CWE-119.",
551                      CELoc, CE->getCallee()->getSourceRange());
552 }
553
554 //===----------------------------------------------------------------------===//
555 // Common check for str* functions with no bounds parameters.
556 //===----------------------------------------------------------------------===//
557 bool WalkAST::checkCall_strCommon(const CallExpr *CE, const FunctionDecl *FD) {
558   const FunctionProtoType *FPT = FD->getType()->getAs<FunctionProtoType>();
559   if (!FPT)
560     return false;
561
562   // Verify the function takes two arguments, three in the _chk version.
563   int numArgs = FPT->getNumParams();
564   if (numArgs != 2 && numArgs != 3)
565     return false;
566
567   // Verify the type for both arguments.
568   for (int i = 0; i < 2; i++) {
569     // Verify that the arguments are pointers.
570     const PointerType *PT = FPT->getParamType(i)->getAs<PointerType>();
571     if (!PT)
572       return false;
573
574     // Verify that the argument is a 'char*'.
575     if (PT->getPointeeType().getUnqualifiedType() != BR.getContext().CharTy)
576       return false;
577   }
578
579   return true;
580 }
581
582 //===----------------------------------------------------------------------===//
583 // Check: Linear congruent random number generators should not be used
584 // Originally: <rdar://problem/63371000>
585 // CWE-338: Use of cryptographically weak prng
586 //===----------------------------------------------------------------------===//
587
588 void WalkAST::checkCall_rand(const CallExpr *CE, const FunctionDecl *FD) {
589   if (!filter.check_rand || !CheckRand)
590     return;
591
592   const FunctionProtoType *FTP = FD->getType()->getAs<FunctionProtoType>();
593   if (!FTP)
594     return;
595
596   if (FTP->getNumParams() == 1) {
597     // Is the argument an 'unsigned short *'?
598     // (Actually any integer type is allowed.)
599     const PointerType *PT = FTP->getParamType(0)->getAs<PointerType>();
600     if (!PT)
601       return;
602
603     if (! PT->getPointeeType()->isIntegralOrUnscopedEnumerationType())
604       return;
605   } else if (FTP->getNumParams() != 0)
606     return;
607
608   // Issue a warning.
609   SmallString<256> buf1;
610   llvm::raw_svector_ostream os1(buf1);
611   os1 << '\'' << *FD << "' is a poor random number generator";
612
613   SmallString<256> buf2;
614   llvm::raw_svector_ostream os2(buf2);
615   os2 << "Function '" << *FD
616       << "' is obsolete because it implements a poor random number generator."
617       << "  Use 'arc4random' instead";
618
619   PathDiagnosticLocation CELoc =
620     PathDiagnosticLocation::createBegin(CE, BR.getSourceManager(), AC);
621   BR.EmitBasicReport(AC->getDecl(), filter.checkName_rand, os1.str(),
622                      "Security", os2.str(), CELoc,
623                      CE->getCallee()->getSourceRange());
624 }
625
626 //===----------------------------------------------------------------------===//
627 // Check: 'random' should not be used
628 // Originally: <rdar://problem/63371000>
629 //===----------------------------------------------------------------------===//
630
631 void WalkAST::checkCall_random(const CallExpr *CE, const FunctionDecl *FD) {
632   if (!CheckRand || !filter.check_rand)
633     return;
634
635   const FunctionProtoType *FTP = FD->getType()->getAs<FunctionProtoType>();
636   if (!FTP)
637     return;
638
639   // Verify that the function takes no argument.
640   if (FTP->getNumParams() != 0)
641     return;
642
643   // Issue a warning.
644   PathDiagnosticLocation CELoc =
645     PathDiagnosticLocation::createBegin(CE, BR.getSourceManager(), AC);
646   BR.EmitBasicReport(AC->getDecl(), filter.checkName_rand,
647                      "'random' is not a secure random number generator",
648                      "Security",
649                      "The 'random' function produces a sequence of values that "
650                      "an adversary may be able to predict.  Use 'arc4random' "
651                      "instead", CELoc, CE->getCallee()->getSourceRange());
652 }
653
654 //===----------------------------------------------------------------------===//
655 // Check: 'vfork' should not be used.
656 // POS33-C: Do not use vfork().
657 //===----------------------------------------------------------------------===//
658
659 void WalkAST::checkCall_vfork(const CallExpr *CE, const FunctionDecl *FD) {
660   if (!filter.check_vfork)
661     return;
662
663   // All calls to vfork() are insecure, issue a warning.
664   PathDiagnosticLocation CELoc =
665     PathDiagnosticLocation::createBegin(CE, BR.getSourceManager(), AC);
666   BR.EmitBasicReport(AC->getDecl(), filter.checkName_vfork,
667                      "Potential insecure implementation-specific behavior in "
668                      "call 'vfork'",
669                      "Security",
670                      "Call to function 'vfork' is insecure as it can lead to "
671                      "denial of service situations in the parent process. "
672                      "Replace calls to vfork with calls to the safer "
673                      "'posix_spawn' function",
674                      CELoc, CE->getCallee()->getSourceRange());
675 }
676
677 //===----------------------------------------------------------------------===//
678 // Check: Should check whether privileges are dropped successfully.
679 // Originally: <rdar://problem/6337132>
680 //===----------------------------------------------------------------------===//
681
682 void WalkAST::checkUncheckedReturnValue(CallExpr *CE) {
683   if (!filter.check_UncheckedReturn)
684     return;
685
686   const FunctionDecl *FD = CE->getDirectCallee();
687   if (!FD)
688     return;
689
690   if (II_setid[0] == nullptr) {
691     static const char * const identifiers[num_setids] = {
692       "setuid", "setgid", "seteuid", "setegid",
693       "setreuid", "setregid"
694     };
695
696     for (size_t i = 0; i < num_setids; i++)
697       II_setid[i] = &BR.getContext().Idents.get(identifiers[i]);
698   }
699
700   const IdentifierInfo *id = FD->getIdentifier();
701   size_t identifierid;
702
703   for (identifierid = 0; identifierid < num_setids; identifierid++)
704     if (id == II_setid[identifierid])
705       break;
706
707   if (identifierid >= num_setids)
708     return;
709
710   const FunctionProtoType *FTP = FD->getType()->getAs<FunctionProtoType>();
711   if (!FTP)
712     return;
713
714   // Verify that the function takes one or two arguments (depending on
715   //   the function).
716   if (FTP->getNumParams() != (identifierid < 4 ? 1 : 2))
717     return;
718
719   // The arguments must be integers.
720   for (unsigned i = 0; i < FTP->getNumParams(); i++)
721     if (!FTP->getParamType(i)->isIntegralOrUnscopedEnumerationType())
722       return;
723
724   // Issue a warning.
725   SmallString<256> buf1;
726   llvm::raw_svector_ostream os1(buf1);
727   os1 << "Return value is not checked in call to '" << *FD << '\'';
728
729   SmallString<256> buf2;
730   llvm::raw_svector_ostream os2(buf2);
731   os2 << "The return value from the call to '" << *FD
732       << "' is not checked.  If an error occurs in '" << *FD
733       << "', the following code may execute with unexpected privileges";
734
735   PathDiagnosticLocation CELoc =
736     PathDiagnosticLocation::createBegin(CE, BR.getSourceManager(), AC);
737   BR.EmitBasicReport(AC->getDecl(), filter.checkName_UncheckedReturn, os1.str(),
738                      "Security", os2.str(), CELoc,
739                      CE->getCallee()->getSourceRange());
740 }
741
742 //===----------------------------------------------------------------------===//
743 // SecuritySyntaxChecker
744 //===----------------------------------------------------------------------===//
745
746 namespace {
747 class SecuritySyntaxChecker : public Checker<check::ASTCodeBody> {
748 public:
749   ChecksFilter filter;
750
751   void checkASTCodeBody(const Decl *D, AnalysisManager& mgr,
752                         BugReporter &BR) const {
753     WalkAST walker(BR, mgr.getAnalysisDeclContext(D), filter);
754     walker.Visit(D->getBody());
755   }
756 };
757 }
758
759 #define REGISTER_CHECKER(name)                                                 \
760   void ento::register##name(CheckerManager &mgr) {                             \
761     SecuritySyntaxChecker *checker =                                           \
762         mgr.registerChecker<SecuritySyntaxChecker>();                          \
763     checker->filter.check_##name = true;                                       \
764     checker->filter.checkName_##name = mgr.getCurrentCheckName();              \
765   }
766
767 REGISTER_CHECKER(gets)
768 REGISTER_CHECKER(getpw)
769 REGISTER_CHECKER(mkstemp)
770 REGISTER_CHECKER(mktemp)
771 REGISTER_CHECKER(strcpy)
772 REGISTER_CHECKER(rand)
773 REGISTER_CHECKER(vfork)
774 REGISTER_CHECKER(FloatLoopCounter)
775 REGISTER_CHECKER(UncheckedReturn)
776
777