]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/CheckSecuritySyntaxOnly.cpp
Import libxo-1.3.0:
[FreeBSD/FreeBSD.git] / contrib / llvm / tools / clang / lib / StaticAnalyzer / Checkers / CheckSecuritySyntaxOnly.cpp
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)