Clang Project

clang_source_code/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
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.getOS() == llvm::Triple::CloudABI ||
31         T.isOSFreeBSD() ||
32         T.isOSNetBSD() ||
33         T.isOSOpenBSD() ||
34         T.isOSDragonFly();
35}
36
37namespace {
38struct 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
68class WalkAST : public StmtVisitor<WalkAST> {
69  BugReporter &BR;
70  AnalysisDeclContextAC;
71  enum { num_setids = 6 };
72  IdentifierInfo *II_setid[num_setids];
73
74  const bool CheckRand;
75  const ChecksFilter &filter;
76
77public:
78  WalkAST(BugReporter &brAnalysisDeclContextac,
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 *CEconst 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 *CEconst FunctionDecl *FD);
100  void checkCall_bcopy(const CallExpr *CEconst FunctionDecl *FD);
101  void checkCall_bzero(const CallExpr *CEconst FunctionDecl *FD);
102  void checkCall_gets(const CallExpr *CEconst FunctionDecl *FD);
103  void checkCall_getpw(const CallExpr *CEconst FunctionDecl *FD);
104  void checkCall_mktemp(const CallExpr *CEconst FunctionDecl *FD);
105  void checkCall_mkstemp(const CallExpr *CEconst FunctionDecl *FD);
106  void checkCall_strcpy(const CallExpr *CEconst FunctionDecl *FD);
107  void checkCall_strcat(const CallExpr *CEconst FunctionDecl *FD);
108  void checkDeprecatedOrUnsafeBufferHandling(const CallExpr *CE,
109                                             const FunctionDecl *FD);
110  void checkCall_rand(const CallExpr *CEconst FunctionDecl *FD);
111  void checkCall_random(const CallExpr *CEconst FunctionDecl *FD);
112  void checkCall_vfork(const CallExpr *CEconst FunctionDecl *FD);
113  void checkUncheckedReturnValue(CallExpr *CE);
114};
115// end anonymous namespace
116
117//===----------------------------------------------------------------------===//
118// AST walking.
119//===----------------------------------------------------------------------===//
120
121void WalkAST::VisitChildren(Stmt *S) {
122  for (Stmt *Child : S->children())
123    if (Child)
124      Visit(Child);
125}
126
127void 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)(CEFD);
180
181  // Recurse and check children.
182  VisitChildren(CE);
183}
184
185void 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
194void 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
207static const DeclRefExpr*
208getIncrementedVar(const Expr *exprconst VarDecl *xconst 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(), xy))
217      return lhs;
218
219    if (const DeclRefExpr *rhs = getIncrementedVar(B->getRHS(), xy))
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(), xy) : 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///
241void 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(incrementvdLHSvdRHS);
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  getDecl()", "/home/seafit/code_projects/clang_source/clang/lib/StaticAnalyzer/Checkers/CheckSecuritySyntaxOnly.cpp", 298, __PRETTY_FUNCTION__))" file_link="../../../../include/assert.h.html#88" macro="true">assert(drInc->getDecl());
299  const DeclRefExpr *drCond = vdLHS == drInc->getDecl() ? drLHS : drRHS;
300
301  SmallVector<SourceRange2ranges;
302  SmallString<256sbuf;
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(FSBR.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
327void WalkAST::checkCall_bcmp(const CallExpr *CEconst 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 = 0i < 2i++) {
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(CEBR.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                     CELocCE->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
369void WalkAST::checkCall_bcopy(const CallExpr *CEconst 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 = 0i < 2i++) {
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(CEBR.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                     CELocCE->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
412void WalkAST::checkCall_bzero(const CallExpr *CEconst 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(CEBR.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                     CELocCE->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
454void WalkAST::checkCall_gets(const CallExpr *CEconst 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(CEBR.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                     CELocCE->getCallee()->getSourceRange());
483}
484
485//===----------------------------------------------------------------------===//
486// Check: Any use of 'getpwd' is insecure.
487// CWE-477: Use of Obsolete Functions
488//===----------------------------------------------------------------------===//
489
490void WalkAST::checkCall_getpw(const CallExpr *CEconst 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(CEBR.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                     CELocCE->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
530void WalkAST::checkCall_mktemp(const CallExpr *CEconst 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(CEFD);
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(CEBR.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                     CELocCE->getCallee()->getSourceRange());
565}
566
567//===----------------------------------------------------------------------===//
568// Check: Use of 'mkstemp', 'mktemp', 'mkdtemp' should contain at least 6 X's.
569//===----------------------------------------------------------------------===//
570
571void WalkAST::checkCall_mkstemp(const CallExpr *CEconst FunctionDecl *FD) {
572  if (!filter.check_mkstemp)
573    return;
574
575  StringRef Name = FD->getIdentifier()->getName();
576  std::pair<signedsignedArgSuffix =
577    llvm::StringSwitch<std::pair<signedsigned> >(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   (0) . __assert_fail ("ArgSuffix.first >= 0 && \"Unsupported function\"", "/home/seafit/code_projects/clang_source/clang/lib/StaticAnalyzer/Checkers/CheckSecuritySyntaxOnly.cpp", 584, __PRETTY_FUNCTION__))" file_link="../../../../include/assert.h.html#88" macro="true">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 ((signednumArgs <= 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(EVResultBR.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 = 0i < 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(CEBR.getSourceManager(), AC);
630  SmallString<512buf;
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
656void WalkAST::checkCall_strcpy(const CallExpr *CEconst FunctionDecl *FD) {
657  if (!filter.check_strcpy)
658    return;
659
660  if (!checkCall_strCommon(CEFD))
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(CEBR.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                     CELocCE->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
695void WalkAST::checkCall_strcat(const CallExpr *CEconst FunctionDecl *FD) {
696  if (!filter.check_strcpy)
697    return;
698
699  if (!checkCall_strCommon(CEFD))
700    return;
701
702  // Issue a warning.
703  PathDiagnosticLocation CELoc =
704    PathDiagnosticLocation::createBegin(CEBR.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                     CELocCE->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
732void 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 = -1UNKNOWN_CALL = -2 };
743  StringRef Name = FD->getIdentifier()->getName();
744  int ArgIndex =
745      llvm::StringSwitch<int>(Name)
746          .Cases("scanf""wscanf""vscanf""vwscanf"0)
747          .Cases("sprintf""vsprintf""fscanf""fwscanf""vfscanf",
748                 "vfwscanf""sscanf""swscanf""vsscanf""vswscanf"1)
749          .Cases("swprintf""snprintf""vswprintf""vsnprintf""memcpy",
750                 "memmove""memset""strncpy""strncat", DEPR_ONLY)
751          .Default(UNKNOWN_CALL);
752
753   (0) . __assert_fail ("ArgIndex != UNKNOWN_CALL && \"Unsupported function\"", "/home/seafit/code_projects/clang_source/clang/lib/StaticAnalyzer/Checkers/CheckSecuritySyntaxOnly.cpp", 753, __PRETTY_FUNCTION__))" file_link="../../../../include/assert.h.html#88" macro="true">assert(ArgIndex != UNKNOWN_CALL && "Unsupported function");
754  bool BoundsProvided = ArgIndex == DEPR_ONLY;
755
756  if (!BoundsProvided) {
757    // Currently we only handle (not wide) string literals. It is possible to do
758    // better, either by looking at references to const variables, or by doing
759    // real flow analysis.
760    auto FormatString =
761        dyn_cast<StringLiteral>(CE->getArg(ArgIndex)->IgnoreParenImpCasts());
762    if (FormatString &&
763        FormatString->getString().find("%s") == StringRef::npos &&
764        FormatString->getString().find("%[") == StringRef::npos)
765      BoundsProvided = true;
766  }
767
768  SmallString<128Buf1;
769  SmallString<512Buf2;
770  llvm::raw_svector_ostream Out1(Buf1);
771  llvm::raw_svector_ostream Out2(Buf2);
772
773  Out1 << "Potential insecure memory buffer bounds restriction in call '"
774       << Name << "'";
775  Out2 << "Call to function '" << Name
776       << "' is insecure as it does not provide ";
777
778  if (!BoundsProvided) {
779    Out2 << "bounding of the memory buffer or ";
780  }
781
782  Out2 << "security checks introduced "
783          "in the C11 standard. Replace with analogous functions that "
784          "support length arguments or provides boundary checks such as '"
785       << Name << "_s' in case of C11";
786
787  PathDiagnosticLocation CELoc =
788      PathDiagnosticLocation::createBegin(CEBR.getSourceManager(), AC);
789  BR.EmitBasicReport(AC->getDecl(),
790                     filter.checkName_DeprecatedOrUnsafeBufferHandling,
791                     Out1.str(), "Security", Out2.str(), CELoc,
792                     CE->getCallee()->getSourceRange());
793}
794
795//===----------------------------------------------------------------------===//
796// Common check for str* functions with no bounds parameters.
797//===----------------------------------------------------------------------===//
798
799bool WalkAST::checkCall_strCommon(const CallExpr *CEconst FunctionDecl *FD) {
800  const FunctionProtoType *FPT = FD->getType()->getAs<FunctionProtoType>();
801  if (!FPT)
802    return false;
803
804  // Verify the function takes two arguments, three in the _chk version.
805  int numArgs = FPT->getNumParams();
806  if (numArgs != 2 && numArgs != 3)
807    return false;
808
809  // Verify the type for both arguments.
810  for (int i = 0i < 2i++) {
811    // Verify that the arguments are pointers.
812    const PointerType *PT = FPT->getParamType(i)->getAs<PointerType>();
813    if (!PT)
814      return false;
815
816    // Verify that the argument is a 'char*'.
817    if (PT->getPointeeType().getUnqualifiedType() != BR.getContext().CharTy)
818      return false;
819  }
820
821  return true;
822}
823
824//===----------------------------------------------------------------------===//
825// Check: Linear congruent random number generators should not be used
826// Originally: <rdar://problem/63371000>
827// CWE-338: Use of cryptographically weak prng
828//===----------------------------------------------------------------------===//
829
830void WalkAST::checkCall_rand(const CallExpr *CEconst FunctionDecl *FD) {
831  if (!filter.check_rand || !CheckRand)
832    return;
833
834  const FunctionProtoType *FTP = FD->getType()->getAs<FunctionProtoType>();
835  if (!FTP)
836    return;
837
838  if (FTP->getNumParams() == 1) {
839    // Is the argument an 'unsigned short *'?
840    // (Actually any integer type is allowed.)
841    const PointerType *PT = FTP->getParamType(0)->getAs<PointerType>();
842    if (!PT)
843      return;
844
845    if (! PT->getPointeeType()->isIntegralOrUnscopedEnumerationType())
846      return;
847  } else if (FTP->getNumParams() != 0)
848    return;
849
850  // Issue a warning.
851  SmallString<256buf1;
852  llvm::raw_svector_ostream os1(buf1);
853  os1 << '\'' << *FD << "' is a poor random number generator";
854
855  SmallString<256buf2;
856  llvm::raw_svector_ostream os2(buf2);
857  os2 << "Function '" << *FD
858      << "' is obsolete because it implements a poor random number generator."
859      << "  Use 'arc4random' instead";
860
861  PathDiagnosticLocation CELoc =
862    PathDiagnosticLocation::createBegin(CEBR.getSourceManager(), AC);
863  BR.EmitBasicReport(AC->getDecl(), filter.checkName_rand, os1.str(),
864                     "Security", os2.str(), CELoc,
865                     CE->getCallee()->getSourceRange());
866}
867
868//===----------------------------------------------------------------------===//
869// Check: 'random' should not be used
870// Originally: <rdar://problem/63371000>
871//===----------------------------------------------------------------------===//
872
873void WalkAST::checkCall_random(const CallExpr *CEconst FunctionDecl *FD) {
874  if (!CheckRand || !filter.check_rand)
875    return;
876
877  const FunctionProtoType *FTP = FD->getType()->getAs<FunctionProtoType>();
878  if (!FTP)
879    return;
880
881  // Verify that the function takes no argument.
882  if (FTP->getNumParams() != 0)
883    return;
884
885  // Issue a warning.
886  PathDiagnosticLocation CELoc =
887    PathDiagnosticLocation::createBegin(CEBR.getSourceManager(), AC);
888  BR.EmitBasicReport(AC->getDecl(), filter.checkName_rand,
889                     "'random' is not a secure random number generator",
890                     "Security",
891                     "The 'random' function produces a sequence of values that "
892                     "an adversary may be able to predict.  Use 'arc4random' "
893                     "instead"CELocCE->getCallee()->getSourceRange());
894}
895
896//===----------------------------------------------------------------------===//
897// Check: 'vfork' should not be used.
898// POS33-C: Do not use vfork().
899//===----------------------------------------------------------------------===//
900
901void WalkAST::checkCall_vfork(const CallExpr *CEconst FunctionDecl *FD) {
902  if (!filter.check_vfork)
903    return;
904
905  // All calls to vfork() are insecure, issue a warning.
906  PathDiagnosticLocation CELoc =
907    PathDiagnosticLocation::createBegin(CEBR.getSourceManager(), AC);
908  BR.EmitBasicReport(AC->getDecl(), filter.checkName_vfork,
909                     "Potential insecure implementation-specific behavior in "
910                     "call 'vfork'",
911                     "Security",
912                     "Call to function 'vfork' is insecure as it can lead to "
913                     "denial of service situations in the parent process. "
914                     "Replace calls to vfork with calls to the safer "
915                     "'posix_spawn' function",
916                     CELocCE->getCallee()->getSourceRange());
917}
918
919//===----------------------------------------------------------------------===//
920// Check: Should check whether privileges are dropped successfully.
921// Originally: <rdar://problem/6337132>
922//===----------------------------------------------------------------------===//
923
924void WalkAST::checkUncheckedReturnValue(CallExpr *CE) {
925  if (!filter.check_UncheckedReturn)
926    return;
927
928  const FunctionDecl *FD = CE->getDirectCallee();
929  if (!FD)
930    return;
931
932  if (II_setid[0] == nullptr) {
933    static const char * const identifiers[num_setids] = {
934      "setuid""setgid""seteuid""setegid",
935      "setreuid""setregid"
936    };
937
938    for (size_t i = 0; i < num_setids; i++)
939      II_setid[i] = &BR.getContext().Idents.get(identifiers[i]);
940  }
941
942  const IdentifierInfo *id = FD->getIdentifier();
943  size_t identifierid;
944
945  for (identifierid = 0; identifierid < num_setids; identifierid++)
946    if (id == II_setid[identifierid])
947      break;
948
949  if (identifierid >= num_setids)
950    return;
951
952  const FunctionProtoType *FTP = FD->getType()->getAs<FunctionProtoType>();
953  if (!FTP)
954    return;
955
956  // Verify that the function takes one or two arguments (depending on
957  //   the function).
958  if (FTP->getNumParams() != (identifierid < 4 ? 1 : 2))
959    return;
960
961  // The arguments must be integers.
962  for (unsigned i = 0i < FTP->getNumParams(); i++)
963    if (!FTP->getParamType(i)->isIntegralOrUnscopedEnumerationType())
964      return;
965
966  // Issue a warning.
967  SmallString<256buf1;
968  llvm::raw_svector_ostream os1(buf1);
969  os1 << "Return value is not checked in call to '" << *FD << '\'';
970
971  SmallString<256buf2;
972  llvm::raw_svector_ostream os2(buf2);
973  os2 << "The return value from the call to '" << *FD
974      << "' is not checked.  If an error occurs in '" << *FD
975      << "', the following code may execute with unexpected privileges";
976
977  PathDiagnosticLocation CELoc =
978    PathDiagnosticLocation::createBegin(CEBR.getSourceManager(), AC);
979  BR.EmitBasicReport(AC->getDecl(), filter.checkName_UncheckedReturn, os1.str(),
980                     "Security", os2.str(), CELoc,
981                     CE->getCallee()->getSourceRange());
982}
983
984//===----------------------------------------------------------------------===//
985// SecuritySyntaxChecker
986//===----------------------------------------------------------------------===//
987
988namespace {
989class SecuritySyntaxChecker : public Checker<check::ASTCodeBody> {
990public:
991  ChecksFilter filter;
992
993  void checkASTCodeBody(const Decl *DAnalysisManagermgr,
994                        BugReporter &BRconst {
995    WalkAST walker(BR, mgr.getAnalysisDeclContext(D), filter);
996    walker.Visit(D->getBody());
997  }
998};
999}
1000
1001void ento::registerSecuritySyntaxChecker(CheckerManager &mgr) {
1002  mgr.registerChecker<SecuritySyntaxChecker>();
1003}
1004
1005bool ento::shouldRegisterSecuritySyntaxChecker(const LangOptions &LO) {
1006  return true;
1007}
1008
1009#define REGISTER_CHECKER(name)                                                 \
1010  void ento::register##name(CheckerManager &mgr) {                             \
1011    SecuritySyntaxChecker *checker =  mgr.getChecker<SecuritySyntaxChecker>(); \
1012    checker->filter.check_##name = true;                                       \
1013    checker->filter.checkName_##name = mgr.getCurrentCheckName();              \
1014  }                                                                            \
1015                                                                               \
1016  bool ento::shouldRegister##name(const LangOptions &LO) {                     \
1017    return true;                                                               \
1018  }
1019
1020REGISTER_CHECKER(bcmp)
1021REGISTER_CHECKER(bcopy)
1022REGISTER_CHECKER(bzero)
1023REGISTER_CHECKER(gets)
1024REGISTER_CHECKER(getpw)
1025REGISTER_CHECKER(mkstemp)
1026REGISTER_CHECKER(mktemp)
1027REGISTER_CHECKER(strcpy)
1028REGISTER_CHECKER(rand)
1029REGISTER_CHECKER(vfork)
1030REGISTER_CHECKER(FloatLoopCounter)
1031REGISTER_CHECKER(UncheckedReturn)
1032REGISTER_CHECKER(DeprecatedOrUnsafeBufferHandling)
1033