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