Coverage Report

Created: 2020-02-25 14:32

/Users/buildslave/jenkins/workspace/coverage/llvm-project/clang/lib/StaticAnalyzer/Checkers/CheckSecuritySyntaxOnly.cpp
Line
Count
Source (jump to first uncovered line)
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
194
static bool isArc4RandomAvailable(const ASTContext &Ctx) {
28
194
  const llvm::Triple &T = Ctx.getTargetInfo().getTriple();
29
194
  return T.getVendor() == llvm::Triple::Apple ||
30
194
         
T.getOS() == llvm::Triple::CloudABI77
||
31
194
         
T.isOSFreeBSD()1
||
32
194
         
T.isOSNetBSD()1
||
33
194
         
T.isOSOpenBSD()1
||
34
194
         
T.isOSDragonFly()1
;
35
194
}
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
194
    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
5.44k
  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
6.16k
void WalkAST::VisitChildren(Stmt *S) {
127
6.16k
  for (Stmt *Child : S->children())
128
5.31k
    if (Child)
129
5.25k
      Visit(Child);
130
6.16k
}
131
132
643
void WalkAST::VisitCallExpr(CallExpr *CE) {
133
643
  // Get the callee.
134
643
  const FunctionDecl *FD = CE->getDirectCallee();
135
643
136
643
  if (!FD)
137
0
    return;
138
643
139
643
  // Get the name of the callee. If it's a builtin, strip off the prefix.
140
643
  IdentifierInfo *II = FD->getIdentifier();
141
643
  if (!II)   // if no identifier, not a simple C function
142
0
    return;
143
643
  StringRef Name = II->getName();
144
643
  if (Name.startswith("__builtin_"))
145
45
    Name = Name.substr(10);
146
643
147
643
  // Set the evaluation function by switching on the callee name.
148
643
  FnCheck evalFunction = llvm::StringSwitch<FnCheck>(Name)
149
643
    .Case("bcmp", &WalkAST::checkCall_bcmp)
150
643
    .Case("bcopy", &WalkAST::checkCall_bcopy)
151
643
    .Case("bzero", &WalkAST::checkCall_bzero)
152
643
    .Case("gets", &WalkAST::checkCall_gets)
153
643
    .Case("getpw", &WalkAST::checkCall_getpw)
154
643
    .Case("mktemp", &WalkAST::checkCall_mktemp)
155
643
    .Case("mkstemp", &WalkAST::checkCall_mkstemp)
156
643
    .Case("mkdtemp", &WalkAST::checkCall_mkstemp)
157
643
    .Case("mkstemps", &WalkAST::checkCall_mkstemp)
158
643
    .Cases("strcpy", "__strcpy_chk", &WalkAST::checkCall_strcpy)
159
643
    .Cases("strcat", "__strcat_chk", &WalkAST::checkCall_strcat)
160
643
    .Cases("sprintf", "vsprintf", "scanf", "wscanf", "fscanf", "fwscanf",
161
643
           "vscanf", "vwscanf", "vfscanf", "vfwscanf",
162
643
           &WalkAST::checkDeprecatedOrUnsafeBufferHandling)
163
643
    .Cases("sscanf", "swscanf", "vsscanf", "vswscanf", "swprintf",
164
643
           "snprintf", "vswprintf", "vsnprintf", "memcpy", "memmove",
165
643
           &WalkAST::checkDeprecatedOrUnsafeBufferHandling)
166
643
    .Cases("strncpy", "strncat", "memset",
167
643
           &WalkAST::checkDeprecatedOrUnsafeBufferHandling)
168
643
    .Case("drand48", &WalkAST::checkCall_rand)
169
643
    .Case("erand48", &WalkAST::checkCall_rand)
170
643
    .Case("jrand48", &WalkAST::checkCall_rand)
171
643
    .Case("lrand48", &WalkAST::checkCall_rand)
172
643
    .Case("mrand48", &WalkAST::checkCall_rand)
173
643
    .Case("nrand48", &WalkAST::checkCall_rand)
174
643
    .Case("lcong48", &WalkAST::checkCall_rand)
175
643
    .Case("rand", &WalkAST::checkCall_rand)
176
643
    .Case("rand_r", &WalkAST::checkCall_rand)
177
643
    .Case("random", &WalkAST::checkCall_random)
178
643
    .Case("vfork", &WalkAST::checkCall_vfork)
179
643
    .Default(nullptr);
180
643
181
643
  // If the callee isn't defined, it is not of security concern.
182
643
  // Check and evaluate the call.
183
643
  if (evalFunction)
184
513
    (this->*evalFunction)(CE, FD);
185
643
186
643
  // Recurse and check children.
187
643
  VisitChildren(CE);
188
643
}
189
190
16
void WalkAST::VisitObjCMessageExpr(ObjCMessageExpr *ME) {
191
16
  MsgCheck evalFunction =
192
16
      llvm::StringSwitch<MsgCheck>(ME->getSelector().getAsString())
193
16
          .Case("decodeValueOfObjCType:at:",
194
16
                &WalkAST::checkMsg_decodeValueOfObjCType)
195
16
          .Default(nullptr);
196
16
197
16
  if (evalFunction)
198
8
    (this->*evalFunction)(ME);
199
16
200
16
  // Recurse and check children.
201
16
  VisitChildren(ME);
202
16
}
203
204
284
void WalkAST::VisitCompoundStmt(CompoundStmt *S) {
205
284
  for (Stmt *Child : S->children())
206
1.00k
    if (Child) {
207
1.00k
      if (CallExpr *CE = dyn_cast<CallExpr>(Child))
208
553
        checkUncheckedReturnValue(CE);
209
1.00k
      Visit(Child);
210
1.00k
    }
211
284
}
212
213
64
void WalkAST::VisitForStmt(ForStmt *FS) {
214
64
  checkLoopConditionForFloat(FS);
215
64
216
64
  // Recurse and check children.
217
64
  VisitChildren(FS);
218
64
}
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
136
getIncrementedVar(const Expr *expr, const VarDecl *x, const VarDecl *y) {
230
136
  expr = expr->IgnoreParenCasts();
231
136
232
136
  if (const BinaryOperator *B = dyn_cast<BinaryOperator>(expr)) {
233
32
    if (!(B->isAssignmentOp() || 
B->isCompoundAssignmentOp()8
||
234
32
          
B->getOpcode() == BO_Comma8
))
235
0
      return nullptr;
236
32
237
32
    if (const DeclRefExpr *lhs = getIncrementedVar(B->getLHS(), x, y))
238
32
      return lhs;
239
0
240
0
    if (const DeclRefExpr *rhs = getIncrementedVar(B->getRHS(), x, y))
241
0
      return rhs;
242
0
243
0
    return nullptr;
244
0
  }
245
104
246
104
  if (const DeclRefExpr *DR = dyn_cast<DeclRefExpr>(expr)) {
247
64
    const NamedDecl *ND = DR->getDecl();
248
64
    return ND == x || 
ND == y8
? DR :
nullptr0
;
249
64
  }
250
40
251
40
  if (const UnaryOperator *U = dyn_cast<UnaryOperator>(expr))
252
40
    return U->isIncrementDecrementOp()
253
40
      ? getIncrementedVar(U->getSubExpr(), x, y) : 
nullptr0
;
254
0
255
0
  return nullptr;
256
0
}
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
64
void WalkAST::checkLoopConditionForFloat(const ForStmt *FS) {
263
64
  if (!filter.check_FloatLoopCounter)
264
0
    return;
265
64
266
64
  // Does the loop have a condition?
267
64
  const Expr *condition = FS->getCond();
268
64
269
64
  if (!condition)
270
0
    return;
271
64
272
64
  // Does the loop have an increment?
273
64
  const Expr *increment = FS->getInc();
274
64
275
64
  if (!increment)
276
0
    return;
277
64
278
64
  // Strip away '()' and casts.
279
64
  condition = condition->IgnoreParenCasts();
280
64
  increment = increment->IgnoreParenCasts();
281
64
282
64
  // Is the loop condition a comparison?
283
64
  const BinaryOperator *B = dyn_cast<BinaryOperator>(condition);
284
64
285
64
  if (!B)
286
0
    return;
287
64
288
64
  // Is this a comparison?
289
64
  if (!(B->isRelationalOp() || 
B->isEqualityOp()0
))
290
0
    return;
291
64
292
64
  // Are we comparing variables?
293
64
  const DeclRefExpr *drLHS =
294
64
    dyn_cast<DeclRefExpr>(B->getLHS()->IgnoreParenLValueCasts());
295
64
  const DeclRefExpr *drRHS =
296
64
    dyn_cast<DeclRefExpr>(B->getRHS()->IgnoreParenLValueCasts());
297
64
298
64
  // Does at least one of the variables have a floating point type?
299
64
  drLHS = drLHS && 
drLHS->getType()->isRealFloatingType()56
?
drLHS56
:
nullptr8
;
300
64
  drRHS = drRHS && 
drRHS->getType()->isRealFloatingType()8
?
drRHS8
:
nullptr56
;
301
64
302
64
  if (!drLHS && 
!drRHS8
)
303
0
    return;
304
64
305
64
  const VarDecl *vdLHS = drLHS ? 
dyn_cast<VarDecl>(drLHS->getDecl())56
:
nullptr8
;
306
64
  const VarDecl *vdRHS = drRHS ? 
dyn_cast<VarDecl>(drRHS->getDecl())8
:
nullptr56
;
307
64
308
64
  if (!vdLHS && 
!vdRHS8
)
309
0
    return;
310
64
311
64
  // Does either variable appear in increment?
312
64
  const DeclRefExpr *drInc = getIncrementedVar(increment, vdLHS, vdRHS);
313
64
  if (!drInc)
314
0
    return;
315
64
316
64
  const VarDecl *vdInc = cast<VarDecl>(drInc->getDecl());
317
64
  assert(vdInc && (vdInc == vdLHS || vdInc == vdRHS));
318
64
319
64
  // Emit the error.  First figure out which DeclRefExpr in the condition
320
64
  // referenced the compared variable.
321
64
  const DeclRefExpr *drCond = vdLHS == vdInc ? 
drLHS56
:
drRHS8
;
322
64
323
64
  SmallVector<SourceRange, 2> ranges;
324
64
  SmallString<256> sbuf;
325
64
  llvm::raw_svector_ostream os(sbuf);
326
64
327
64
  os << "Variable '" << drCond->getDecl()->getName()
328
64
     << "' with floating point type '" << drCond->getType().getAsString()
329
64
     << "' should not be used as a loop counter";
330
64
331
64
  ranges.push_back(drCond->getSourceRange());
332
64
  ranges.push_back(drInc->getSourceRange());
333
64
334
64
  const char *bugType = "Floating point variable used as loop counter";
335
64
336
64
  PathDiagnosticLocation FSLoc =
337
64
    PathDiagnosticLocation::createBegin(FS, BR.getSourceManager(), AC);
338
64
  BR.EmitBasicReport(AC->getDecl(), filter.checkName_FloatLoopCounter,
339
64
                     bugType, "Security", os.str(),
340
64
                     FSLoc, ranges);
341
64
}
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
8
void WalkAST::checkCall_bcmp(const CallExpr *CE, const FunctionDecl *FD) {
350
8
  if (!filter.check_bcmp)
351
0
    return;
352
8
353
8
  const FunctionProtoType *FPT = FD->getType()->getAs<FunctionProtoType>();
354
8
  if (!FPT)
355
0
    return;
356
8
357
8
  // Verify that the function takes three arguments.
358
8
  if (FPT->getNumParams() != 3)
359
0
    return;
360
8
361
24
  
for (int i = 0; 8
i < 2;
i++16
) {
362
16
    // Verify the first and second argument type is void*.
363
16
    const PointerType *PT = FPT->getParamType(i)->getAs<PointerType>();
364
16
    if (!PT)
365
0
      return;
366
16
367
16
    if (PT->getPointeeType().getUnqualifiedType() != BR.getContext().VoidTy)
368
0
      return;
369
16
  }
370
8
371
8
  // Verify the third argument type is integer.
372
8
  if (!FPT->getParamType(2)->isIntegralOrUnscopedEnumerationType())
373
0
    return;
374
8
375
8
  // Issue a warning.
376
8
  PathDiagnosticLocation CELoc =
377
8
    PathDiagnosticLocation::createBegin(CE, BR.getSourceManager(), AC);
378
8
  BR.EmitBasicReport(AC->getDecl(), filter.checkName_bcmp,
379
8
                     "Use of deprecated function in call to 'bcmp()'",
380
8
                     "Security",
381
8
                     "The bcmp() function is obsoleted by memcmp().",
382
8
                     CELoc, CE->getCallee()->getSourceRange());
383
8
}
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
8
void WalkAST::checkCall_bcopy(const CallExpr *CE, const FunctionDecl *FD) {
392
8
  if (!filter.check_bcopy)
393
0
    return;
394
8
395
8
  const FunctionProtoType *FPT = FD->getType()->getAs<FunctionProtoType>();
396
8
  if (!FPT)
397
0
    return;
398
8
399
8
  // Verify that the function takes three arguments.
400
8
  if (FPT->getNumParams() != 3)
401
0
    return;
402
8
403
24
  
for (int i = 0; 8
i < 2;
i++16
) {
404
16
    // Verify the first and second argument type is void*.
405
16
    const PointerType *PT = FPT->getParamType(i)->getAs<PointerType>();
406
16
    if (!PT)
407
0
      return;
408
16
409
16
    if (PT->getPointeeType().getUnqualifiedType() != BR.getContext().VoidTy)
410
0
      return;
411
16
  }
412
8
413
8
  // Verify the third argument type is integer.
414
8
  if (!FPT->getParamType(2)->isIntegralOrUnscopedEnumerationType())
415
0
    return;
416
8
417
8
  // Issue a warning.
418
8
  PathDiagnosticLocation CELoc =
419
8
    PathDiagnosticLocation::createBegin(CE, BR.getSourceManager(), AC);
420
8
  BR.EmitBasicReport(AC->getDecl(), filter.checkName_bcopy,
421
8
                     "Use of deprecated function in call to 'bcopy()'",
422
8
                     "Security",
423
8
                     "The bcopy() function is obsoleted by memcpy() "
424
8
                     "or memmove().",
425
8
                     CELoc, CE->getCallee()->getSourceRange());
426
8
}
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
8
void WalkAST::checkCall_bzero(const CallExpr *CE, const FunctionDecl *FD) {
435
8
  if (!filter.check_bzero)
436
0
    return;
437
8
438
8
  const FunctionProtoType *FPT = FD->getType()->getAs<FunctionProtoType>();
439
8
  if (!FPT)
440
0
    return;
441
8
442
8
  // Verify that the function takes two arguments.
443
8
  if (FPT->getNumParams() != 2)
444
0
    return;
445
8
446
8
  // Verify the first argument type is void*.
447
8
  const PointerType *PT = FPT->getParamType(0)->getAs<PointerType>();
448
8
  if (!PT)
449
0
    return;
450
8
451
8
  if (PT->getPointeeType().getUnqualifiedType() != BR.getContext().VoidTy)
452
0
    return;
453
8
454
8
  // Verify the second argument type is integer.
455
8
  if (!FPT->getParamType(1)->isIntegralOrUnscopedEnumerationType())
456
0
    return;
457
8
458
8
  // Issue a warning.
459
8
  PathDiagnosticLocation CELoc =
460
8
    PathDiagnosticLocation::createBegin(CE, BR.getSourceManager(), AC);
461
8
  BR.EmitBasicReport(AC->getDecl(), filter.checkName_bzero,
462
8
                     "Use of deprecated function in call to 'bzero()'",
463
8
                     "Security",
464
8
                     "The bzero() function is obsoleted by memset().",
465
8
                     CELoc, CE->getCallee()->getSourceRange());
466
8
}
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
8
void WalkAST::checkCall_gets(const CallExpr *CE, const FunctionDecl *FD) {
477
8
  if (!filter.check_gets)
478
0
    return;
479
8
480
8
  const FunctionProtoType *FPT = FD->getType()->getAs<FunctionProtoType>();
481
8
  if (!FPT)
482
0
    return;
483
8
484
8
  // Verify that the function takes a single argument.
485
8
  if (FPT->getNumParams() != 1)
486
0
    return;
487
8
488
8
  // Is the argument a 'char*'?
489
8
  const PointerType *PT = FPT->getParamType(0)->getAs<PointerType>();
490
8
  if (!PT)
491
0
    return;
492
8
493
8
  if (PT->getPointeeType().getUnqualifiedType() != BR.getContext().CharTy)
494
0
    return;
495
8
496
8
  // Issue a warning.
497
8
  PathDiagnosticLocation CELoc =
498
8
    PathDiagnosticLocation::createBegin(CE, BR.getSourceManager(), AC);
499
8
  BR.EmitBasicReport(AC->getDecl(), filter.checkName_gets,
500
8
                     "Potential buffer overflow in call to 'gets'",
501
8
                     "Security",
502
8
                     "Call to function 'gets' is extremely insecure as it can "
503
8
                     "always result in a buffer overflow",
504
8
                     CELoc, CE->getCallee()->getSourceRange());
505
8
}
506
507
//===----------------------------------------------------------------------===//
508
// Check: Any use of 'getpwd' is insecure.
509
// CWE-477: Use of Obsolete Functions
510
//===----------------------------------------------------------------------===//
511
512
8
void WalkAST::checkCall_getpw(const CallExpr *CE, const FunctionDecl *FD) {
513
8
  if (!filter.check_getpw)
514
0
    return;
515
8
516
8
  const FunctionProtoType *FPT = FD->getType()->getAs<FunctionProtoType>();
517
8
  if (!FPT)
518
0
    return;
519
8
520
8
  // Verify that the function takes two arguments.
521
8
  if (FPT->getNumParams() != 2)
522
0
    return;
523
8
524
8
  // Verify the first argument type is integer.
525
8
  if (!FPT->getParamType(0)->isIntegralOrUnscopedEnumerationType())
526
0
    return;
527
8
528
8
  // Verify the second argument type is char*.
529
8
  const PointerType *PT = FPT->getParamType(1)->getAs<PointerType>();
530
8
  if (!PT)
531
0
    return;
532
8
533
8
  if (PT->getPointeeType().getUnqualifiedType() != BR.getContext().CharTy)
534
0
    return;
535
8
536
8
  // Issue a warning.
537
8
  PathDiagnosticLocation CELoc =
538
8
    PathDiagnosticLocation::createBegin(CE, BR.getSourceManager(), AC);
539
8
  BR.EmitBasicReport(AC->getDecl(), filter.checkName_getpw,
540
8
                     "Potential buffer overflow in call to 'getpw'",
541
8
                     "Security",
542
8
                     "The getpw() function is dangerous as it may overflow the "
543
8
                     "provided buffer. It is obsoleted by getpwuid().",
544
8
                     CELoc, CE->getCallee()->getSourceRange());
545
8
}
546
547
//===----------------------------------------------------------------------===//
548
// Check: Any use of 'mktemp' is insecure.  It is obsoleted by mkstemp().
549
// CWE-377: Insecure Temporary File
550
//===----------------------------------------------------------------------===//
551
552
8
void WalkAST::checkCall_mktemp(const CallExpr *CE, const FunctionDecl *FD) {
553
8
  if (!filter.check_mktemp) {
554
0
    // Fall back to the security check of looking for enough 'X's in the
555
0
    // format string, since that is a less severe warning.
556
0
    checkCall_mkstemp(CE, FD);
557
0
    return;
558
0
  }
559
8
560
8
  const FunctionProtoType *FPT = FD->getType()->getAs<FunctionProtoType>();
561
8
  if(!FPT)
562
0
    return;
563
8
564
8
  // Verify that the function takes a single argument.
565
8
  if (FPT->getNumParams() != 1)
566
0
    return;
567
8
568
8
  // Verify that the argument is Pointer Type.
569
8
  const PointerType *PT = FPT->getParamType(0)->getAs<PointerType>();
570
8
  if (!PT)
571
0
    return;
572
8
573
8
  // Verify that the argument is a 'char*'.
574
8
  if (PT->getPointeeType().getUnqualifiedType() != BR.getContext().CharTy)
575
0
    return;
576
8
577
8
  // Issue a warning.
578
8
  PathDiagnosticLocation CELoc =
579
8
    PathDiagnosticLocation::createBegin(CE, BR.getSourceManager(), AC);
580
8
  BR.EmitBasicReport(AC->getDecl(), filter.checkName_mktemp,
581
8
                     "Potential insecure temporary file in call 'mktemp'",
582
8
                     "Security",
583
8
                     "Call to function 'mktemp' is insecure as it always "
584
8
                     "creates or uses insecure temporary file.  Use 'mkstemp' "
585
8
                     "instead",
586
8
                     CELoc, CE->getCallee()->getSourceRange());
587
8
}
588
589
//===----------------------------------------------------------------------===//
590
// Check: Use of 'mkstemp', 'mktemp', 'mkdtemp' should contain at least 6 X's.
591
//===----------------------------------------------------------------------===//
592
593
72
void WalkAST::checkCall_mkstemp(const CallExpr *CE, const FunctionDecl *FD) {
594
72
  if (!filter.check_mkstemp)
595
0
    return;
596
72
597
72
  StringRef Name = FD->getIdentifier()->getName();
598
72
  std::pair<signed, signed> ArgSuffix =
599
72
    llvm::StringSwitch<std::pair<signed, signed> >(Name)
600
72
      .Case("mktemp", std::make_pair(0,-1))
601
72
      .Case("mkstemp", std::make_pair(0,-1))
602
72
      .Case("mkdtemp", std::make_pair(0,-1))
603
72
      .Case("mkstemps", std::make_pair(0,1))
604
72
      .Default(std::make_pair(-1, -1));
605
72
606
72
  assert(ArgSuffix.first >= 0 && "Unsupported function");
607
72
608
72
  // Check if the number of arguments is consistent with out expectations.
609
72
  unsigned numArgs = CE->getNumArgs();
610
72
  if ((signed) numArgs <= ArgSuffix.first)
611
0
    return;
612
72
613
72
  const StringLiteral *strArg =
614
72
    dyn_cast<StringLiteral>(CE->getArg((unsigned)ArgSuffix.first)
615
72
                              ->IgnoreParenImpCasts());
616
72
617
72
  // Currently we only handle string literals.  It is possible to do better,
618
72
  // either by looking at references to const variables, or by doing real
619
72
  // flow analysis.
620
72
  if (!strArg || strArg->getCharByteWidth() != 1)
621
0
    return;
622
72
623
72
  // Count the number of X's, taking into account a possible cutoff suffix.
624
72
  StringRef str = strArg->getString();
625
72
  unsigned numX = 0;
626
72
  unsigned n = str.size();
627
72
628
72
  // Take into account the suffix.
629
72
  unsigned suffix = 0;
630
72
  if (ArgSuffix.second >= 0) {
631
24
    const Expr *suffixEx = CE->getArg((unsigned)ArgSuffix.second);
632
24
    Expr::EvalResult EVResult;
633
24
    if (!suffixEx->EvaluateAsInt(EVResult, BR.getContext()))
634
0
      return;
635
24
    llvm::APSInt Result = EVResult.Val.getInt();
636
24
    // FIXME: Issue a warning.
637
24
    if (Result.isNegative())
638
0
      return;
639
24
    suffix = (unsigned) Result.getZExtValue();
640
24
    n = (n > suffix) ? n - suffix : 
00
;
641
24
  }
642
72
643
384
  
for (unsigned i = 0; 72
i < n;
++i312
)
644
312
    if (str[i] == 'X') ++numX;
645
72
646
72
  if (numX >= 6)
647
32
    return;
648
40
649
40
  // Issue a warning.
650
40
  PathDiagnosticLocation CELoc =
651
40
    PathDiagnosticLocation::createBegin(CE, BR.getSourceManager(), AC);
652
40
  SmallString<512> buf;
653
40
  llvm::raw_svector_ostream out(buf);
654
40
  out << "Call to '" << Name << "' should have at least 6 'X's in the"
655
40
    " format string to be secure (" << numX << " 'X'";
656
40
  if (numX != 1)
657
32
    out << 's';
658
40
  out << " seen";
659
40
  if (suffix) {
660
16
    out << ", " << suffix << " character";
661
16
    if (suffix > 1)
662
8
      out << 's';
663
16
    out << " used as a suffix";
664
16
  }
665
40
  out << ')';
666
40
  BR.EmitBasicReport(AC->getDecl(), filter.checkName_mkstemp,
667
40
                     "Insecure temporary file creation", "Security",
668
40
                     out.str(), CELoc, strArg->getSourceRange());
669
40
}
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
32
void WalkAST::checkCall_strcpy(const CallExpr *CE, const FunctionDecl *FD) {
679
32
  if (!filter.check_strcpy)
680
0
    return;
681
32
682
32
  if (!checkCall_strCommon(CE, FD))
683
0
    return;
684
32
685
32
  const auto *Target = CE->getArg(0)->IgnoreImpCasts(),
686
32
             *Source = CE->getArg(1)->IgnoreImpCasts();
687
32
688
32
  if (const auto *Array = dyn_cast<ConstantArrayType>(Target->getType())) {
689
32
    uint64_t ArraySize = BR.getContext().getTypeSize(Array) / 8;
690
32
    if (const auto *String = dyn_cast<StringLiteral>(Source)) {
691
24
      if (ArraySize >= String->getLength() + 1)
692
16
        return;
693
16
    }
694
32
  }
695
16
696
16
  // Issue a warning.
697
16
  PathDiagnosticLocation CELoc =
698
16
    PathDiagnosticLocation::createBegin(CE, BR.getSourceManager(), AC);
699
16
  BR.EmitBasicReport(AC->getDecl(), filter.checkName_strcpy,
700
16
                     "Potential insecure memory buffer bounds restriction in "
701
16
                     "call 'strcpy'",
702
16
                     "Security",
703
16
                     "Call to function 'strcpy' is insecure as it does not "
704
16
                     "provide bounding of the memory buffer. Replace "
705
16
                     "unbounded copy functions with analogous functions that "
706
16
                     "support length arguments such as 'strlcpy'. CWE-119.",
707
16
                     CELoc, CE->getCallee()->getSourceRange());
708
16
}
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
8
void WalkAST::checkCall_strcat(const CallExpr *CE, const FunctionDecl *FD) {
718
8
  if (!filter.check_strcpy)
719
0
    return;
720
8
721
8
  if (!checkCall_strCommon(CE, FD))
722
0
    return;
723
8
724
8
  // Issue a warning.
725
8
  PathDiagnosticLocation CELoc =
726
8
    PathDiagnosticLocation::createBegin(CE, BR.getSourceManager(), AC);
727
8
  BR.EmitBasicReport(AC->getDecl(), filter.checkName_strcpy,
728
8
                     "Potential insecure memory buffer bounds restriction in "
729
8
                     "call 'strcat'",
730
8
                     "Security",
731
8
                     "Call to function 'strcat' is insecure as it does not "
732
8
                     "provide bounding of the memory buffer. Replace "
733
8
                     "unbounded copy functions with analogous functions that "
734
8
                     "support length arguments such as 'strlcat'. CWE-119.",
735
8
                     CELoc, CE->getCallee()->getSourceRange());
736
8
}
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
241
                                                    const FunctionDecl *FD) {
756
241
  if (!filter.check_DeprecatedOrUnsafeBufferHandling)
757
0
    return;
758
241
759
241
  if (!BR.getContext().getLangOpts().C11)
760
3
    return;
761
238
762
238
  // Issue a warning. ArgIndex == -1: Deprecated but not unsafe (has size
763
238
  // restrictions).
764
238
  enum { DEPR_ONLY = -1, UNKNOWN_CALL = -2 };
765
238
766
238
  StringRef Name = FD->getIdentifier()->getName();
767
238
  if (Name.startswith("__builtin_"))
768
6
    Name = Name.substr(10);
769
238
770
238
  int ArgIndex =
771
238
      llvm::StringSwitch<int>(Name)
772
238
          .Cases("scanf", "wscanf", "vscanf", "vwscanf", 0)
773
238
          .Cases("sprintf", "vsprintf", "fscanf", "fwscanf", "vfscanf",
774
238
                 "vfwscanf", "sscanf", "swscanf", "vsscanf", "vswscanf", 1)
775
238
          .Cases("swprintf", "snprintf", "vswprintf", "vsnprintf", "memcpy",
776
238
                 "memmove", "memset", "strncpy", "strncat", DEPR_ONLY)
777
238
          .Default(UNKNOWN_CALL);
778
238
779
238
  assert(ArgIndex != UNKNOWN_CALL && "Unsupported function");
780
238
  bool BoundsProvided = ArgIndex == DEPR_ONLY;
781
238
782
238
  if (!BoundsProvided) {
783
160
    // Currently we only handle (not wide) string literals. It is possible to do
784
160
    // better, either by looking at references to const variables, or by doing
785
160
    // real flow analysis.
786
160
    auto FormatString =
787
160
        dyn_cast<StringLiteral>(CE->getArg(ArgIndex)->IgnoreParenImpCasts());
788
160
    if (FormatString &&
789
160
        
FormatString->getString().find("%s") == StringRef::npos80
&&
790
160
        
FormatString->getString().find("%[") == StringRef::npos56
)
791
56
      BoundsProvided = true;
792
160
  }
793
238
794
238
  SmallString<128> Buf1;
795
238
  SmallString<512> Buf2;
796
238
  llvm::raw_svector_ostream Out1(Buf1);
797
238
  llvm::raw_svector_ostream Out2(Buf2);
798
238
799
238
  Out1 << "Potential insecure memory buffer bounds restriction in call '"
800
238
       << Name << "'";
801
238
  Out2 << "Call to function '" << Name
802
238
       << "' is insecure as it does not provide ";
803
238
804
238
  if (!BoundsProvided) {
805
104
    Out2 << "bounding of the memory buffer or ";
806
104
  }
807
238
808
238
  Out2 << "security checks introduced "
809
238
          "in the C11 standard. Replace with analogous functions that "
810
238
          "support length arguments or provides boundary checks such as '"
811
238
       << Name << "_s' in case of C11";
812
238
813
238
  PathDiagnosticLocation CELoc =
814
238
      PathDiagnosticLocation::createBegin(CE, BR.getSourceManager(), AC);
815
238
  BR.EmitBasicReport(AC->getDecl(),
816
238
                     filter.checkName_DeprecatedOrUnsafeBufferHandling,
817
238
                     Out1.str(), "Security", Out2.str(), CELoc,
818
238
                     CE->getCallee()->getSourceRange());
819
238
}
820
821
//===----------------------------------------------------------------------===//
822
// Common check for str* functions with no bounds parameters.
823
//===----------------------------------------------------------------------===//
824
825
40
bool WalkAST::checkCall_strCommon(const CallExpr *CE, const FunctionDecl *FD) {
826
40
  const FunctionProtoType *FPT = FD->getType()->getAs<FunctionProtoType>();
827
40
  if (!FPT)
828
0
    return false;
829
40
830
40
  // Verify the function takes two arguments, three in the _chk version.
831
40
  int numArgs = FPT->getNumParams();
832
40
  if (numArgs != 2 && 
numArgs != 320
)
833
0
    return false;
834
40
835
40
  // Verify the type for both arguments.
836
120
  
for (int i = 0; 40
i < 2;
i++80
) {
837
80
    // Verify that the arguments are pointers.
838
80
    const PointerType *PT = FPT->getParamType(i)->getAs<PointerType>();
839
80
    if (!PT)
840
0
      return false;
841
80
842
80
    // Verify that the argument is a 'char*'.
843
80
    if (PT->getPointeeType().getUnqualifiedType() != BR.getContext().CharTy)
844
0
      return false;
845
80
  }
846
40
847
40
  return true;
848
40
}
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
81
void WalkAST::checkCall_rand(const CallExpr *CE, const FunctionDecl *FD) {
857
81
  if (!filter.check_rand || !CheckRand)
858
9
    return;
859
72
860
72
  const FunctionProtoType *FTP = FD->getType()->getAs<FunctionProtoType>();
861
72
  if (!FTP)
862
0
    return;
863
72
864
72
  if (FTP->getNumParams() == 1) {
865
40
    // Is the argument an 'unsigned short *'?
866
40
    // (Actually any integer type is allowed.)
867
40
    const PointerType *PT = FTP->getParamType(0)->getAs<PointerType>();
868
40
    if (!PT)
869
0
      return;
870
40
871
40
    if (! PT->getPointeeType()->isIntegralOrUnscopedEnumerationType())
872
0
      return;
873
32
  } else if (FTP->getNumParams() != 0)
874
0
    return;
875
72
876
72
  // Issue a warning.
877
72
  SmallString<256> buf1;
878
72
  llvm::raw_svector_ostream os1(buf1);
879
72
  os1 << '\'' << *FD << "' is a poor random number generator";
880
72
881
72
  SmallString<256> buf2;
882
72
  llvm::raw_svector_ostream os2(buf2);
883
72
  os2 << "Function '" << *FD
884
72
      << "' is obsolete because it implements a poor random number generator."
885
72
      << "  Use 'arc4random' instead";
886
72
887
72
  PathDiagnosticLocation CELoc =
888
72
    PathDiagnosticLocation::createBegin(CE, BR.getSourceManager(), AC);
889
72
  BR.EmitBasicReport(AC->getDecl(), filter.checkName_rand, os1.str(),
890
72
                     "Security", os2.str(), CELoc,
891
72
                     CE->getCallee()->getSourceRange());
892
72
}
893
894
//===----------------------------------------------------------------------===//
895
// Check: 'random' should not be used
896
// Originally: <rdar://problem/63371000>
897
//===----------------------------------------------------------------------===//
898
899
9
void WalkAST::checkCall_random(const CallExpr *CE, const FunctionDecl *FD) {
900
9
  if (!CheckRand || 
!filter.check_rand8
)
901
1
    return;
902
8
903
8
  const FunctionProtoType *FTP = FD->getType()->getAs<FunctionProtoType>();
904
8
  if (!FTP)
905
0
    return;
906
8
907
8
  // Verify that the function takes no argument.
908
8
  if (FTP->getNumParams() != 0)
909
0
    return;
910
8
911
8
  // Issue a warning.
912
8
  PathDiagnosticLocation CELoc =
913
8
    PathDiagnosticLocation::createBegin(CE, BR.getSourceManager(), AC);
914
8
  BR.EmitBasicReport(AC->getDecl(), filter.checkName_rand,
915
8
                     "'random' is not a secure random number generator",
916
8
                     "Security",
917
8
                     "The 'random' function produces a sequence of values that "
918
8
                     "an adversary may be able to predict.  Use 'arc4random' "
919
8
                     "instead", CELoc, CE->getCallee()->getSourceRange());
920
8
}
921
922
//===----------------------------------------------------------------------===//
923
// Check: 'vfork' should not be used.
924
// POS33-C: Do not use vfork().
925
//===----------------------------------------------------------------------===//
926
927
22
void WalkAST::checkCall_vfork(const CallExpr *CE, const FunctionDecl *FD) {
928
22
  if (!filter.check_vfork)
929
0
    return;
930
22
931
22
  // All calls to vfork() are insecure, issue a warning.
932
22
  PathDiagnosticLocation CELoc =
933
22
    PathDiagnosticLocation::createBegin(CE, BR.getSourceManager(), AC);
934
22
  BR.EmitBasicReport(AC->getDecl(), filter.checkName_vfork,
935
22
                     "Potential insecure implementation-specific behavior in "
936
22
                     "call 'vfork'",
937
22
                     "Security",
938
22
                     "Call to function 'vfork' is insecure as it can lead to "
939
22
                     "denial of service situations in the parent process. "
940
22
                     "Replace calls to vfork with calls to the safer "
941
22
                     "'posix_spawn' function",
942
22
                     CELoc, CE->getCallee()->getSourceRange());
943
22
}
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
8
void WalkAST::checkMsg_decodeValueOfObjCType(const ObjCMessageExpr *ME) {
952
8
  if (!filter.check_decodeValueOfObjCType)
953
0
    return;
954
8
955
8
  // Check availability of the secure alternative:
956
8
  // iOS 11+, macOS 10.13+, tvOS 11+, and watchOS 4.0+
957
8
  // FIXME: We probably shouldn't register the check if it's not available.
958
8
  const TargetInfo &TI = AC->getASTContext().getTargetInfo();
959
8
  const llvm::Triple &T = TI.getTriple();
960
8
  const VersionTuple &VT = TI.getPlatformMinVersion();
961
8
  switch (T.getOS()) {
962
2
  case llvm::Triple::IOS:
963
2
    if (VT < VersionTuple(11, 0))
964
1
      return;
965
1
    break;
966
2
  case llvm::Triple::MacOSX:
967
2
    if (VT < VersionTuple(10, 13))
968
1
      return;
969
1
    break;
970
2
  case llvm::Triple::WatchOS:
971
2
    if (VT < VersionTuple(4, 0))
972
1
      return;
973
1
    break;
974
2
  case llvm::Triple::TvOS:
975
2
    if (VT < VersionTuple(11, 0))
976
1
      return;
977
1
    break;
978
1
  default:
979
0
    return;
980
4
  }
981
4
982
4
  PathDiagnosticLocation MELoc =
983
4
      PathDiagnosticLocation::createBegin(ME, BR.getSourceManager(), AC);
984
4
  BR.EmitBasicReport(
985
4
      AC->getDecl(), filter.checkName_decodeValueOfObjCType,
986
4
      "Potential buffer overflow in '-decodeValueOfObjCType:at:'", "Security",
987
4
      "Deprecated method '-decodeValueOfObjCType:at:' is insecure "
988
4
      "as it can lead to potential buffer overflows. Use the safer "
989
4
      "'-decodeValueOfObjCType:at:size:' method.",
990
4
      MELoc, ME->getSourceRange());
991
4
}
992
993
//===----------------------------------------------------------------------===//
994
// Check: Should check whether privileges are dropped successfully.
995
// Originally: <rdar://problem/6337132>
996
//===----------------------------------------------------------------------===//
997
998
553
void WalkAST::checkUncheckedReturnValue(CallExpr *CE) {
999
553
  if (!filter.check_UncheckedReturn)
1000
14
    return;
1001
539
1002
539
  const FunctionDecl *FD = CE->getDirectCallee();
1003
539
  if (!FD)
1004
0
    return;
1005
539
1006
539
  if (II_setid[0] == nullptr) {
1007
132
    static const char * const identifiers[num_setids] = {
1008
132
      "setuid", "setgid", "seteuid", "setegid",
1009
132
      "setreuid", "setregid"
1010
132
    };
1011
132
1012
924
    for (size_t i = 0; i < num_setids; 
i++792
)
1013
792
      II_setid[i] = &BR.getContext().Idents.get(identifiers[i]);
1014
132
  }
1015
539
1016
539
  const IdentifierInfo *id = FD->getIdentifier();
1017
539
  size_t identifierid;
1018
539
1019
3.65k
  for (identifierid = 0; identifierid < num_setids; 
identifierid++3.11k
)
1020
3.14k
    if (id == II_setid[identifierid])
1021
32
      break;
1022
539
1023
539
  if (identifierid >= num_setids)
1024
507
    return;
1025
32
1026
32
  const FunctionProtoType *FTP = FD->getType()->getAs<FunctionProtoType>();
1027
32
  if (!FTP)
1028
0
    return;
1029
32
1030
32
  // Verify that the function takes one or two arguments (depending on
1031
32
  //   the function).
1032
32
  if (FTP->getNumParams() != (identifierid < 4 ? 
116
:
216
))
1033
0
    return;
1034
32
1035
32
  // The arguments must be integers.
1036
80
  
for (unsigned i = 0; 32
i < FTP->getNumParams();
i++48
)
1037
48
    if (!FTP->getParamType(i)->isIntegralOrUnscopedEnumerationType())
1038
0
      return;
1039
32
1040
32
  // Issue a warning.
1041
32
  SmallString<256> buf1;
1042
32
  llvm::raw_svector_ostream os1(buf1);
1043
32
  os1 << "Return value is not checked in call to '" << *FD << '\'';
1044
32
1045
32
  SmallString<256> buf2;
1046
32
  llvm::raw_svector_ostream os2(buf2);
1047
32
  os2 << "The return value from the call to '" << *FD
1048
32
      << "' is not checked.  If an error occurs in '" << *FD
1049
32
      << "', the following code may execute with unexpected privileges";
1050
32
1051
32
  PathDiagnosticLocation CELoc =
1052
32
    PathDiagnosticLocation::createBegin(CE, BR.getSourceManager(), AC);
1053
32
  BR.EmitBasicReport(AC->getDecl(), filter.checkName_UncheckedReturn, os1.str(),
1054
32
                     "Security", os2.str(), CELoc,
1055
32
                     CE->getCallee()->getSourceRange());
1056
32
}
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
194
                        BugReporter &BR) const {
1069
194
    WalkAST walker(BR, mgr.getAnalysisDeclContext(D), filter);
1070
194
    walker.Visit(D->getBody());
1071
194
  }
1072
};
1073
}
1074
1075
39
void ento::registerSecuritySyntaxChecker(CheckerManager &mgr) {
1076
39
  mgr.registerChecker<SecuritySyntaxChecker>();
1077
39
}
1078
1079
12
bool ento::shouldRegisterSecuritySyntaxChecker(const LangOptions &LO) {
1080
12
  return true;
1081
12
}
1082
1083
#define REGISTER_CHECKER(name)                                                 \
1084
294
  void ento::register##name(CheckerManager &mgr) {                             \
1085
294
    SecuritySyntaxChecker *checker = mgr.getChecker<SecuritySyntaxChecker>();  \
1086
294
    checker->filter.check_##name = true;                                       \
1087
294
    checker->filter.checkName_##name = mgr.getCurrentCheckerName();            \
1088
294
  }                                                                            \
clang::ento::registerbcmp(clang::ento::CheckerManager&)
Line
Count
Source
1084
12
  void ento::register##name(CheckerManager &mgr) {                             \
1085
12
    SecuritySyntaxChecker *checker = mgr.getChecker<SecuritySyntaxChecker>();  \
1086
12
    checker->filter.check_##name = true;                                       \
1087
12
    checker->filter.checkName_##name = mgr.getCurrentCheckerName();            \
1088
12
  }                                                                            \
clang::ento::registerbcopy(clang::ento::CheckerManager&)
Line
Count
Source
1084
12
  void ento::register##name(CheckerManager &mgr) {                             \
1085
12
    SecuritySyntaxChecker *checker = mgr.getChecker<SecuritySyntaxChecker>();  \
1086
12
    checker->filter.check_##name = true;                                       \
1087
12
    checker->filter.checkName_##name = mgr.getCurrentCheckerName();            \
1088
12
  }                                                                            \
clang::ento::registerbzero(clang::ento::CheckerManager&)
Line
Count
Source
1084
12
  void ento::register##name(CheckerManager &mgr) {                             \
1085
12
    SecuritySyntaxChecker *checker = mgr.getChecker<SecuritySyntaxChecker>();  \
1086
12
    checker->filter.check_##name = true;                                       \
1087
12
    checker->filter.checkName_##name = mgr.getCurrentCheckerName();            \
1088
12
  }                                                                            \
clang::ento::registergets(clang::ento::CheckerManager&)
Line
Count
Source
1084
29
  void ento::register##name(CheckerManager &mgr) {                             \
1085
29
    SecuritySyntaxChecker *checker = mgr.getChecker<SecuritySyntaxChecker>();  \
1086
29
    checker->filter.check_##name = true;                                       \
1087
29
    checker->filter.checkName_##name = mgr.getCurrentCheckerName();            \
1088
29
  }                                                                            \
clang::ento::registergetpw(clang::ento::CheckerManager&)
Line
Count
Source
1084
29
  void ento::register##name(CheckerManager &mgr) {                             \
1085
29
    SecuritySyntaxChecker *checker = mgr.getChecker<SecuritySyntaxChecker>();  \
1086
29
    checker->filter.check_##name = true;                                       \
1087
29
    checker->filter.checkName_##name = mgr.getCurrentCheckerName();            \
1088
29
  }                                                                            \
clang::ento::registermkstemp(clang::ento::CheckerManager&)
Line
Count
Source
1084
29
  void ento::register##name(CheckerManager &mgr) {                             \
1085
29
    SecuritySyntaxChecker *checker = mgr.getChecker<SecuritySyntaxChecker>();  \
1086
29
    checker->filter.check_##name = true;                                       \
1087
29
    checker->filter.checkName_##name = mgr.getCurrentCheckerName();            \
1088
29
  }                                                                            \
clang::ento::registermktemp(clang::ento::CheckerManager&)
Line
Count
Source
1084
29
  void ento::register##name(CheckerManager &mgr) {                             \
1085
29
    SecuritySyntaxChecker *checker = mgr.getChecker<SecuritySyntaxChecker>();  \
1086
29
    checker->filter.check_##name = true;                                       \
1087
29
    checker->filter.checkName_##name = mgr.getCurrentCheckerName();            \
1088
29
  }                                                                            \
clang::ento::registerstrcpy(clang::ento::CheckerManager&)
Line
Count
Source
1084
12
  void ento::register##name(CheckerManager &mgr) {                             \
1085
12
    SecuritySyntaxChecker *checker = mgr.getChecker<SecuritySyntaxChecker>();  \
1086
12
    checker->filter.check_##name = true;                                       \
1087
12
    checker->filter.checkName_##name = mgr.getCurrentCheckerName();            \
1088
12
  }                                                                            \
clang::ento::registerrand(clang::ento::CheckerManager&)
Line
Count
Source
1084
12
  void ento::register##name(CheckerManager &mgr) {                             \
1085
12
    SecuritySyntaxChecker *checker = mgr.getChecker<SecuritySyntaxChecker>();  \
1086
12
    checker->filter.check_##name = true;                                       \
1087
12
    checker->filter.checkName_##name = mgr.getCurrentCheckerName();            \
1088
12
  }                                                                            \
clang::ento::registervfork(clang::ento::CheckerManager&)
Line
Count
Source
1084
31
  void ento::register##name(CheckerManager &mgr) {                             \
1085
31
    SecuritySyntaxChecker *checker = mgr.getChecker<SecuritySyntaxChecker>();  \
1086
31
    checker->filter.check_##name = true;                                       \
1087
31
    checker->filter.checkName_##name = mgr.getCurrentCheckerName();            \
1088
31
  }                                                                            \
clang::ento::registerFloatLoopCounter(clang::ento::CheckerManager&)
Line
Count
Source
1084
9
  void ento::register##name(CheckerManager &mgr) {                             \
1085
9
    SecuritySyntaxChecker *checker = mgr.getChecker<SecuritySyntaxChecker>();  \
1086
9
    checker->filter.check_##name = true;                                       \
1087
9
    checker->filter.checkName_##name = mgr.getCurrentCheckerName();            \
1088
9
  }                                                                            \
clang::ento::registerUncheckedReturn(clang::ento::CheckerManager&)
Line
Count
Source
1084
29
  void ento::register##name(CheckerManager &mgr) {                             \
1085
29
    SecuritySyntaxChecker *checker = mgr.getChecker<SecuritySyntaxChecker>();  \
1086
29
    checker->filter.check_##name = true;                                       \
1087
29
    checker->filter.checkName_##name = mgr.getCurrentCheckerName();            \
1088
29
  }                                                                            \
clang::ento::registerDeprecatedOrUnsafeBufferHandling(clang::ento::CheckerManager&)
Line
Count
Source
1084
12
  void ento::register##name(CheckerManager &mgr) {                             \
1085
12
    SecuritySyntaxChecker *checker = mgr.getChecker<SecuritySyntaxChecker>();  \
1086
12
    checker->filter.check_##name = true;                                       \
1087
12
    checker->filter.checkName_##name = mgr.getCurrentCheckerName();            \
1088
12
  }                                                                            \
clang::ento::registerdecodeValueOfObjCType(clang::ento::CheckerManager&)
Line
Count
Source
1084
37
  void ento::register##name(CheckerManager &mgr) {                             \
1085
37
    SecuritySyntaxChecker *checker = mgr.getChecker<SecuritySyntaxChecker>();  \
1086
37
    checker->filter.check_##name = true;                                       \
1087
37
    checker->filter.checkName_##name = mgr.getCurrentCheckerName();            \
1088
37
  }                                                                            \
1089
                                                                               \
1090
300
  bool ento::shouldRegister##name(const LangOptions &LO) { return true; }
clang::ento::shouldRegisterbcmp(clang::LangOptions const&)
Line
Count
Source
1090
12
  bool ento::shouldRegister##name(const LangOptions &LO) { return true; }
clang::ento::shouldRegisterbcopy(clang::LangOptions const&)
Line
Count
Source
1090
12
  bool ento::shouldRegister##name(const LangOptions &LO) { return true; }
clang::ento::shouldRegisterbzero(clang::LangOptions const&)
Line
Count
Source
1090
12
  bool ento::shouldRegister##name(const LangOptions &LO) { return true; }
clang::ento::shouldRegistergets(clang::LangOptions const&)
Line
Count
Source
1090
30
  bool ento::shouldRegister##name(const LangOptions &LO) { return true; }
clang::ento::shouldRegistergetpw(clang::LangOptions const&)
Line
Count
Source
1090
30
  bool ento::shouldRegister##name(const LangOptions &LO) { return true; }
clang::ento::shouldRegistermkstemp(clang::LangOptions const&)
Line
Count
Source
1090
30
  bool ento::shouldRegister##name(const LangOptions &LO) { return true; }
clang::ento::shouldRegistermktemp(clang::LangOptions const&)
Line
Count
Source
1090
30
  bool ento::shouldRegister##name(const LangOptions &LO) { return true; }
clang::ento::shouldRegisterstrcpy(clang::LangOptions const&)
Line
Count
Source
1090
12
  bool ento::shouldRegister##name(const LangOptions &LO) { return true; }
clang::ento::shouldRegisterrand(clang::LangOptions const&)
Line
Count
Source
1090
12
  bool ento::shouldRegister##name(const LangOptions &LO) { return true; }
clang::ento::shouldRegistervfork(clang::LangOptions const&)
Line
Count
Source
1090
32
  bool ento::shouldRegister##name(const LangOptions &LO) { return true; }
clang::ento::shouldRegisterFloatLoopCounter(clang::LangOptions const&)
Line
Count
Source
1090
9
  bool ento::shouldRegister##name(const LangOptions &LO) { return true; }
clang::ento::shouldRegisterUncheckedReturn(clang::LangOptions const&)
Line
Count
Source
1090
30
  bool ento::shouldRegister##name(const LangOptions &LO) { return true; }
clang::ento::shouldRegisterDeprecatedOrUnsafeBufferHandling(clang::LangOptions const&)
Line
Count
Source
1090
12
  bool ento::shouldRegister##name(const LangOptions &LO) { return true; }
clang::ento::shouldRegisterdecodeValueOfObjCType(clang::LangOptions const&)
Line
Count
Source
1090
37
  bool ento::shouldRegister##name(const LangOptions &LO) { 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)