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