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