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