clang  10.0.0svn
CheckSecuritySyntaxOnly.cpp
Go to the documentation of this file.
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 
14 #include "clang/AST/StmtVisitor.h"
16 #include "clang/Basic/TargetInfo.h"
20 #include "llvm/ADT/SmallString.h"
21 #include "llvm/ADT/StringSwitch.h"
22 #include "llvm/Support/raw_ostream.h"
23 
24 using namespace clang;
25 using namespace ento;
26 
27 static bool isArc4RandomAvailable(const ASTContext &Ctx) {
28  const llvm::Triple &T = Ctx.getTargetInfo().getTriple();
29  return T.getVendor() == llvm::Triple::Apple ||
30  T.getOS() == llvm::Triple::CloudABI ||
31  T.isOSFreeBSD() ||
32  T.isOSNetBSD() ||
33  T.isOSOpenBSD() ||
34  T.isOSDragonFly();
35 }
36 
37 namespace {
38 struct ChecksFilter {
39  DefaultBool check_bcmp;
40  DefaultBool check_bcopy;
41  DefaultBool check_bzero;
42  DefaultBool check_gets;
43  DefaultBool check_getpw;
44  DefaultBool check_mktemp;
45  DefaultBool check_mkstemp;
46  DefaultBool check_strcpy;
47  DefaultBool check_DeprecatedOrUnsafeBufferHandling;
48  DefaultBool check_rand;
49  DefaultBool check_vfork;
50  DefaultBool check_FloatLoopCounter;
51  DefaultBool check_UncheckedReturn;
52 
53  CheckName checkName_bcmp;
54  CheckName checkName_bcopy;
55  CheckName checkName_bzero;
56  CheckName checkName_gets;
57  CheckName checkName_getpw;
58  CheckName checkName_mktemp;
59  CheckName checkName_mkstemp;
60  CheckName checkName_strcpy;
61  CheckName checkName_DeprecatedOrUnsafeBufferHandling;
62  CheckName checkName_rand;
63  CheckName checkName_vfork;
64  CheckName checkName_FloatLoopCounter;
65  CheckName checkName_UncheckedReturn;
66 };
67 
68 class WalkAST : public StmtVisitor<WalkAST> {
69  BugReporter &BR;
71  enum { num_setids = 6 };
72  IdentifierInfo *II_setid[num_setids];
73 
74  const bool CheckRand;
75  const ChecksFilter &filter;
76 
77 public:
78  WalkAST(BugReporter &br, AnalysisDeclContext* ac,
79  const ChecksFilter &f)
80  : BR(br), AC(ac), II_setid(),
81  CheckRand(isArc4RandomAvailable(BR.getContext())),
82  filter(f) {}
83 
84  // Statement visitor methods.
85  void VisitCallExpr(CallExpr *CE);
86  void VisitForStmt(ForStmt *S);
87  void VisitCompoundStmt (CompoundStmt *S);
88  void VisitStmt(Stmt *S) { VisitChildren(S); }
89 
90  void VisitChildren(Stmt *S);
91 
92  // Helpers.
93  bool checkCall_strCommon(const CallExpr *CE, const FunctionDecl *FD);
94 
95  typedef void (WalkAST::*FnCheck)(const CallExpr *, const FunctionDecl *);
96 
97  // Checker-specific methods.
98  void checkLoopConditionForFloat(const ForStmt *FS);
99  void checkCall_bcmp(const CallExpr *CE, const FunctionDecl *FD);
100  void checkCall_bcopy(const CallExpr *CE, const FunctionDecl *FD);
101  void checkCall_bzero(const CallExpr *CE, const FunctionDecl *FD);
102  void checkCall_gets(const CallExpr *CE, const FunctionDecl *FD);
103  void checkCall_getpw(const CallExpr *CE, const FunctionDecl *FD);
104  void checkCall_mktemp(const CallExpr *CE, const FunctionDecl *FD);
105  void checkCall_mkstemp(const CallExpr *CE, const FunctionDecl *FD);
106  void checkCall_strcpy(const CallExpr *CE, const FunctionDecl *FD);
107  void checkCall_strcat(const CallExpr *CE, const FunctionDecl *FD);
108  void checkDeprecatedOrUnsafeBufferHandling(const CallExpr *CE,
109  const FunctionDecl *FD);
110  void checkCall_rand(const CallExpr *CE, const FunctionDecl *FD);
111  void checkCall_random(const CallExpr *CE, const FunctionDecl *FD);
112  void checkCall_vfork(const CallExpr *CE, const FunctionDecl *FD);
113  void checkUncheckedReturnValue(CallExpr *CE);
114 };
115 } // end anonymous namespace
116 
117 //===----------------------------------------------------------------------===//
118 // AST walking.
119 //===----------------------------------------------------------------------===//
120 
121 void WalkAST::VisitChildren(Stmt *S) {
122  for (Stmt *Child : S->children())
123  if (Child)
124  Visit(Child);
125 }
126 
127 void WalkAST::VisitCallExpr(CallExpr *CE) {
128  // Get the callee.
129  const FunctionDecl *FD = CE->getDirectCallee();
130 
131  if (!FD)
132  return;
133 
134  // Get the name of the callee. If it's a builtin, strip off the prefix.
135  IdentifierInfo *II = FD->getIdentifier();
136  if (!II) // if no identifier, not a simple C function
137  return;
138  StringRef Name = II->getName();
139  if (Name.startswith("__builtin_"))
140  Name = Name.substr(10);
141 
142  // Set the evaluation function by switching on the callee name.
143  FnCheck evalFunction = llvm::StringSwitch<FnCheck>(Name)
144  .Case("bcmp", &WalkAST::checkCall_bcmp)
145  .Case("bcopy", &WalkAST::checkCall_bcopy)
146  .Case("bzero", &WalkAST::checkCall_bzero)
147  .Case("gets", &WalkAST::checkCall_gets)
148  .Case("getpw", &WalkAST::checkCall_getpw)
149  .Case("mktemp", &WalkAST::checkCall_mktemp)
150  .Case("mkstemp", &WalkAST::checkCall_mkstemp)
151  .Case("mkdtemp", &WalkAST::checkCall_mkstemp)
152  .Case("mkstemps", &WalkAST::checkCall_mkstemp)
153  .Cases("strcpy", "__strcpy_chk", &WalkAST::checkCall_strcpy)
154  .Cases("strcat", "__strcat_chk", &WalkAST::checkCall_strcat)
155  .Cases("sprintf", "vsprintf", "scanf", "wscanf", "fscanf", "fwscanf",
156  "vscanf", "vwscanf", "vfscanf", "vfwscanf",
157  &WalkAST::checkDeprecatedOrUnsafeBufferHandling)
158  .Cases("sscanf", "swscanf", "vsscanf", "vswscanf", "swprintf",
159  "snprintf", "vswprintf", "vsnprintf", "memcpy", "memmove",
160  &WalkAST::checkDeprecatedOrUnsafeBufferHandling)
161  .Cases("strncpy", "strncat", "memset",
162  &WalkAST::checkDeprecatedOrUnsafeBufferHandling)
163  .Case("drand48", &WalkAST::checkCall_rand)
164  .Case("erand48", &WalkAST::checkCall_rand)
165  .Case("jrand48", &WalkAST::checkCall_rand)
166  .Case("lrand48", &WalkAST::checkCall_rand)
167  .Case("mrand48", &WalkAST::checkCall_rand)
168  .Case("nrand48", &WalkAST::checkCall_rand)
169  .Case("lcong48", &WalkAST::checkCall_rand)
170  .Case("rand", &WalkAST::checkCall_rand)
171  .Case("rand_r", &WalkAST::checkCall_rand)
172  .Case("random", &WalkAST::checkCall_random)
173  .Case("vfork", &WalkAST::checkCall_vfork)
174  .Default(nullptr);
175 
176  // If the callee isn't defined, it is not of security concern.
177  // Check and evaluate the call.
178  if (evalFunction)
179  (this->*evalFunction)(CE, FD);
180 
181  // Recurse and check children.
182  VisitChildren(CE);
183 }
184 
185 void WalkAST::VisitCompoundStmt(CompoundStmt *S) {
186  for (Stmt *Child : S->children())
187  if (Child) {
188  if (CallExpr *CE = dyn_cast<CallExpr>(Child))
189  checkUncheckedReturnValue(CE);
190  Visit(Child);
191  }
192 }
193 
194 void WalkAST::VisitForStmt(ForStmt *FS) {
195  checkLoopConditionForFloat(FS);
196 
197  // Recurse and check children.
198  VisitChildren(FS);
199 }
200 
201 //===----------------------------------------------------------------------===//
202 // Check: floating point variable used as loop counter.
203 // Originally: <rdar://problem/6336718>
204 // Implements: CERT security coding advisory FLP-30.
205 //===----------------------------------------------------------------------===//
206 
207 static const DeclRefExpr*
208 getIncrementedVar(const Expr *expr, const VarDecl *x, const VarDecl *y) {
209  expr = expr->IgnoreParenCasts();
210 
211  if (const BinaryOperator *B = dyn_cast<BinaryOperator>(expr)) {
212  if (!(B->isAssignmentOp() || B->isCompoundAssignmentOp() ||
213  B->getOpcode() == BO_Comma))
214  return nullptr;
215 
216  if (const DeclRefExpr *lhs = getIncrementedVar(B->getLHS(), x, y))
217  return lhs;
218 
219  if (const DeclRefExpr *rhs = getIncrementedVar(B->getRHS(), x, y))
220  return rhs;
221 
222  return nullptr;
223  }
224 
225  if (const DeclRefExpr *DR = dyn_cast<DeclRefExpr>(expr)) {
226  const NamedDecl *ND = DR->getDecl();
227  return ND == x || ND == y ? DR : nullptr;
228  }
229 
230  if (const UnaryOperator *U = dyn_cast<UnaryOperator>(expr))
231  return U->isIncrementDecrementOp()
232  ? getIncrementedVar(U->getSubExpr(), x, y) : nullptr;
233 
234  return nullptr;
235 }
236 
237 /// CheckLoopConditionForFloat - This check looks for 'for' statements that
238 /// use a floating point variable as a loop counter.
239 /// CERT: FLP30-C, FLP30-CPP.
240 ///
241 void WalkAST::checkLoopConditionForFloat(const ForStmt *FS) {
242  if (!filter.check_FloatLoopCounter)
243  return;
244 
245  // Does the loop have a condition?
246  const Expr *condition = FS->getCond();
247 
248  if (!condition)
249  return;
250 
251  // Does the loop have an increment?
252  const Expr *increment = FS->getInc();
253 
254  if (!increment)
255  return;
256 
257  // Strip away '()' and casts.
258  condition = condition->IgnoreParenCasts();
259  increment = increment->IgnoreParenCasts();
260 
261  // Is the loop condition a comparison?
262  const BinaryOperator *B = dyn_cast<BinaryOperator>(condition);
263 
264  if (!B)
265  return;
266 
267  // Is this a comparison?
268  if (!(B->isRelationalOp() || B->isEqualityOp()))
269  return;
270 
271  // Are we comparing variables?
272  const DeclRefExpr *drLHS =
273  dyn_cast<DeclRefExpr>(B->getLHS()->IgnoreParenLValueCasts());
274  const DeclRefExpr *drRHS =
275  dyn_cast<DeclRefExpr>(B->getRHS()->IgnoreParenLValueCasts());
276 
277  // Does at least one of the variables have a floating point type?
278  drLHS = drLHS && drLHS->getType()->isRealFloatingType() ? drLHS : nullptr;
279  drRHS = drRHS && drRHS->getType()->isRealFloatingType() ? drRHS : nullptr;
280 
281  if (!drLHS && !drRHS)
282  return;
283 
284  const VarDecl *vdLHS = drLHS ? dyn_cast<VarDecl>(drLHS->getDecl()) : nullptr;
285  const VarDecl *vdRHS = drRHS ? dyn_cast<VarDecl>(drRHS->getDecl()) : nullptr;
286 
287  if (!vdLHS && !vdRHS)
288  return;
289 
290  // Does either variable appear in increment?
291  const DeclRefExpr *drInc = getIncrementedVar(increment, vdLHS, vdRHS);
292 
293  if (!drInc)
294  return;
295 
296  // Emit the error. First figure out which DeclRefExpr in the condition
297  // referenced the compared variable.
298  assert(drInc->getDecl());
299  const DeclRefExpr *drCond = vdLHS == drInc->getDecl() ? drLHS : drRHS;
300 
302  SmallString<256> sbuf;
303  llvm::raw_svector_ostream os(sbuf);
304 
305  os << "Variable '" << drCond->getDecl()->getName()
306  << "' with floating point type '" << drCond->getType().getAsString()
307  << "' should not be used as a loop counter";
308 
309  ranges.push_back(drCond->getSourceRange());
310  ranges.push_back(drInc->getSourceRange());
311 
312  const char *bugType = "Floating point variable used as loop counter";
313 
314  PathDiagnosticLocation FSLoc =
315  PathDiagnosticLocation::createBegin(FS, BR.getSourceManager(), AC);
316  BR.EmitBasicReport(AC->getDecl(), filter.checkName_FloatLoopCounter,
317  bugType, "Security", os.str(),
318  FSLoc, ranges);
319 }
320 
321 //===----------------------------------------------------------------------===//
322 // Check: Any use of bcmp.
323 // CWE-477: Use of Obsolete Functions
324 // bcmp was deprecated in POSIX.1-2008
325 //===----------------------------------------------------------------------===//
326 
327 void WalkAST::checkCall_bcmp(const CallExpr *CE, const FunctionDecl *FD) {
328  if (!filter.check_bcmp)
329  return;
330 
331  const FunctionProtoType *FPT = FD->getType()->getAs<FunctionProtoType>();
332  if (!FPT)
333  return;
334 
335  // Verify that the function takes three arguments.
336  if (FPT->getNumParams() != 3)
337  return;
338 
339  for (int i = 0; i < 2; i++) {
340  // Verify the first and second argument type is void*.
341  const PointerType *PT = FPT->getParamType(i)->getAs<PointerType>();
342  if (!PT)
343  return;
344 
345  if (PT->getPointeeType().getUnqualifiedType() != BR.getContext().VoidTy)
346  return;
347  }
348 
349  // Verify the third argument type is integer.
351  return;
352 
353  // Issue a warning.
354  PathDiagnosticLocation CELoc =
355  PathDiagnosticLocation::createBegin(CE, BR.getSourceManager(), AC);
356  BR.EmitBasicReport(AC->getDecl(), filter.checkName_bcmp,
357  "Use of deprecated function in call to 'bcmp()'",
358  "Security",
359  "The bcmp() function is obsoleted by memcmp().",
360  CELoc, CE->getCallee()->getSourceRange());
361 }
362 
363 //===----------------------------------------------------------------------===//
364 // Check: Any use of bcopy.
365 // CWE-477: Use of Obsolete Functions
366 // bcopy was deprecated in POSIX.1-2008
367 //===----------------------------------------------------------------------===//
368 
369 void WalkAST::checkCall_bcopy(const CallExpr *CE, const FunctionDecl *FD) {
370  if (!filter.check_bcopy)
371  return;
372 
373  const FunctionProtoType *FPT = FD->getType()->getAs<FunctionProtoType>();
374  if (!FPT)
375  return;
376 
377  // Verify that the function takes three arguments.
378  if (FPT->getNumParams() != 3)
379  return;
380 
381  for (int i = 0; i < 2; i++) {
382  // Verify the first and second argument type is void*.
383  const PointerType *PT = FPT->getParamType(i)->getAs<PointerType>();
384  if (!PT)
385  return;
386 
387  if (PT->getPointeeType().getUnqualifiedType() != BR.getContext().VoidTy)
388  return;
389  }
390 
391  // Verify the third argument type is integer.
393  return;
394 
395  // Issue a warning.
396  PathDiagnosticLocation CELoc =
397  PathDiagnosticLocation::createBegin(CE, BR.getSourceManager(), AC);
398  BR.EmitBasicReport(AC->getDecl(), filter.checkName_bcopy,
399  "Use of deprecated function in call to 'bcopy()'",
400  "Security",
401  "The bcopy() function is obsoleted by memcpy() "
402  "or memmove().",
403  CELoc, CE->getCallee()->getSourceRange());
404 }
405 
406 //===----------------------------------------------------------------------===//
407 // Check: Any use of bzero.
408 // CWE-477: Use of Obsolete Functions
409 // bzero was deprecated in POSIX.1-2008
410 //===----------------------------------------------------------------------===//
411 
412 void WalkAST::checkCall_bzero(const CallExpr *CE, const FunctionDecl *FD) {
413  if (!filter.check_bzero)
414  return;
415 
416  const FunctionProtoType *FPT = FD->getType()->getAs<FunctionProtoType>();
417  if (!FPT)
418  return;
419 
420  // Verify that the function takes two arguments.
421  if (FPT->getNumParams() != 2)
422  return;
423 
424  // Verify the first argument type is void*.
425  const PointerType *PT = FPT->getParamType(0)->getAs<PointerType>();
426  if (!PT)
427  return;
428 
429  if (PT->getPointeeType().getUnqualifiedType() != BR.getContext().VoidTy)
430  return;
431 
432  // Verify the second argument type is integer.
434  return;
435 
436  // Issue a warning.
437  PathDiagnosticLocation CELoc =
438  PathDiagnosticLocation::createBegin(CE, BR.getSourceManager(), AC);
439  BR.EmitBasicReport(AC->getDecl(), filter.checkName_bzero,
440  "Use of deprecated function in call to 'bzero()'",
441  "Security",
442  "The bzero() function is obsoleted by memset().",
443  CELoc, CE->getCallee()->getSourceRange());
444 }
445 
446 
447 //===----------------------------------------------------------------------===//
448 // Check: Any use of 'gets' is insecure.
449 // Originally: <rdar://problem/6335715>
450 // Implements (part of): 300-BSI (buildsecurityin.us-cert.gov)
451 // CWE-242: Use of Inherently Dangerous Function
452 //===----------------------------------------------------------------------===//
453 
454 void WalkAST::checkCall_gets(const CallExpr *CE, const FunctionDecl *FD) {
455  if (!filter.check_gets)
456  return;
457 
458  const FunctionProtoType *FPT = FD->getType()->getAs<FunctionProtoType>();
459  if (!FPT)
460  return;
461 
462  // Verify that the function takes a single argument.
463  if (FPT->getNumParams() != 1)
464  return;
465 
466  // Is the argument a 'char*'?
467  const PointerType *PT = FPT->getParamType(0)->getAs<PointerType>();
468  if (!PT)
469  return;
470 
471  if (PT->getPointeeType().getUnqualifiedType() != BR.getContext().CharTy)
472  return;
473 
474  // Issue a warning.
475  PathDiagnosticLocation CELoc =
476  PathDiagnosticLocation::createBegin(CE, BR.getSourceManager(), AC);
477  BR.EmitBasicReport(AC->getDecl(), filter.checkName_gets,
478  "Potential buffer overflow in call to 'gets'",
479  "Security",
480  "Call to function 'gets' is extremely insecure as it can "
481  "always result in a buffer overflow",
482  CELoc, CE->getCallee()->getSourceRange());
483 }
484 
485 //===----------------------------------------------------------------------===//
486 // Check: Any use of 'getpwd' is insecure.
487 // CWE-477: Use of Obsolete Functions
488 //===----------------------------------------------------------------------===//
489 
490 void WalkAST::checkCall_getpw(const CallExpr *CE, const FunctionDecl *FD) {
491  if (!filter.check_getpw)
492  return;
493 
494  const FunctionProtoType *FPT = FD->getType()->getAs<FunctionProtoType>();
495  if (!FPT)
496  return;
497 
498  // Verify that the function takes two arguments.
499  if (FPT->getNumParams() != 2)
500  return;
501 
502  // Verify the first argument type is integer.
504  return;
505 
506  // Verify the second argument type is char*.
507  const PointerType *PT = FPT->getParamType(1)->getAs<PointerType>();
508  if (!PT)
509  return;
510 
511  if (PT->getPointeeType().getUnqualifiedType() != BR.getContext().CharTy)
512  return;
513 
514  // Issue a warning.
515  PathDiagnosticLocation CELoc =
516  PathDiagnosticLocation::createBegin(CE, BR.getSourceManager(), AC);
517  BR.EmitBasicReport(AC->getDecl(), filter.checkName_getpw,
518  "Potential buffer overflow in call to 'getpw'",
519  "Security",
520  "The getpw() function is dangerous as it may overflow the "
521  "provided buffer. It is obsoleted by getpwuid().",
522  CELoc, CE->getCallee()->getSourceRange());
523 }
524 
525 //===----------------------------------------------------------------------===//
526 // Check: Any use of 'mktemp' is insecure. It is obsoleted by mkstemp().
527 // CWE-377: Insecure Temporary File
528 //===----------------------------------------------------------------------===//
529 
530 void WalkAST::checkCall_mktemp(const CallExpr *CE, const FunctionDecl *FD) {
531  if (!filter.check_mktemp) {
532  // Fall back to the security check of looking for enough 'X's in the
533  // format string, since that is a less severe warning.
534  checkCall_mkstemp(CE, FD);
535  return;
536  }
537 
538  const FunctionProtoType *FPT = FD->getType()->getAs<FunctionProtoType>();
539  if(!FPT)
540  return;
541 
542  // Verify that the function takes a single argument.
543  if (FPT->getNumParams() != 1)
544  return;
545 
546  // Verify that the argument is Pointer Type.
547  const PointerType *PT = FPT->getParamType(0)->getAs<PointerType>();
548  if (!PT)
549  return;
550 
551  // Verify that the argument is a 'char*'.
552  if (PT->getPointeeType().getUnqualifiedType() != BR.getContext().CharTy)
553  return;
554 
555  // Issue a warning.
556  PathDiagnosticLocation CELoc =
557  PathDiagnosticLocation::createBegin(CE, BR.getSourceManager(), AC);
558  BR.EmitBasicReport(AC->getDecl(), filter.checkName_mktemp,
559  "Potential insecure temporary file in call 'mktemp'",
560  "Security",
561  "Call to function 'mktemp' is insecure as it always "
562  "creates or uses insecure temporary file. Use 'mkstemp' "
563  "instead",
564  CELoc, CE->getCallee()->getSourceRange());
565 }
566 
567 //===----------------------------------------------------------------------===//
568 // Check: Use of 'mkstemp', 'mktemp', 'mkdtemp' should contain at least 6 X's.
569 //===----------------------------------------------------------------------===//
570 
571 void WalkAST::checkCall_mkstemp(const CallExpr *CE, const FunctionDecl *FD) {
572  if (!filter.check_mkstemp)
573  return;
574 
575  StringRef Name = FD->getIdentifier()->getName();
576  std::pair<signed, signed> ArgSuffix =
577  llvm::StringSwitch<std::pair<signed, signed> >(Name)
578  .Case("mktemp", std::make_pair(0,-1))
579  .Case("mkstemp", std::make_pair(0,-1))
580  .Case("mkdtemp", std::make_pair(0,-1))
581  .Case("mkstemps", std::make_pair(0,1))
582  .Default(std::make_pair(-1, -1));
583 
584  assert(ArgSuffix.first >= 0 && "Unsupported function");
585 
586  // Check if the number of arguments is consistent with out expectations.
587  unsigned numArgs = CE->getNumArgs();
588  if ((signed) numArgs <= ArgSuffix.first)
589  return;
590 
591  const StringLiteral *strArg =
592  dyn_cast<StringLiteral>(CE->getArg((unsigned)ArgSuffix.first)
593  ->IgnoreParenImpCasts());
594 
595  // Currently we only handle string literals. It is possible to do better,
596  // either by looking at references to const variables, or by doing real
597  // flow analysis.
598  if (!strArg || strArg->getCharByteWidth() != 1)
599  return;
600 
601  // Count the number of X's, taking into account a possible cutoff suffix.
602  StringRef str = strArg->getString();
603  unsigned numX = 0;
604  unsigned n = str.size();
605 
606  // Take into account the suffix.
607  unsigned suffix = 0;
608  if (ArgSuffix.second >= 0) {
609  const Expr *suffixEx = CE->getArg((unsigned)ArgSuffix.second);
610  Expr::EvalResult EVResult;
611  if (!suffixEx->EvaluateAsInt(EVResult, BR.getContext()))
612  return;
613  llvm::APSInt Result = EVResult.Val.getInt();
614  // FIXME: Issue a warning.
615  if (Result.isNegative())
616  return;
617  suffix = (unsigned) Result.getZExtValue();
618  n = (n > suffix) ? n - suffix : 0;
619  }
620 
621  for (unsigned i = 0; i < n; ++i)
622  if (str[i] == 'X') ++numX;
623 
624  if (numX >= 6)
625  return;
626 
627  // Issue a warning.
628  PathDiagnosticLocation CELoc =
629  PathDiagnosticLocation::createBegin(CE, BR.getSourceManager(), AC);
630  SmallString<512> buf;
631  llvm::raw_svector_ostream out(buf);
632  out << "Call to '" << Name << "' should have at least 6 'X's in the"
633  " format string to be secure (" << numX << " 'X'";
634  if (numX != 1)
635  out << 's';
636  out << " seen";
637  if (suffix) {
638  out << ", " << suffix << " character";
639  if (suffix > 1)
640  out << 's';
641  out << " used as a suffix";
642  }
643  out << ')';
644  BR.EmitBasicReport(AC->getDecl(), filter.checkName_mkstemp,
645  "Insecure temporary file creation", "Security",
646  out.str(), CELoc, strArg->getSourceRange());
647 }
648 
649 //===----------------------------------------------------------------------===//
650 // Check: Any use of 'strcpy' is insecure.
651 //
652 // CWE-119: Improper Restriction of Operations within
653 // the Bounds of a Memory Buffer
654 //===----------------------------------------------------------------------===//
655 
656 void WalkAST::checkCall_strcpy(const CallExpr *CE, const FunctionDecl *FD) {
657  if (!filter.check_strcpy)
658  return;
659 
660  if (!checkCall_strCommon(CE, FD))
661  return;
662 
663  const auto *Target = CE->getArg(0)->IgnoreImpCasts(),
664  *Source = CE->getArg(1)->IgnoreImpCasts();
665 
666  if (const auto *Array = dyn_cast<ConstantArrayType>(Target->getType())) {
667  uint64_t ArraySize = BR.getContext().getTypeSize(Array) / 8;
668  if (const auto *String = dyn_cast<StringLiteral>(Source)) {
669  if (ArraySize >= String->getLength() + 1)
670  return;
671  }
672  }
673 
674  // Issue a warning.
675  PathDiagnosticLocation CELoc =
676  PathDiagnosticLocation::createBegin(CE, BR.getSourceManager(), AC);
677  BR.EmitBasicReport(AC->getDecl(), filter.checkName_strcpy,
678  "Potential insecure memory buffer bounds restriction in "
679  "call 'strcpy'",
680  "Security",
681  "Call to function 'strcpy' is insecure as it does not "
682  "provide bounding of the memory buffer. Replace "
683  "unbounded copy functions with analogous functions that "
684  "support length arguments such as 'strlcpy'. CWE-119.",
685  CELoc, CE->getCallee()->getSourceRange());
686 }
687 
688 //===----------------------------------------------------------------------===//
689 // Check: Any use of 'strcat' is insecure.
690 //
691 // CWE-119: Improper Restriction of Operations within
692 // the Bounds of a Memory Buffer
693 //===----------------------------------------------------------------------===//
694 
695 void WalkAST::checkCall_strcat(const CallExpr *CE, const FunctionDecl *FD) {
696  if (!filter.check_strcpy)
697  return;
698 
699  if (!checkCall_strCommon(CE, FD))
700  return;
701 
702  // Issue a warning.
703  PathDiagnosticLocation CELoc =
704  PathDiagnosticLocation::createBegin(CE, BR.getSourceManager(), AC);
705  BR.EmitBasicReport(AC->getDecl(), filter.checkName_strcpy,
706  "Potential insecure memory buffer bounds restriction in "
707  "call 'strcat'",
708  "Security",
709  "Call to function 'strcat' is insecure as it does not "
710  "provide bounding of the memory buffer. Replace "
711  "unbounded copy functions with analogous functions that "
712  "support length arguments such as 'strlcat'. CWE-119.",
713  CELoc, CE->getCallee()->getSourceRange());
714 }
715 
716 //===----------------------------------------------------------------------===//
717 // Check: Any use of 'sprintf', 'vsprintf', 'scanf', 'wscanf', 'fscanf',
718 // 'fwscanf', 'vscanf', 'vwscanf', 'vfscanf', 'vfwscanf', 'sscanf',
719 // 'swscanf', 'vsscanf', 'vswscanf', 'swprintf', 'snprintf', 'vswprintf',
720 // 'vsnprintf', 'memcpy', 'memmove', 'strncpy', 'strncat', 'memset'
721 // is deprecated since C11.
722 //
723 // Use of 'sprintf', 'vsprintf', 'scanf', 'wscanf','fscanf',
724 // 'fwscanf', 'vscanf', 'vwscanf', 'vfscanf', 'vfwscanf', 'sscanf',
725 // 'swscanf', 'vsscanf', 'vswscanf' without buffer limitations
726 // is insecure.
727 //
728 // CWE-119: Improper Restriction of Operations within
729 // the Bounds of a Memory Buffer
730 //===----------------------------------------------------------------------===//
731 
732 void WalkAST::checkDeprecatedOrUnsafeBufferHandling(const CallExpr *CE,
733  const FunctionDecl *FD) {
734  if (!filter.check_DeprecatedOrUnsafeBufferHandling)
735  return;
736 
737  if (!BR.getContext().getLangOpts().C11)
738  return;
739 
740  // Issue a warning. ArgIndex == -1: Deprecated but not unsafe (has size
741  // restrictions).
742  enum { DEPR_ONLY = -1, UNKNOWN_CALL = -2 };
743 
744  StringRef Name = FD->getIdentifier()->getName();
745  if (Name.startswith("__builtin_"))
746  Name = Name.substr(10);
747 
748  int ArgIndex =
749  llvm::StringSwitch<int>(Name)
750  .Cases("scanf", "wscanf", "vscanf", "vwscanf", 0)
751  .Cases("sprintf", "vsprintf", "fscanf", "fwscanf", "vfscanf",
752  "vfwscanf", "sscanf", "swscanf", "vsscanf", "vswscanf", 1)
753  .Cases("swprintf", "snprintf", "vswprintf", "vsnprintf", "memcpy",
754  "memmove", "memset", "strncpy", "strncat", DEPR_ONLY)
755  .Default(UNKNOWN_CALL);
756 
757  assert(ArgIndex != UNKNOWN_CALL && "Unsupported function");
758  bool BoundsProvided = ArgIndex == DEPR_ONLY;
759 
760  if (!BoundsProvided) {
761  // Currently we only handle (not wide) string literals. It is possible to do
762  // better, either by looking at references to const variables, or by doing
763  // real flow analysis.
764  auto FormatString =
765  dyn_cast<StringLiteral>(CE->getArg(ArgIndex)->IgnoreParenImpCasts());
766  if (FormatString &&
767  FormatString->getString().find("%s") == StringRef::npos &&
768  FormatString->getString().find("%[") == StringRef::npos)
769  BoundsProvided = true;
770  }
771 
772  SmallString<128> Buf1;
773  SmallString<512> Buf2;
774  llvm::raw_svector_ostream Out1(Buf1);
775  llvm::raw_svector_ostream Out2(Buf2);
776 
777  Out1 << "Potential insecure memory buffer bounds restriction in call '"
778  << Name << "'";
779  Out2 << "Call to function '" << Name
780  << "' is insecure as it does not provide ";
781 
782  if (!BoundsProvided) {
783  Out2 << "bounding of the memory buffer or ";
784  }
785 
786  Out2 << "security checks introduced "
787  "in the C11 standard. Replace with analogous functions that "
788  "support length arguments or provides boundary checks such as '"
789  << Name << "_s' in case of C11";
790 
791  PathDiagnosticLocation CELoc =
792  PathDiagnosticLocation::createBegin(CE, BR.getSourceManager(), AC);
793  BR.EmitBasicReport(AC->getDecl(),
794  filter.checkName_DeprecatedOrUnsafeBufferHandling,
795  Out1.str(), "Security", Out2.str(), CELoc,
796  CE->getCallee()->getSourceRange());
797 }
798 
799 //===----------------------------------------------------------------------===//
800 // Common check for str* functions with no bounds parameters.
801 //===----------------------------------------------------------------------===//
802 
803 bool WalkAST::checkCall_strCommon(const CallExpr *CE, const FunctionDecl *FD) {
804  const FunctionProtoType *FPT = FD->getType()->getAs<FunctionProtoType>();
805  if (!FPT)
806  return false;
807 
808  // Verify the function takes two arguments, three in the _chk version.
809  int numArgs = FPT->getNumParams();
810  if (numArgs != 2 && numArgs != 3)
811  return false;
812 
813  // Verify the type for both arguments.
814  for (int i = 0; i < 2; i++) {
815  // Verify that the arguments are pointers.
816  const PointerType *PT = FPT->getParamType(i)->getAs<PointerType>();
817  if (!PT)
818  return false;
819 
820  // Verify that the argument is a 'char*'.
821  if (PT->getPointeeType().getUnqualifiedType() != BR.getContext().CharTy)
822  return false;
823  }
824 
825  return true;
826 }
827 
828 //===----------------------------------------------------------------------===//
829 // Check: Linear congruent random number generators should not be used
830 // Originally: <rdar://problem/63371000>
831 // CWE-338: Use of cryptographically weak prng
832 //===----------------------------------------------------------------------===//
833 
834 void WalkAST::checkCall_rand(const CallExpr *CE, const FunctionDecl *FD) {
835  if (!filter.check_rand || !CheckRand)
836  return;
837 
838  const FunctionProtoType *FTP = FD->getType()->getAs<FunctionProtoType>();
839  if (!FTP)
840  return;
841 
842  if (FTP->getNumParams() == 1) {
843  // Is the argument an 'unsigned short *'?
844  // (Actually any integer type is allowed.)
845  const PointerType *PT = FTP->getParamType(0)->getAs<PointerType>();
846  if (!PT)
847  return;
848 
850  return;
851  } else if (FTP->getNumParams() != 0)
852  return;
853 
854  // Issue a warning.
855  SmallString<256> buf1;
856  llvm::raw_svector_ostream os1(buf1);
857  os1 << '\'' << *FD << "' is a poor random number generator";
858 
859  SmallString<256> buf2;
860  llvm::raw_svector_ostream os2(buf2);
861  os2 << "Function '" << *FD
862  << "' is obsolete because it implements a poor random number generator."
863  << " Use 'arc4random' instead";
864 
865  PathDiagnosticLocation CELoc =
866  PathDiagnosticLocation::createBegin(CE, BR.getSourceManager(), AC);
867  BR.EmitBasicReport(AC->getDecl(), filter.checkName_rand, os1.str(),
868  "Security", os2.str(), CELoc,
869  CE->getCallee()->getSourceRange());
870 }
871 
872 //===----------------------------------------------------------------------===//
873 // Check: 'random' should not be used
874 // Originally: <rdar://problem/63371000>
875 //===----------------------------------------------------------------------===//
876 
877 void WalkAST::checkCall_random(const CallExpr *CE, const FunctionDecl *FD) {
878  if (!CheckRand || !filter.check_rand)
879  return;
880 
881  const FunctionProtoType *FTP = FD->getType()->getAs<FunctionProtoType>();
882  if (!FTP)
883  return;
884 
885  // Verify that the function takes no argument.
886  if (FTP->getNumParams() != 0)
887  return;
888 
889  // Issue a warning.
890  PathDiagnosticLocation CELoc =
891  PathDiagnosticLocation::createBegin(CE, BR.getSourceManager(), AC);
892  BR.EmitBasicReport(AC->getDecl(), filter.checkName_rand,
893  "'random' is not a secure random number generator",
894  "Security",
895  "The 'random' function produces a sequence of values that "
896  "an adversary may be able to predict. Use 'arc4random' "
897  "instead", CELoc, CE->getCallee()->getSourceRange());
898 }
899 
900 //===----------------------------------------------------------------------===//
901 // Check: 'vfork' should not be used.
902 // POS33-C: Do not use vfork().
903 //===----------------------------------------------------------------------===//
904 
905 void WalkAST::checkCall_vfork(const CallExpr *CE, const FunctionDecl *FD) {
906  if (!filter.check_vfork)
907  return;
908 
909  // All calls to vfork() are insecure, issue a warning.
910  PathDiagnosticLocation CELoc =
911  PathDiagnosticLocation::createBegin(CE, BR.getSourceManager(), AC);
912  BR.EmitBasicReport(AC->getDecl(), filter.checkName_vfork,
913  "Potential insecure implementation-specific behavior in "
914  "call 'vfork'",
915  "Security",
916  "Call to function 'vfork' is insecure as it can lead to "
917  "denial of service situations in the parent process. "
918  "Replace calls to vfork with calls to the safer "
919  "'posix_spawn' function",
920  CELoc, CE->getCallee()->getSourceRange());
921 }
922 
923 //===----------------------------------------------------------------------===//
924 // Check: Should check whether privileges are dropped successfully.
925 // Originally: <rdar://problem/6337132>
926 //===----------------------------------------------------------------------===//
927 
928 void WalkAST::checkUncheckedReturnValue(CallExpr *CE) {
929  if (!filter.check_UncheckedReturn)
930  return;
931 
932  const FunctionDecl *FD = CE->getDirectCallee();
933  if (!FD)
934  return;
935 
936  if (II_setid[0] == nullptr) {
937  static const char * const identifiers[num_setids] = {
938  "setuid", "setgid", "seteuid", "setegid",
939  "setreuid", "setregid"
940  };
941 
942  for (size_t i = 0; i < num_setids; i++)
943  II_setid[i] = &BR.getContext().Idents.get(identifiers[i]);
944  }
945 
946  const IdentifierInfo *id = FD->getIdentifier();
947  size_t identifierid;
948 
949  for (identifierid = 0; identifierid < num_setids; identifierid++)
950  if (id == II_setid[identifierid])
951  break;
952 
953  if (identifierid >= num_setids)
954  return;
955 
956  const FunctionProtoType *FTP = FD->getType()->getAs<FunctionProtoType>();
957  if (!FTP)
958  return;
959 
960  // Verify that the function takes one or two arguments (depending on
961  // the function).
962  if (FTP->getNumParams() != (identifierid < 4 ? 1 : 2))
963  return;
964 
965  // The arguments must be integers.
966  for (unsigned i = 0; i < FTP->getNumParams(); i++)
968  return;
969 
970  // Issue a warning.
971  SmallString<256> buf1;
972  llvm::raw_svector_ostream os1(buf1);
973  os1 << "Return value is not checked in call to '" << *FD << '\'';
974 
975  SmallString<256> buf2;
976  llvm::raw_svector_ostream os2(buf2);
977  os2 << "The return value from the call to '" << *FD
978  << "' is not checked. If an error occurs in '" << *FD
979  << "', the following code may execute with unexpected privileges";
980 
981  PathDiagnosticLocation CELoc =
982  PathDiagnosticLocation::createBegin(CE, BR.getSourceManager(), AC);
983  BR.EmitBasicReport(AC->getDecl(), filter.checkName_UncheckedReturn, os1.str(),
984  "Security", os2.str(), CELoc,
985  CE->getCallee()->getSourceRange());
986 }
987 
988 //===----------------------------------------------------------------------===//
989 // SecuritySyntaxChecker
990 //===----------------------------------------------------------------------===//
991 
992 namespace {
993 class SecuritySyntaxChecker : public Checker<check::ASTCodeBody> {
994 public:
995  ChecksFilter filter;
996 
997  void checkASTCodeBody(const Decl *D, AnalysisManager& mgr,
998  BugReporter &BR) const {
999  WalkAST walker(BR, mgr.getAnalysisDeclContext(D), filter);
1000  walker.Visit(D->getBody());
1001  }
1002 };
1003 }
1004 
1005 void ento::registerSecuritySyntaxChecker(CheckerManager &mgr) {
1006  mgr.registerChecker<SecuritySyntaxChecker>();
1007 }
1008 
1009 bool ento::shouldRegisterSecuritySyntaxChecker(const LangOptions &LO) {
1010  return true;
1011 }
1012 
1013 #define REGISTER_CHECKER(name) \
1014  void ento::register##name(CheckerManager &mgr) { \
1015  SecuritySyntaxChecker *checker = mgr.getChecker<SecuritySyntaxChecker>(); \
1016  checker->filter.check_##name = true; \
1017  checker->filter.checkName_##name = mgr.getCurrentCheckName(); \
1018  } \
1019  \
1020  bool ento::shouldRegister##name(const LangOptions &LO) { \
1021  return true; \
1022  }
1023 
1024 REGISTER_CHECKER(bcmp)
1025 REGISTER_CHECKER(bcopy)
1026 REGISTER_CHECKER(bzero)
1027 REGISTER_CHECKER(gets)
1028 REGISTER_CHECKER(getpw)
1029 REGISTER_CHECKER(mkstemp)
1030 REGISTER_CHECKER(mktemp)
1031 REGISTER_CHECKER(strcpy)
1032 REGISTER_CHECKER(rand)
1033 REGISTER_CHECKER(vfork)
1034 REGISTER_CHECKER(FloatLoopCounter)
1035 REGISTER_CHECKER(UncheckedReturn)
1036 REGISTER_CHECKER(DeprecatedOrUnsafeBufferHandling)
Expr * getInc()
Definition: Stmt.h:2417
Represents a function declaration or definition.
Definition: Decl.h:1748
PointerType - C99 6.7.5.1 - Pointer Declarators.
Definition: Type.h:2569
QualType getPointeeType() const
Definition: Type.h:2582
Expr * getArg(unsigned Arg)
getArg - Return the specified argument.
Definition: Expr.h:2673
virtual Stmt * getBody() const
getBody - If this Decl represents a declaration for a body of code, such as a function or method defi...
Definition: DeclBase.h:986
Stmt - This represents one statement.
Definition: Stmt.h:66
unsigned getNumArgs() const
getNumArgs - Return the number of actual arguments to this call.
Definition: Expr.h:2660
const llvm::Triple & getTriple() const
Returns the target triple of the primary target.
Definition: TargetInfo.h:985
bool isRealFloatingType() const
Floating point categories.
Definition: Type.cpp:1968
Decl - This represents one declaration (or definition), e.g.
Definition: DeclBase.h:88
const TargetInfo & getTargetInfo() const
Definition: ASTContext.h:693
Represents a variable declaration or definition.
Definition: Decl.h:812
unsigned getNumParams() const
Definition: Type.h:3921
const internal::VariadicDynCastAllOfMatcher< Stmt, Expr > expr
Matches expressions.
const T * getAs() const
Member-template getAs<specific type>&#39;.
Definition: Type.h:6851
long i
Definition: xmmintrin.h:1456
IdentifierInfo * getIdentifier() const
Get the identifier that names this declaration, if there is one.
Definition: Decl.h:269
One of these records is kept for each identifier that is lexed.
Holds long-lived AST nodes (such as types and decls) that can be referred to throughout the semantic ...
Definition: ASTContext.h:154
AnalysisDeclContext contains the context data for the function or method under analysis.
Keeps track of the various options that can be enabled, which controls the dialect of C or C++ that i...
Definition: LangOptions.h:49
unsigned getCharByteWidth() const
Definition: Expr.h:1794
static bool isRelationalOp(Opcode Opc)
Definition: Expr.h:3489
ForStmt - This represents a &#39;for (init;cond;inc)&#39; stmt.
Definition: Stmt.h:2384
static bool isEqualityOp(Opcode Opc)
Definition: Expr.h:3492
APValue Val
Val - This is the value the expression can be folded to.
Definition: Expr.h:582
child_range children()
Definition: Stmt.cpp:212
A builtin binary operation expression such as "x + y" or "x <= y".
Definition: Expr.h:3405
Expr * IgnoreParenCasts() LLVM_READONLY
Skip past any parentheses and casts which might surround this expression until reaching a fixed point...
Definition: Expr.cpp:2947
Expr * getCond()
Definition: Stmt.h:2416
child_range children()
Definition: Stmt.h:1425
Expr * IgnoreImpCasts() LLVM_READONLY
Skip past any implicit casts which might surround this expression until reaching a fixed point...
Definition: Expr.cpp:2926
bool isIntegralOrUnscopedEnumerationType() const
Determine whether this type is an integral or unscoped enumeration type.
Definition: Type.cpp:1803
StringRef getString() const
Definition: Expr.h:1764
CompoundStmt - This represents a group of statements like { stmt stmt }.
Definition: Stmt.h:1310
Represents a prototype with parameter type info, e.g.
Definition: Type.h:3719
This represents one expression.
Definition: Expr.h:108
Expr * getCallee()
Definition: Expr.h:2634
FunctionDecl * getDirectCallee()
If the callee is a FunctionDecl, return it. Otherwise return null.
Definition: Expr.h:2652
QualType getType() const
Definition: Expr.h:137
UnaryOperator - This represents the unary-expression&#39;s (except sizeof and alignof), the postinc/postdec operators from postfix-expression, and various extensions.
Definition: Expr.h:2016
ValueDecl * getDecl()
Definition: Expr.h:1217
static PathDiagnosticLocation createBegin(const Decl *D, const SourceManager &SM)
Create a location for the beginning of the declaration.
static const DeclRefExpr * getIncrementedVar(const Expr *expr, const VarDecl *x, const VarDecl *y)
StmtVisitor - This class implements a simple visitor for Stmt subclasses.
Definition: StmtVisitor.h:182
#define REGISTER_CHECKER(name)
Expr * getLHS() const
Definition: Expr.h:3445
StringRef getName() const
Return the actual identifier string.
Dataflow Directional Tag Classes.
EvalResult is a struct with detailed info about an evaluated expression.
Definition: Expr.h:580
Expr * IgnoreParenImpCasts() LLVM_READONLY
Skip past any parentheses and implicit casts which might surround this expression until reaching a fi...
Definition: Expr.cpp:2942
Expr * IgnoreParenLValueCasts() LLVM_READONLY
Skip past any parentheses and lvalue casts which might surround this expression until reaching a fixe...
Definition: Expr.cpp:2959
QualType getParamType(unsigned i) const
Definition: Type.h:3923
bool EvaluateAsInt(EvalResult &Result, const ASTContext &Ctx, SideEffectsKind AllowSideEffects=SE_NoSideEffects, bool InConstantContext=false) const
EvaluateAsInt - Return true if this is a constant which we can fold and convert to an integer...
QualType getUnqualifiedType() const
Retrieve the unqualified variant of the given type, removing as little sugar as possible.
Definition: Type.h:6222
SourceRange getSourceRange() const LLVM_READONLY
SourceLocation tokens are not useful in isolation - they are low level value objects created/interpre...
Definition: Stmt.cpp:251
StringLiteral - This represents a string literal expression, e.g.
Definition: Expr.h:1681
Defines the clang::TargetInfo interface.
CallExpr - Represents a function call (C99 6.5.2.2, C++ [expr.call]).
Definition: Expr.h:2516
A reference to a declared variable, function, enum, etc.
Definition: Expr.h:1141
Expr * getRHS() const
Definition: Expr.h:3447
static bool isArc4RandomAvailable(const ASTContext &Ctx)
QualType getType() const
Definition: Decl.h:647
This represents a decl that may have a name.
Definition: Decl.h:248
APSInt & getInt()
Definition: APValue.h:336