clang  6.0.0svn
CheckSecuritySyntaxOnly.cpp
Go to the documentation of this file.
1 //==- CheckSecuritySyntaxOnly.cpp - Basic security checks --------*- C++ -*-==//
2 //
3 // The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 //
10 // This file defines a set of flow-insensitive security checks.
11 //
12 //===----------------------------------------------------------------------===//
13 
14 #include "ClangSACheckers.h"
15 #include "clang/AST/StmtVisitor.h"
17 #include "clang/Basic/TargetInfo.h"
21 #include "llvm/ADT/SmallString.h"
22 #include "llvm/ADT/StringSwitch.h"
23 #include "llvm/Support/raw_ostream.h"
24 
25 using namespace clang;
26 using namespace ento;
27 
28 static bool isArc4RandomAvailable(const ASTContext &Ctx) {
29  const llvm::Triple &T = Ctx.getTargetInfo().getTriple();
30  return T.getVendor() == llvm::Triple::Apple ||
31  T.getOS() == llvm::Triple::CloudABI ||
32  T.getOS() == llvm::Triple::FreeBSD ||
33  T.getOS() == llvm::Triple::NetBSD ||
34  T.getOS() == llvm::Triple::OpenBSD ||
35  T.getOS() == llvm::Triple::DragonFly;
36 }
37 
38 namespace {
39 struct ChecksFilter {
40  DefaultBool check_gets;
41  DefaultBool check_getpw;
42  DefaultBool check_mktemp;
43  DefaultBool check_mkstemp;
44  DefaultBool check_strcpy;
45  DefaultBool check_rand;
46  DefaultBool check_vfork;
47  DefaultBool check_FloatLoopCounter;
48  DefaultBool check_UncheckedReturn;
49 
50  CheckName checkName_gets;
51  CheckName checkName_getpw;
52  CheckName checkName_mktemp;
53  CheckName checkName_mkstemp;
54  CheckName checkName_strcpy;
55  CheckName checkName_rand;
56  CheckName checkName_vfork;
57  CheckName checkName_FloatLoopCounter;
58  CheckName checkName_UncheckedReturn;
59 };
60 
61 class WalkAST : public StmtVisitor<WalkAST> {
62  BugReporter &BR;
64  enum { num_setids = 6 };
65  IdentifierInfo *II_setid[num_setids];
66 
67  const bool CheckRand;
68  const ChecksFilter &filter;
69 
70 public:
71  WalkAST(BugReporter &br, AnalysisDeclContext* ac,
72  const ChecksFilter &f)
73  : BR(br), AC(ac), II_setid(),
74  CheckRand(isArc4RandomAvailable(BR.getContext())),
75  filter(f) {}
76 
77  // Statement visitor methods.
78  void VisitCallExpr(CallExpr *CE);
79  void VisitForStmt(ForStmt *S);
80  void VisitCompoundStmt (CompoundStmt *S);
81  void VisitStmt(Stmt *S) { VisitChildren(S); }
82 
83  void VisitChildren(Stmt *S);
84 
85  // Helpers.
86  bool checkCall_strCommon(const CallExpr *CE, const FunctionDecl *FD);
87 
88  typedef void (WalkAST::*FnCheck)(const CallExpr *, const FunctionDecl *);
89 
90  // Checker-specific methods.
91  void checkLoopConditionForFloat(const ForStmt *FS);
92  void checkCall_gets(const CallExpr *CE, const FunctionDecl *FD);
93  void checkCall_getpw(const CallExpr *CE, const FunctionDecl *FD);
94  void checkCall_mktemp(const CallExpr *CE, const FunctionDecl *FD);
95  void checkCall_mkstemp(const CallExpr *CE, const FunctionDecl *FD);
96  void checkCall_strcpy(const CallExpr *CE, const FunctionDecl *FD);
97  void checkCall_strcat(const CallExpr *CE, const FunctionDecl *FD);
98  void checkCall_rand(const CallExpr *CE, const FunctionDecl *FD);
99  void checkCall_random(const CallExpr *CE, const FunctionDecl *FD);
100  void checkCall_vfork(const CallExpr *CE, const FunctionDecl *FD);
101  void checkUncheckedReturnValue(CallExpr *CE);
102 };
103 } // end anonymous namespace
104 
105 //===----------------------------------------------------------------------===//
106 // AST walking.
107 //===----------------------------------------------------------------------===//
108 
109 void WalkAST::VisitChildren(Stmt *S) {
110  for (Stmt *Child : S->children())
111  if (Child)
112  Visit(Child);
113 }
114 
115 void WalkAST::VisitCallExpr(CallExpr *CE) {
116  // Get the callee.
117  const FunctionDecl *FD = CE->getDirectCallee();
118 
119  if (!FD)
120  return;
121 
122  // Get the name of the callee. If it's a builtin, strip off the prefix.
123  IdentifierInfo *II = FD->getIdentifier();
124  if (!II) // if no identifier, not a simple C function
125  return;
126  StringRef Name = II->getName();
127  if (Name.startswith("__builtin_"))
128  Name = Name.substr(10);
129 
130  // Set the evaluation function by switching on the callee name.
131  FnCheck evalFunction = llvm::StringSwitch<FnCheck>(Name)
132  .Case("gets", &WalkAST::checkCall_gets)
133  .Case("getpw", &WalkAST::checkCall_getpw)
134  .Case("mktemp", &WalkAST::checkCall_mktemp)
135  .Case("mkstemp", &WalkAST::checkCall_mkstemp)
136  .Case("mkdtemp", &WalkAST::checkCall_mkstemp)
137  .Case("mkstemps", &WalkAST::checkCall_mkstemp)
138  .Cases("strcpy", "__strcpy_chk", &WalkAST::checkCall_strcpy)
139  .Cases("strcat", "__strcat_chk", &WalkAST::checkCall_strcat)
140  .Case("drand48", &WalkAST::checkCall_rand)
141  .Case("erand48", &WalkAST::checkCall_rand)
142  .Case("jrand48", &WalkAST::checkCall_rand)
143  .Case("lrand48", &WalkAST::checkCall_rand)
144  .Case("mrand48", &WalkAST::checkCall_rand)
145  .Case("nrand48", &WalkAST::checkCall_rand)
146  .Case("lcong48", &WalkAST::checkCall_rand)
147  .Case("rand", &WalkAST::checkCall_rand)
148  .Case("rand_r", &WalkAST::checkCall_rand)
149  .Case("random", &WalkAST::checkCall_random)
150  .Case("vfork", &WalkAST::checkCall_vfork)
151  .Default(nullptr);
152 
153  // If the callee isn't defined, it is not of security concern.
154  // Check and evaluate the call.
155  if (evalFunction)
156  (this->*evalFunction)(CE, FD);
157 
158  // Recurse and check children.
159  VisitChildren(CE);
160 }
161 
162 void WalkAST::VisitCompoundStmt(CompoundStmt *S) {
163  for (Stmt *Child : S->children())
164  if (Child) {
165  if (CallExpr *CE = dyn_cast<CallExpr>(Child))
166  checkUncheckedReturnValue(CE);
167  Visit(Child);
168  }
169 }
170 
171 void WalkAST::VisitForStmt(ForStmt *FS) {
172  checkLoopConditionForFloat(FS);
173 
174  // Recurse and check children.
175  VisitChildren(FS);
176 }
177 
178 //===----------------------------------------------------------------------===//
179 // Check: floating poing variable used as loop counter.
180 // Originally: <rdar://problem/6336718>
181 // Implements: CERT security coding advisory FLP-30.
182 //===----------------------------------------------------------------------===//
183 
184 static const DeclRefExpr*
185 getIncrementedVar(const Expr *expr, const VarDecl *x, const VarDecl *y) {
186  expr = expr->IgnoreParenCasts();
187 
188  if (const BinaryOperator *B = dyn_cast<BinaryOperator>(expr)) {
189  if (!(B->isAssignmentOp() || B->isCompoundAssignmentOp() ||
190  B->getOpcode() == BO_Comma))
191  return nullptr;
192 
193  if (const DeclRefExpr *lhs = getIncrementedVar(B->getLHS(), x, y))
194  return lhs;
195 
196  if (const DeclRefExpr *rhs = getIncrementedVar(B->getRHS(), x, y))
197  return rhs;
198 
199  return nullptr;
200  }
201 
202  if (const DeclRefExpr *DR = dyn_cast<DeclRefExpr>(expr)) {
203  const NamedDecl *ND = DR->getDecl();
204  return ND == x || ND == y ? DR : nullptr;
205  }
206 
207  if (const UnaryOperator *U = dyn_cast<UnaryOperator>(expr))
208  return U->isIncrementDecrementOp()
209  ? getIncrementedVar(U->getSubExpr(), x, y) : nullptr;
210 
211  return nullptr;
212 }
213 
214 /// CheckLoopConditionForFloat - This check looks for 'for' statements that
215 /// use a floating point variable as a loop counter.
216 /// CERT: FLP30-C, FLP30-CPP.
217 ///
218 void WalkAST::checkLoopConditionForFloat(const ForStmt *FS) {
219  if (!filter.check_FloatLoopCounter)
220  return;
221 
222  // Does the loop have a condition?
223  const Expr *condition = FS->getCond();
224 
225  if (!condition)
226  return;
227 
228  // Does the loop have an increment?
229  const Expr *increment = FS->getInc();
230 
231  if (!increment)
232  return;
233 
234  // Strip away '()' and casts.
235  condition = condition->IgnoreParenCasts();
236  increment = increment->IgnoreParenCasts();
237 
238  // Is the loop condition a comparison?
239  const BinaryOperator *B = dyn_cast<BinaryOperator>(condition);
240 
241  if (!B)
242  return;
243 
244  // Is this a comparison?
245  if (!(B->isRelationalOp() || B->isEqualityOp()))
246  return;
247 
248  // Are we comparing variables?
249  const DeclRefExpr *drLHS =
250  dyn_cast<DeclRefExpr>(B->getLHS()->IgnoreParenLValueCasts());
251  const DeclRefExpr *drRHS =
252  dyn_cast<DeclRefExpr>(B->getRHS()->IgnoreParenLValueCasts());
253 
254  // Does at least one of the variables have a floating point type?
255  drLHS = drLHS && drLHS->getType()->isRealFloatingType() ? drLHS : nullptr;
256  drRHS = drRHS && drRHS->getType()->isRealFloatingType() ? drRHS : nullptr;
257 
258  if (!drLHS && !drRHS)
259  return;
260 
261  const VarDecl *vdLHS = drLHS ? dyn_cast<VarDecl>(drLHS->getDecl()) : nullptr;
262  const VarDecl *vdRHS = drRHS ? dyn_cast<VarDecl>(drRHS->getDecl()) : nullptr;
263 
264  if (!vdLHS && !vdRHS)
265  return;
266 
267  // Does either variable appear in increment?
268  const DeclRefExpr *drInc = getIncrementedVar(increment, vdLHS, vdRHS);
269 
270  if (!drInc)
271  return;
272 
273  // Emit the error. First figure out which DeclRefExpr in the condition
274  // referenced the compared variable.
275  assert(drInc->getDecl());
276  const DeclRefExpr *drCond = vdLHS == drInc->getDecl() ? drLHS : drRHS;
277 
279  SmallString<256> sbuf;
280  llvm::raw_svector_ostream os(sbuf);
281 
282  os << "Variable '" << drCond->getDecl()->getName()
283  << "' with floating point type '" << drCond->getType().getAsString()
284  << "' should not be used as a loop counter";
285 
286  ranges.push_back(drCond->getSourceRange());
287  ranges.push_back(drInc->getSourceRange());
288 
289  const char *bugType = "Floating point variable used as loop counter";
290 
291  PathDiagnosticLocation FSLoc =
292  PathDiagnosticLocation::createBegin(FS, BR.getSourceManager(), AC);
293  BR.EmitBasicReport(AC->getDecl(), filter.checkName_FloatLoopCounter,
294  bugType, "Security", os.str(),
295  FSLoc, ranges);
296 }
297 
298 //===----------------------------------------------------------------------===//
299 // Check: Any use of 'gets' is insecure.
300 // Originally: <rdar://problem/6335715>
301 // Implements (part of): 300-BSI (buildsecurityin.us-cert.gov)
302 // CWE-242: Use of Inherently Dangerous Function
303 //===----------------------------------------------------------------------===//
304 
305 void WalkAST::checkCall_gets(const CallExpr *CE, const FunctionDecl *FD) {
306  if (!filter.check_gets)
307  return;
308 
309  const FunctionProtoType *FPT = FD->getType()->getAs<FunctionProtoType>();
310  if (!FPT)
311  return;
312 
313  // Verify that the function takes a single argument.
314  if (FPT->getNumParams() != 1)
315  return;
316 
317  // Is the argument a 'char*'?
318  const PointerType *PT = FPT->getParamType(0)->getAs<PointerType>();
319  if (!PT)
320  return;
321 
322  if (PT->getPointeeType().getUnqualifiedType() != BR.getContext().CharTy)
323  return;
324 
325  // Issue a warning.
326  PathDiagnosticLocation CELoc =
327  PathDiagnosticLocation::createBegin(CE, BR.getSourceManager(), AC);
328  BR.EmitBasicReport(AC->getDecl(), filter.checkName_gets,
329  "Potential buffer overflow in call to 'gets'",
330  "Security",
331  "Call to function 'gets' is extremely insecure as it can "
332  "always result in a buffer overflow",
333  CELoc, CE->getCallee()->getSourceRange());
334 }
335 
336 //===----------------------------------------------------------------------===//
337 // Check: Any use of 'getpwd' is insecure.
338 // CWE-477: Use of Obsolete Functions
339 //===----------------------------------------------------------------------===//
340 
341 void WalkAST::checkCall_getpw(const CallExpr *CE, const FunctionDecl *FD) {
342  if (!filter.check_getpw)
343  return;
344 
345  const FunctionProtoType *FPT = FD->getType()->getAs<FunctionProtoType>();
346  if (!FPT)
347  return;
348 
349  // Verify that the function takes two arguments.
350  if (FPT->getNumParams() != 2)
351  return;
352 
353  // Verify the first argument type is integer.
355  return;
356 
357  // Verify the second argument type is char*.
358  const PointerType *PT = FPT->getParamType(1)->getAs<PointerType>();
359  if (!PT)
360  return;
361 
362  if (PT->getPointeeType().getUnqualifiedType() != BR.getContext().CharTy)
363  return;
364 
365  // Issue a warning.
366  PathDiagnosticLocation CELoc =
367  PathDiagnosticLocation::createBegin(CE, BR.getSourceManager(), AC);
368  BR.EmitBasicReport(AC->getDecl(), filter.checkName_getpw,
369  "Potential buffer overflow in call to 'getpw'",
370  "Security",
371  "The getpw() function is dangerous as it may overflow the "
372  "provided buffer. It is obsoleted by getpwuid().",
373  CELoc, CE->getCallee()->getSourceRange());
374 }
375 
376 //===----------------------------------------------------------------------===//
377 // Check: Any use of 'mktemp' is insecure. It is obsoleted by mkstemp().
378 // CWE-377: Insecure Temporary File
379 //===----------------------------------------------------------------------===//
380 
381 void WalkAST::checkCall_mktemp(const CallExpr *CE, const FunctionDecl *FD) {
382  if (!filter.check_mktemp) {
383  // Fall back to the security check of looking for enough 'X's in the
384  // format string, since that is a less severe warning.
385  checkCall_mkstemp(CE, FD);
386  return;
387  }
388 
389  const FunctionProtoType *FPT = FD->getType()->getAs<FunctionProtoType>();
390  if(!FPT)
391  return;
392 
393  // Verify that the function takes a single argument.
394  if (FPT->getNumParams() != 1)
395  return;
396 
397  // Verify that the argument is Pointer Type.
398  const PointerType *PT = FPT->getParamType(0)->getAs<PointerType>();
399  if (!PT)
400  return;
401 
402  // Verify that the argument is a 'char*'.
403  if (PT->getPointeeType().getUnqualifiedType() != BR.getContext().CharTy)
404  return;
405 
406  // Issue a warning.
407  PathDiagnosticLocation CELoc =
408  PathDiagnosticLocation::createBegin(CE, BR.getSourceManager(), AC);
409  BR.EmitBasicReport(AC->getDecl(), filter.checkName_mktemp,
410  "Potential insecure temporary file in call 'mktemp'",
411  "Security",
412  "Call to function 'mktemp' is insecure as it always "
413  "creates or uses insecure temporary file. Use 'mkstemp' "
414  "instead",
415  CELoc, CE->getCallee()->getSourceRange());
416 }
417 
418 
419 //===----------------------------------------------------------------------===//
420 // Check: Use of 'mkstemp', 'mktemp', 'mkdtemp' should contain at least 6 X's.
421 //===----------------------------------------------------------------------===//
422 
423 void WalkAST::checkCall_mkstemp(const CallExpr *CE, const FunctionDecl *FD) {
424  if (!filter.check_mkstemp)
425  return;
426 
427  StringRef Name = FD->getIdentifier()->getName();
428  std::pair<signed, signed> ArgSuffix =
429  llvm::StringSwitch<std::pair<signed, signed> >(Name)
430  .Case("mktemp", std::make_pair(0,-1))
431  .Case("mkstemp", std::make_pair(0,-1))
432  .Case("mkdtemp", std::make_pair(0,-1))
433  .Case("mkstemps", std::make_pair(0,1))
434  .Default(std::make_pair(-1, -1));
435 
436  assert(ArgSuffix.first >= 0 && "Unsupported function");
437 
438  // Check if the number of arguments is consistent with out expectations.
439  unsigned numArgs = CE->getNumArgs();
440  if ((signed) numArgs <= ArgSuffix.first)
441  return;
442 
443  const StringLiteral *strArg =
444  dyn_cast<StringLiteral>(CE->getArg((unsigned)ArgSuffix.first)
445  ->IgnoreParenImpCasts());
446 
447  // Currently we only handle string literals. It is possible to do better,
448  // either by looking at references to const variables, or by doing real
449  // flow analysis.
450  if (!strArg || strArg->getCharByteWidth() != 1)
451  return;
452 
453  // Count the number of X's, taking into account a possible cutoff suffix.
454  StringRef str = strArg->getString();
455  unsigned numX = 0;
456  unsigned n = str.size();
457 
458  // Take into account the suffix.
459  unsigned suffix = 0;
460  if (ArgSuffix.second >= 0) {
461  const Expr *suffixEx = CE->getArg((unsigned)ArgSuffix.second);
462  llvm::APSInt Result;
463  if (!suffixEx->EvaluateAsInt(Result, BR.getContext()))
464  return;
465  // FIXME: Issue a warning.
466  if (Result.isNegative())
467  return;
468  suffix = (unsigned) Result.getZExtValue();
469  n = (n > suffix) ? n - suffix : 0;
470  }
471 
472  for (unsigned i = 0; i < n; ++i)
473  if (str[i] == 'X') ++numX;
474 
475  if (numX >= 6)
476  return;
477 
478  // Issue a warning.
479  PathDiagnosticLocation CELoc =
480  PathDiagnosticLocation::createBegin(CE, BR.getSourceManager(), AC);
481  SmallString<512> buf;
482  llvm::raw_svector_ostream out(buf);
483  out << "Call to '" << Name << "' should have at least 6 'X's in the"
484  " format string to be secure (" << numX << " 'X'";
485  if (numX != 1)
486  out << 's';
487  out << " seen";
488  if (suffix) {
489  out << ", " << suffix << " character";
490  if (suffix > 1)
491  out << 's';
492  out << " used as a suffix";
493  }
494  out << ')';
495  BR.EmitBasicReport(AC->getDecl(), filter.checkName_mkstemp,
496  "Insecure temporary file creation", "Security",
497  out.str(), CELoc, strArg->getSourceRange());
498 }
499 
500 //===----------------------------------------------------------------------===//
501 // Check: Any use of 'strcpy' is insecure.
502 //
503 // CWE-119: Improper Restriction of Operations within
504 // the Bounds of a Memory Buffer
505 //===----------------------------------------------------------------------===//
506 void WalkAST::checkCall_strcpy(const CallExpr *CE, const FunctionDecl *FD) {
507  if (!filter.check_strcpy)
508  return;
509 
510  if (!checkCall_strCommon(CE, FD))
511  return;
512 
513  // Issue a warning.
514  PathDiagnosticLocation CELoc =
515  PathDiagnosticLocation::createBegin(CE, BR.getSourceManager(), AC);
516  BR.EmitBasicReport(AC->getDecl(), filter.checkName_strcpy,
517  "Potential insecure memory buffer bounds restriction in "
518  "call 'strcpy'",
519  "Security",
520  "Call to function 'strcpy' is insecure as it does not "
521  "provide bounding of the memory buffer. Replace "
522  "unbounded copy functions with analogous functions that "
523  "support length arguments such as 'strlcpy'. CWE-119.",
524  CELoc, CE->getCallee()->getSourceRange());
525 }
526 
527 //===----------------------------------------------------------------------===//
528 // Check: Any use of 'strcat' is insecure.
529 //
530 // CWE-119: Improper Restriction of Operations within
531 // the Bounds of a Memory Buffer
532 //===----------------------------------------------------------------------===//
533 void WalkAST::checkCall_strcat(const CallExpr *CE, const FunctionDecl *FD) {
534  if (!filter.check_strcpy)
535  return;
536 
537  if (!checkCall_strCommon(CE, FD))
538  return;
539 
540  // Issue a warning.
541  PathDiagnosticLocation CELoc =
542  PathDiagnosticLocation::createBegin(CE, BR.getSourceManager(), AC);
543  BR.EmitBasicReport(AC->getDecl(), filter.checkName_strcpy,
544  "Potential insecure memory buffer bounds restriction in "
545  "call 'strcat'",
546  "Security",
547  "Call to function 'strcat' is insecure as it does not "
548  "provide bounding of the memory buffer. Replace "
549  "unbounded copy functions with analogous functions that "
550  "support length arguments such as 'strlcat'. CWE-119.",
551  CELoc, CE->getCallee()->getSourceRange());
552 }
553 
554 //===----------------------------------------------------------------------===//
555 // Common check for str* functions with no bounds parameters.
556 //===----------------------------------------------------------------------===//
557 bool WalkAST::checkCall_strCommon(const CallExpr *CE, const FunctionDecl *FD) {
558  const FunctionProtoType *FPT = FD->getType()->getAs<FunctionProtoType>();
559  if (!FPT)
560  return false;
561 
562  // Verify the function takes two arguments, three in the _chk version.
563  int numArgs = FPT->getNumParams();
564  if (numArgs != 2 && numArgs != 3)
565  return false;
566 
567  // Verify the type for both arguments.
568  for (int i = 0; i < 2; i++) {
569  // Verify that the arguments are pointers.
570  const PointerType *PT = FPT->getParamType(i)->getAs<PointerType>();
571  if (!PT)
572  return false;
573 
574  // Verify that the argument is a 'char*'.
575  if (PT->getPointeeType().getUnqualifiedType() != BR.getContext().CharTy)
576  return false;
577  }
578 
579  return true;
580 }
581 
582 //===----------------------------------------------------------------------===//
583 // Check: Linear congruent random number generators should not be used
584 // Originally: <rdar://problem/63371000>
585 // CWE-338: Use of cryptographically weak prng
586 //===----------------------------------------------------------------------===//
587 
588 void WalkAST::checkCall_rand(const CallExpr *CE, const FunctionDecl *FD) {
589  if (!filter.check_rand || !CheckRand)
590  return;
591 
592  const FunctionProtoType *FTP = FD->getType()->getAs<FunctionProtoType>();
593  if (!FTP)
594  return;
595 
596  if (FTP->getNumParams() == 1) {
597  // Is the argument an 'unsigned short *'?
598  // (Actually any integer type is allowed.)
599  const PointerType *PT = FTP->getParamType(0)->getAs<PointerType>();
600  if (!PT)
601  return;
602 
604  return;
605  } else if (FTP->getNumParams() != 0)
606  return;
607 
608  // Issue a warning.
609  SmallString<256> buf1;
610  llvm::raw_svector_ostream os1(buf1);
611  os1 << '\'' << *FD << "' is a poor random number generator";
612 
613  SmallString<256> buf2;
614  llvm::raw_svector_ostream os2(buf2);
615  os2 << "Function '" << *FD
616  << "' is obsolete because it implements a poor random number generator."
617  << " Use 'arc4random' instead";
618 
619  PathDiagnosticLocation CELoc =
620  PathDiagnosticLocation::createBegin(CE, BR.getSourceManager(), AC);
621  BR.EmitBasicReport(AC->getDecl(), filter.checkName_rand, os1.str(),
622  "Security", os2.str(), CELoc,
623  CE->getCallee()->getSourceRange());
624 }
625 
626 //===----------------------------------------------------------------------===//
627 // Check: 'random' should not be used
628 // Originally: <rdar://problem/63371000>
629 //===----------------------------------------------------------------------===//
630 
631 void WalkAST::checkCall_random(const CallExpr *CE, const FunctionDecl *FD) {
632  if (!CheckRand || !filter.check_rand)
633  return;
634 
635  const FunctionProtoType *FTP = FD->getType()->getAs<FunctionProtoType>();
636  if (!FTP)
637  return;
638 
639  // Verify that the function takes no argument.
640  if (FTP->getNumParams() != 0)
641  return;
642 
643  // Issue a warning.
644  PathDiagnosticLocation CELoc =
645  PathDiagnosticLocation::createBegin(CE, BR.getSourceManager(), AC);
646  BR.EmitBasicReport(AC->getDecl(), filter.checkName_rand,
647  "'random' is not a secure random number generator",
648  "Security",
649  "The 'random' function produces a sequence of values that "
650  "an adversary may be able to predict. Use 'arc4random' "
651  "instead", CELoc, CE->getCallee()->getSourceRange());
652 }
653 
654 //===----------------------------------------------------------------------===//
655 // Check: 'vfork' should not be used.
656 // POS33-C: Do not use vfork().
657 //===----------------------------------------------------------------------===//
658 
659 void WalkAST::checkCall_vfork(const CallExpr *CE, const FunctionDecl *FD) {
660  if (!filter.check_vfork)
661  return;
662 
663  // All calls to vfork() are insecure, issue a warning.
664  PathDiagnosticLocation CELoc =
665  PathDiagnosticLocation::createBegin(CE, BR.getSourceManager(), AC);
666  BR.EmitBasicReport(AC->getDecl(), filter.checkName_vfork,
667  "Potential insecure implementation-specific behavior in "
668  "call 'vfork'",
669  "Security",
670  "Call to function 'vfork' is insecure as it can lead to "
671  "denial of service situations in the parent process. "
672  "Replace calls to vfork with calls to the safer "
673  "'posix_spawn' function",
674  CELoc, CE->getCallee()->getSourceRange());
675 }
676 
677 //===----------------------------------------------------------------------===//
678 // Check: Should check whether privileges are dropped successfully.
679 // Originally: <rdar://problem/6337132>
680 //===----------------------------------------------------------------------===//
681 
682 void WalkAST::checkUncheckedReturnValue(CallExpr *CE) {
683  if (!filter.check_UncheckedReturn)
684  return;
685 
686  const FunctionDecl *FD = CE->getDirectCallee();
687  if (!FD)
688  return;
689 
690  if (II_setid[0] == nullptr) {
691  static const char * const identifiers[num_setids] = {
692  "setuid", "setgid", "seteuid", "setegid",
693  "setreuid", "setregid"
694  };
695 
696  for (size_t i = 0; i < num_setids; i++)
697  II_setid[i] = &BR.getContext().Idents.get(identifiers[i]);
698  }
699 
700  const IdentifierInfo *id = FD->getIdentifier();
701  size_t identifierid;
702 
703  for (identifierid = 0; identifierid < num_setids; identifierid++)
704  if (id == II_setid[identifierid])
705  break;
706 
707  if (identifierid >= num_setids)
708  return;
709 
710  const FunctionProtoType *FTP = FD->getType()->getAs<FunctionProtoType>();
711  if (!FTP)
712  return;
713 
714  // Verify that the function takes one or two arguments (depending on
715  // the function).
716  if (FTP->getNumParams() != (identifierid < 4 ? 1 : 2))
717  return;
718 
719  // The arguments must be integers.
720  for (unsigned i = 0; i < FTP->getNumParams(); i++)
722  return;
723 
724  // Issue a warning.
725  SmallString<256> buf1;
726  llvm::raw_svector_ostream os1(buf1);
727  os1 << "Return value is not checked in call to '" << *FD << '\'';
728 
729  SmallString<256> buf2;
730  llvm::raw_svector_ostream os2(buf2);
731  os2 << "The return value from the call to '" << *FD
732  << "' is not checked. If an error occurs in '" << *FD
733  << "', the following code may execute with unexpected privileges";
734 
735  PathDiagnosticLocation CELoc =
736  PathDiagnosticLocation::createBegin(CE, BR.getSourceManager(), AC);
737  BR.EmitBasicReport(AC->getDecl(), filter.checkName_UncheckedReturn, os1.str(),
738  "Security", os2.str(), CELoc,
739  CE->getCallee()->getSourceRange());
740 }
741 
742 //===----------------------------------------------------------------------===//
743 // SecuritySyntaxChecker
744 //===----------------------------------------------------------------------===//
745 
746 namespace {
747 class SecuritySyntaxChecker : public Checker<check::ASTCodeBody> {
748 public:
749  ChecksFilter filter;
750 
751  void checkASTCodeBody(const Decl *D, AnalysisManager& mgr,
752  BugReporter &BR) const {
753  WalkAST walker(BR, mgr.getAnalysisDeclContext(D), filter);
754  walker.Visit(D->getBody());
755  }
756 };
757 }
758 
759 #define REGISTER_CHECKER(name) \
760  void ento::register##name(CheckerManager &mgr) { \
761  SecuritySyntaxChecker *checker = \
762  mgr.registerChecker<SecuritySyntaxChecker>(); \
763  checker->filter.check_##name = true; \
764  checker->filter.checkName_##name = mgr.getCurrentCheckName(); \
765  }
766 
767 REGISTER_CHECKER(gets)
768 REGISTER_CHECKER(getpw)
769 REGISTER_CHECKER(mkstemp)
770 REGISTER_CHECKER(mktemp)
771 REGISTER_CHECKER(strcpy)
772 REGISTER_CHECKER(rand)
773 REGISTER_CHECKER(vfork)
774 REGISTER_CHECKER(FloatLoopCounter)
775 REGISTER_CHECKER(UncheckedReturn)
776 
777 
Expr * getInc()
Definition: Stmt.h:1213
FunctionDecl - An instance of this class is created to represent a function declaration or definition...
Definition: Decl.h:1631
const internal::VariadicDynCastAllOfMatcher< Stmt, Expr > expr
Matches expressions.
Definition: ASTMatchers.h:1538
PointerType - C99 6.7.5.1 - Pointer Declarators.
Definition: Type.h:2222
QualType getPointeeType() const
Definition: Type.h:2236
Expr * getArg(unsigned Arg)
getArg - Return the specified argument.
Definition: Expr.h:2278
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:955
Stmt - This represents one statement.
Definition: Stmt.h:60
unsigned getNumArgs() const
getNumArgs - Return the number of actual arguments to this call.
Definition: Expr.h:2266
A helper class which wraps a boolean value set to false by default.
Definition: Checker.h:551
const llvm::Triple & getTriple() const
Returns the target triple of the primary target.
Definition: TargetInfo.h:782
bool isRealFloatingType() const
Floating point categories.
Definition: Type.cpp:1858
Decl - This represents one declaration (or definition), e.g.
Definition: DeclBase.h:81
const TargetInfo & getTargetInfo() const
Definition: ASTContext.h:645
bool EvaluateAsInt(llvm::APSInt &Result, const ASTContext &Ctx, SideEffectsKind AllowSideEffects=SE_NoSideEffects) const
EvaluateAsInt - Return true if this is a constant which we can fold and convert to an integer...
VarDecl - An instance of this class is created to represent a variable declaration or definition...
Definition: Decl.h:771
unsigned getNumParams() const
Definition: Type.h:3393
const T * getAs() const
Member-template getAs<specific type>&#39;.
Definition: Type.h:6099
IdentifierInfo * getIdentifier() const
getIdentifier - Get the identifier that names this declaration, if there is one.
Definition: Decl.h:232
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:128
AnalysisDeclContext contains the context data for the function or method under analysis.
unsigned getCharByteWidth() const
Definition: Expr.h:1591
static bool isRelationalOp(Opcode Opc)
Definition: Expr.h:3070
ForStmt - This represents a &#39;for (init;cond;inc)&#39; stmt.
Definition: Stmt.h:1179
static bool isEqualityOp(Opcode Opc)
Definition: Expr.h:3073
ASTContext & getContext()
Definition: BugReporter.h:461
child_range children()
Definition: Stmt.cpp:208
A builtin binary operation expression such as "x + y" or "x <= y".
Definition: Expr.h:2986
Expr * IgnoreParenCasts() LLVM_READONLY
IgnoreParenCasts - Ignore parentheses and casts.
Definition: Expr.cpp:2463
Expr * getCond()
Definition: Stmt.h:1212
child_range children()
Definition: Stmt.h:661
AnalysisDeclContext * getAnalysisDeclContext(const Decl *D)
bool isIntegralOrUnscopedEnumerationType() const
Determine whether this type is an integral or unscoped enumeration type.
Definition: Type.cpp:1698
StringRef getString() const
Definition: Expr.h:1557
CompoundStmt - This represents a group of statements like { stmt stmt }.
Definition: Stmt.h:575
Represents a prototype with parameter type info, e.g.
Definition: Type.h:3170
Expr - This represents one expression.
Definition: Expr.h:106
const FunctionProtoType * T
const Expr * getCallee() const
Definition: Expr.h:2249
QualType getType() const
Definition: Expr.h:128
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:1717
ValueDecl * getDecl()
Definition: Expr.h:1041
BugReporter is a utility class for generating PathDiagnostics for analysis.
Definition: BugReporter.h:403
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:180
#define REGISTER_CHECKER(name)
Expr * getLHS() const
Definition: Expr.h:3030
StringRef getName() const
Return the actual identifier string.
Dataflow Directional Tag Classes.
FunctionDecl * getDirectCallee()
If the callee is a FunctionDecl, return it. Otherwise return 0.
Definition: Expr.cpp:1216
Expr * IgnoreParenImpCasts() LLVM_READONLY
IgnoreParenImpCasts - Ignore parentheses and implicit casts.
Definition: Expr.cpp:2550
Expr * IgnoreParenLValueCasts() LLVM_READONLY
Ignore parentheses and lvalue casts.
Definition: Expr.cpp:2510
QualType getParamType(unsigned i) const
Definition: Type.h:3394
QualType getUnqualifiedType() const
Retrieve the unqualified variant of the given type, removing as little sugar as possible.
Definition: Type.h:5623
SourceRange getSourceRange() const LLVM_READONLY
SourceLocation tokens are not useful in isolation - they are low level value objects created/interpre...
Definition: Stmt.cpp:245
StringLiteral - This represents a string literal expression, e.g.
Definition: Expr.h:1509
Defines the clang::TargetInfo interface.
CallExpr - Represents a function call (C99 6.5.2.2, C++ [expr.call]).
Definition: Expr.h:2209
A reference to a declared variable, function, enum, etc.
Definition: Expr.h:956
Expr * getRHS() const
Definition: Expr.h:3032
static bool isArc4RandomAvailable(const ASTContext &Ctx)
QualType getType() const
Definition: Decl.h:602
NamedDecl - This represents a decl with a name.
Definition: Decl.h:213