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