]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - lib/StaticAnalyzer/Checkers/CheckSecuritySyntaxOnly.cpp
Vendor import of stripped clang trunk r375505, the last commit before
[FreeBSD/FreeBSD.git] / 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   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)