Coverage Report

Created: 2020-02-25 14:32

/Users/buildslave/jenkins/workspace/coverage/llvm-project/clang/lib/StaticAnalyzer/Checkers/GenericTaintChecker.cpp
Line
Count
Source (jump to first uncovered line)
1
//== GenericTaintChecker.cpp ----------------------------------- -*- 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 checker defines the attack surface for generic taint propagation.
10
//
11
// The taint information produced by it might be useful to other checkers. For
12
// example, checkers should report errors which involve tainted data more
13
// aggressively, even if the involved symbols are under constrained.
14
//
15
//===----------------------------------------------------------------------===//
16
17
#include "Taint.h"
18
#include "Yaml.h"
19
#include "clang/AST/Attr.h"
20
#include "clang/Basic/Builtins.h"
21
#include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h"
22
#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
23
#include "clang/StaticAnalyzer/Core/Checker.h"
24
#include "clang/StaticAnalyzer/Core/CheckerManager.h"
25
#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
26
#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h"
27
#include "llvm/Support/YAMLTraits.h"
28
#include <algorithm>
29
#include <limits>
30
#include <unordered_map>
31
#include <utility>
32
33
using namespace clang;
34
using namespace ento;
35
using namespace taint;
36
37
namespace {
38
class GenericTaintChecker
39
    : public Checker<check::PostStmt<CallExpr>, check::PreStmt<CallExpr>> {
40
public:
41
0
  static void *getTag() {
42
0
    static int Tag;
43
0
    return &Tag;
44
0
  }
45
46
  void checkPostStmt(const CallExpr *CE, CheckerContext &C) const;
47
48
  void checkPreStmt(const CallExpr *CE, CheckerContext &C) const;
49
50
  void printState(raw_ostream &Out, ProgramStateRef State, const char *NL,
51
                  const char *Sep) const override;
52
53
  using ArgVector = SmallVector<unsigned, 2>;
54
  using SignedArgVector = SmallVector<int, 2>;
55
56
  enum class VariadicType { None, Src, Dst };
57
58
  /// Used to parse the configuration file.
59
  struct TaintConfiguration {
60
    using NameScopeArgs = std::tuple<std::string, std::string, ArgVector>;
61
62
    struct Propagation {
63
      std::string Name;
64
      std::string Scope;
65
      ArgVector SrcArgs;
66
      SignedArgVector DstArgs;
67
      VariadicType VarType;
68
      unsigned VarIndex;
69
    };
70
71
    std::vector<Propagation> Propagations;
72
    std::vector<NameScopeArgs> Filters;
73
    std::vector<NameScopeArgs> Sinks;
74
75
5
    TaintConfiguration() = default;
76
    TaintConfiguration(const TaintConfiguration &) = default;
77
4
    TaintConfiguration(TaintConfiguration &&) = default;
78
    TaintConfiguration &operator=(const TaintConfiguration &) = default;
79
    TaintConfiguration &operator=(TaintConfiguration &&) = default;
80
  };
81
82
  /// Convert SignedArgVector to ArgVector.
83
  ArgVector convertToArgVector(CheckerManager &Mgr, const std::string &Option,
84
                               SignedArgVector Args);
85
86
  /// Parse the config.
87
  void parseConfiguration(CheckerManager &Mgr, const std::string &Option,
88
                          TaintConfiguration &&Config);
89
90
  static const unsigned InvalidArgIndex{std::numeric_limits<unsigned>::max()};
91
  /// Denotes the return vale.
92
  static const unsigned ReturnValueIndex{std::numeric_limits<unsigned>::max() -
93
                                         1};
94
95
private:
96
  mutable std::unique_ptr<BugType> BT;
97
54
  void initBugType() const {
98
54
    if (!BT)
99
4
      BT.reset(new BugType(this, "Use of Untrusted Data", "Untrusted Data"));
100
54
  }
101
102
  struct FunctionData {
103
    FunctionData() = delete;
104
    FunctionData(const FunctionData &) = default;
105
853
    FunctionData(FunctionData &&) = default;
106
    FunctionData &operator=(const FunctionData &) = delete;
107
    FunctionData &operator=(FunctionData &&) = delete;
108
109
    static Optional<FunctionData> create(const CallExpr *CE,
110
854
                                         const CheckerContext &C) {
111
854
      const FunctionDecl *FDecl = C.getCalleeDecl(CE);
112
854
      if (!FDecl || 
(853
FDecl->getKind() != Decl::Function853
&&
113
853
                     
FDecl->getKind() != Decl::CXXMethod12
))
114
1
        return None;
115
853
116
853
      StringRef Name = C.getCalleeName(FDecl);
117
853
      std::string FullName = FDecl->getQualifiedNameAsString();
118
853
      if (Name.empty() || FullName.empty())
119
0
        return None;
120
853
121
853
      return FunctionData{FDecl, Name, FullName};
122
853
    }
123
124
16
    bool isInScope(StringRef Scope) const {
125
16
      return StringRef(FullName).startswith(Scope);
126
16
    }
127
128
    const FunctionDecl *const FDecl;
129
    const StringRef Name;
130
    const std::string FullName;
131
  };
132
133
  /// Catch taint related bugs. Check if tainted data is passed to a
134
  /// system call etc. Returns true on matching.
135
  bool checkPre(const CallExpr *CE, const FunctionData &FData,
136
                CheckerContext &C) const;
137
138
  /// Add taint sources on a pre-visit. Returns true on matching.
139
  bool addSourcesPre(const CallExpr *CE, const FunctionData &FData,
140
                     CheckerContext &C) const;
141
142
  /// Mark filter's arguments not tainted on a pre-visit. Returns true on
143
  /// matching.
144
  bool addFiltersPre(const CallExpr *CE, const FunctionData &FData,
145
                     CheckerContext &C) const;
146
147
  /// Propagate taint generated at pre-visit. Returns true on matching.
148
  bool propagateFromPre(const CallExpr *CE, CheckerContext &C) const;
149
150
  /// Check if the region the expression evaluates to is the standard input,
151
  /// and thus, is tainted.
152
  static bool isStdin(const Expr *E, CheckerContext &C);
153
154
  /// Given a pointer argument, return the value it points to.
155
  static Optional<SVal> getPointedToSVal(CheckerContext &C, const Expr *Arg);
156
157
  /// Check for CWE-134: Uncontrolled Format String.
158
  static constexpr llvm::StringLiteral MsgUncontrolledFormatString =
159
      "Untrusted data is used as a format string "
160
      "(CWE-134: Uncontrolled Format String)";
161
  bool checkUncontrolledFormatString(const CallExpr *CE,
162
                                     CheckerContext &C) const;
163
164
  /// Check for:
165
  /// CERT/STR02-C. "Sanitize data passed to complex subsystems"
166
  /// CWE-78, "Failure to Sanitize Data into an OS Command"
167
  static constexpr llvm::StringLiteral MsgSanitizeSystemArgs =
168
      "Untrusted data is passed to a system call "
169
      "(CERT/STR02-C. Sanitize data passed to complex subsystems)";
170
  bool checkSystemCall(const CallExpr *CE, StringRef Name,
171
                       CheckerContext &C) const;
172
173
  /// Check if tainted data is used as a buffer size ins strn.. functions,
174
  /// and allocators.
175
  static constexpr llvm::StringLiteral MsgTaintedBufferSize =
176
      "Untrusted data is used to specify the buffer size "
177
      "(CERT/STR31-C. Guarantee that storage for strings has sufficient space "
178
      "for character data and the null terminator)";
179
  bool checkTaintedBufferSize(const CallExpr *CE, const FunctionDecl *FDecl,
180
                              CheckerContext &C) const;
181
182
  /// Check if tainted data is used as a custom sink's parameter.
183
  static constexpr llvm::StringLiteral MsgCustomSink =
184
      "Untrusted data is passed to a user-defined sink";
185
  bool checkCustomSinks(const CallExpr *CE, const FunctionData &FData,
186
                        CheckerContext &C) const;
187
188
  /// Generate a report if the expression is tainted or points to tainted data.
189
  bool generateReportIfTainted(const Expr *E, StringRef Msg,
190
                               CheckerContext &C) const;
191
192
  struct TaintPropagationRule;
193
  template <typename T>
194
  using ConfigDataMap =
195
      std::unordered_multimap<std::string, std::pair<std::string, T>>;
196
  using NameRuleMap = ConfigDataMap<TaintPropagationRule>;
197
  using NameArgMap = ConfigDataMap<ArgVector>;
198
199
  /// Find a function with the given name and scope. Returns the first match
200
  /// or the end of the map.
201
  template <typename T>
202
  static auto findFunctionInConfig(const ConfigDataMap<T> &Map,
203
                                   const FunctionData &FData);
204
205
  /// A struct used to specify taint propagation rules for a function.
206
  ///
207
  /// If any of the possible taint source arguments is tainted, all of the
208
  /// destination arguments should also be tainted. Use InvalidArgIndex in the
209
  /// src list to specify that all of the arguments can introduce taint. Use
210
  /// InvalidArgIndex in the dst arguments to signify that all the non-const
211
  /// pointer and reference arguments might be tainted on return. If
212
  /// ReturnValueIndex is added to the dst list, the return value will be
213
  /// tainted.
214
  struct TaintPropagationRule {
215
    using PropagationFuncType = bool (*)(bool IsTainted, const CallExpr *,
216
                                         CheckerContext &C);
217
218
    /// List of arguments which can be taint sources and should be checked.
219
    ArgVector SrcArgs;
220
    /// List of arguments which should be tainted on function return.
221
    ArgVector DstArgs;
222
    /// Index for the first variadic parameter if exist.
223
    unsigned VariadicIndex;
224
    /// Show when a function has variadic parameters. If it has, it marks all
225
    /// of them as source or destination.
226
    VariadicType VarType;
227
    /// Special function for tainted source determination. If defined, it can
228
    /// override the default behavior.
229
    PropagationFuncType PropagationFunc;
230
231
    TaintPropagationRule()
232
        : VariadicIndex(InvalidArgIndex), VarType(VariadicType::None),
233
1.37k
          PropagationFunc(nullptr) {}
234
235
    TaintPropagationRule(ArgVector &&Src, ArgVector &&Dst,
236
                         VariadicType Var = VariadicType::None,
237
                         unsigned VarIndex = InvalidArgIndex,
238
                         PropagationFuncType Func = nullptr)
239
        : SrcArgs(std::move(Src)), DstArgs(std::move(Dst)),
240
23.2k
          VariadicIndex(VarIndex), VarType(Var), PropagationFunc(Func) {}
241
242
    /// Get the propagation rule for a given function.
243
    static TaintPropagationRule
244
    getTaintPropagationRule(const NameRuleMap &CustomPropagations,
245
                            const FunctionData &FData, CheckerContext &C);
246
247
0
    void addSrcArg(unsigned A) { SrcArgs.push_back(A); }
248
0
    void addDstArg(unsigned A) { DstArgs.push_back(A); }
249
250
2.23k
    bool isNull() const {
251
2.23k
      return SrcArgs.empty() && 
DstArgs.empty()2.06k
&&
252
2.23k
             
VariadicType::None == VarType2.00k
;
253
2.23k
    }
254
255
0
    bool isDestinationArgument(unsigned ArgNum) const {
256
0
      return (llvm::find(DstArgs, ArgNum) != DstArgs.end());
257
0
    }
258
259
    static bool isTaintedOrPointsToTainted(const Expr *E, ProgramStateRef State,
260
171
                                           CheckerContext &C) {
261
171
      if (isTainted(State, E, C.getLocationContext()) || 
isStdin(E, C)150
)
262
40
        return true;
263
131
264
131
      if (!E->getType().getTypePtr()->isPointerType())
265
45
        return false;
266
86
267
86
      Optional<SVal> V = getPointedToSVal(C, E);
268
86
      return (V && isTainted(State, *V));
269
86
    }
270
271
    /// Pre-process a function which propagates taint according to the
272
    /// taint rule.
273
    ProgramStateRef process(const CallExpr *CE, CheckerContext &C) const;
274
275
    // Functions for custom taintedness propagation.
276
    static bool postSocket(bool IsTainted, const CallExpr *CE,
277
                           CheckerContext &C);
278
  };
279
280
  /// Defines a map between the propagation function's name, scope
281
  /// and TaintPropagationRule.
282
  NameRuleMap CustomPropagations;
283
284
  /// Defines a map between the filter function's name, scope and filtering
285
  /// args.
286
  NameArgMap CustomFilters;
287
288
  /// Defines a map between the sink function's name, scope and sinking args.
289
  NameArgMap CustomSinks;
290
};
291
292
const unsigned GenericTaintChecker::ReturnValueIndex;
293
const unsigned GenericTaintChecker::InvalidArgIndex;
294
295
// FIXME: these lines can be removed in C++17
296
constexpr llvm::StringLiteral GenericTaintChecker::MsgUncontrolledFormatString;
297
constexpr llvm::StringLiteral GenericTaintChecker::MsgSanitizeSystemArgs;
298
constexpr llvm::StringLiteral GenericTaintChecker::MsgTaintedBufferSize;
299
constexpr llvm::StringLiteral GenericTaintChecker::MsgCustomSink;
300
} // end of anonymous namespace
301
302
using TaintConfig = GenericTaintChecker::TaintConfiguration;
303
304
LLVM_YAML_IS_SEQUENCE_VECTOR(TaintConfig::Propagation)
305
LLVM_YAML_IS_SEQUENCE_VECTOR(TaintConfig::NameScopeArgs)
306
307
namespace llvm {
308
namespace yaml {
309
template <> struct MappingTraits<TaintConfig> {
310
5
  static void mapping(IO &IO, TaintConfig &Config) {
311
5
    IO.mapOptional("Propagations", Config.Propagations);
312
5
    IO.mapOptional("Filters", Config.Filters);
313
5
    IO.mapOptional("Sinks", Config.Sinks);
314
5
  }
315
};
316
317
template <> struct MappingTraits<TaintConfig::Propagation> {
318
26
  static void mapping(IO &IO, TaintConfig::Propagation &Propagation) {
319
26
    IO.mapRequired("Name", Propagation.Name);
320
26
    IO.mapOptional("Scope", Propagation.Scope);
321
26
    IO.mapOptional("SrcArgs", Propagation.SrcArgs);
322
26
    IO.mapOptional("DstArgs", Propagation.DstArgs);
323
26
    IO.mapOptional("VariadicType", Propagation.VarType,
324
26
                   GenericTaintChecker::VariadicType::None);
325
26
    IO.mapOptional("VariadicIndex", Propagation.VarIndex,
326
26
                   GenericTaintChecker::InvalidArgIndex);
327
26
  }
328
};
329
330
template <> struct ScalarEnumerationTraits<GenericTaintChecker::VariadicType> {
331
9
  static void enumeration(IO &IO, GenericTaintChecker::VariadicType &Value) {
332
9
    IO.enumCase(Value, "None", GenericTaintChecker::VariadicType::None);
333
9
    IO.enumCase(Value, "Src", GenericTaintChecker::VariadicType::Src);
334
9
    IO.enumCase(Value, "Dst", GenericTaintChecker::VariadicType::Dst);
335
9
  }
336
};
337
338
template <> struct MappingTraits<TaintConfig::NameScopeArgs> {
339
18
  static void mapping(IO &IO, TaintConfig::NameScopeArgs &NSA) {
340
18
    IO.mapRequired("Name", std::get<0>(NSA));
341
18
    IO.mapOptional("Scope", std::get<1>(NSA));
342
18
    IO.mapRequired("Args", std::get<2>(NSA));
343
18
  }
344
};
345
} // namespace yaml
346
} // namespace llvm
347
348
/// A set which is used to pass information from call pre-visit instruction
349
/// to the call post-visit. The values are unsigned integers, which are either
350
/// ReturnValueIndex, or indexes of the pointer/reference argument, which
351
/// points to data, which should be tainted on return.
352
REGISTER_SET_WITH_PROGRAMSTATE(TaintArgsOnPostVisit, unsigned)
353
354
GenericTaintChecker::ArgVector GenericTaintChecker::convertToArgVector(
355
25
    CheckerManager &Mgr, const std::string &Option, SignedArgVector Args) {
356
25
  ArgVector Result;
357
25
  for (int Arg : Args) {
358
22
    if (Arg == -1)
359
12
      Result.push_back(ReturnValueIndex);
360
10
    else if (Arg < -1) {
361
1
      Result.push_back(InvalidArgIndex);
362
1
      Mgr.reportInvalidCheckerOptionValue(
363
1
          this, Option,
364
1
          "an argument number for propagation rules greater or equal to -1");
365
1
    } else
366
9
      Result.push_back(static_cast<unsigned>(Arg));
367
22
  }
368
25
  return Result;
369
25
}
370
371
void GenericTaintChecker::parseConfiguration(CheckerManager &Mgr,
372
                                             const std::string &Option,
373
4
                                             TaintConfiguration &&Config) {
374
25
  for (auto &P : Config.Propagations) {
375
25
    GenericTaintChecker::CustomPropagations.emplace(
376
25
        P.Name,
377
25
        std::make_pair(P.Scope, TaintPropagationRule{
378
25
                                    std::move(P.SrcArgs),
379
25
                                    convertToArgVector(Mgr, Option, P.DstArgs),
380
25
                                    P.VarType, P.VarIndex}));
381
25
  }
382
4
383
9
  for (auto &F : Config.Filters) {
384
9
    GenericTaintChecker::CustomFilters.emplace(
385
9
        std::get<0>(F),
386
9
        std::make_pair(std::move(std::get<1>(F)), std::move(std::get<2>(F))));
387
9
  }
388
4
389
9
  for (auto &S : Config.Sinks) {
390
9
    GenericTaintChecker::CustomSinks.emplace(
391
9
        std::get<0>(S),
392
9
        std::make_pair(std::move(std::get<1>(S)), std::move(std::get<2>(S))));
393
9
  }
394
4
}
395
396
template <typename T>
397
auto GenericTaintChecker::findFunctionInConfig(const ConfigDataMap<T> &Map,
398
1.98k
                                               const FunctionData &FData) {
399
1.98k
  auto Range = Map.equal_range(std::string(FData.Name));
400
1.98k
  auto It =
401
1.98k
      std::find_if(Range.first, Range.second, [&FData](const auto &Entry) {
402
49
        const auto &Value = Entry.second;
403
49
        StringRef Scope = Value.first;
404
49
        return Scope.empty() || 
FData.isInScope(Scope)16
;
405
49
      });
GenericTaintChecker.cpp:auto auto (anonymous namespace)::GenericTaintChecker::findFunctionInConfig<llvm::SmallVector<unsigned int, 2u> >(std::__1::unordered_multimap<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, std::__1::pair<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, llvm::SmallVector<unsigned int, 2u> >, std::__1::hash<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >, std::__1::equal_to<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >, std::__1::allocator<std::__1::pair<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const, std::__1::pair<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, llvm::SmallVector<unsigned int, 2u> > > > > const&, (anonymous namespace)::GenericTaintChecker::FunctionData const&)::'lambda'(llvm::SmallVector<unsigned int, 2u> const&)::operator()<std::__1::pair<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const, std::__1::pair<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, llvm::SmallVector<unsigned int, 2u> > > >(llvm::SmallVector<unsigned int, 2u> const&) const
Line
Count
Source
401
20
      std::find_if(Range.first, Range.second, [&FData](const auto &Entry) {
402
20
        const auto &Value = Entry.second;
403
20
        StringRef Scope = Value.first;
404
20
        return Scope.empty() || 
FData.isInScope(Scope)10
;
405
20
      });
GenericTaintChecker.cpp:auto auto (anonymous namespace)::GenericTaintChecker::findFunctionInConfig<(anonymous namespace)::GenericTaintChecker::TaintPropagationRule>(std::__1::unordered_multimap<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, std::__1::pair<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, (anonymous namespace)::GenericTaintChecker::TaintPropagationRule>, std::__1::hash<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >, std::__1::equal_to<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >, std::__1::allocator<std::__1::pair<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const, std::__1::pair<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, (anonymous namespace)::GenericTaintChecker::TaintPropagationRule> > > > const&, (anonymous namespace)::GenericTaintChecker::FunctionData const&)::'lambda'((anonymous namespace)::GenericTaintChecker::TaintPropagationRule const&)::operator()<std::__1::pair<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const, std::__1::pair<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, (anonymous namespace)::GenericTaintChecker::TaintPropagationRule> > >((anonymous namespace)::GenericTaintChecker::TaintPropagationRule const&) const
Line
Count
Source
401
29
      std::find_if(Range.first, Range.second, [&FData](const auto &Entry) {
402
29
        const auto &Value = Entry.second;
403
29
        StringRef Scope = Value.first;
404
29
        return Scope.empty() || 
FData.isInScope(Scope)6
;
405
29
      });
406
1.98k
  return It != Range.second ? 
It40
:
Map.end()1.94k
;
407
1.98k
}
GenericTaintChecker.cpp:auto (anonymous namespace)::GenericTaintChecker::findFunctionInConfig<llvm::SmallVector<unsigned int, 2u> >(std::__1::unordered_multimap<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, std::__1::pair<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, llvm::SmallVector<unsigned int, 2u> >, std::__1::hash<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >, std::__1::equal_to<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >, std::__1::allocator<std::__1::pair<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const, std::__1::pair<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, llvm::SmallVector<unsigned int, 2u> > > > > const&, (anonymous namespace)::GenericTaintChecker::FunctionData const&)
Line
Count
Source
398
1.38k
                                               const FunctionData &FData) {
399
1.38k
  auto Range = Map.equal_range(std::string(FData.Name));
400
1.38k
  auto It =
401
1.38k
      std::find_if(Range.first, Range.second, [&FData](const auto &Entry) {
402
1.38k
        const auto &Value = Entry.second;
403
1.38k
        StringRef Scope = Value.first;
404
1.38k
        return Scope.empty() || FData.isInScope(Scope);
405
1.38k
      });
406
1.38k
  return It != Range.second ? 
It14
:
Map.end()1.36k
;
407
1.38k
}
GenericTaintChecker.cpp:auto (anonymous namespace)::GenericTaintChecker::findFunctionInConfig<(anonymous namespace)::GenericTaintChecker::TaintPropagationRule>(std::__1::unordered_multimap<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, std::__1::pair<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, (anonymous namespace)::GenericTaintChecker::TaintPropagationRule>, std::__1::hash<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >, std::__1::equal_to<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >, std::__1::allocator<std::__1::pair<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const, std::__1::pair<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, (anonymous namespace)::GenericTaintChecker::TaintPropagationRule> > > > const&, (anonymous namespace)::GenericTaintChecker::FunctionData const&)
Line
Count
Source
398
600
                                               const FunctionData &FData) {
399
600
  auto Range = Map.equal_range(std::string(FData.Name));
400
600
  auto It =
401
600
      std::find_if(Range.first, Range.second, [&FData](const auto &Entry) {
402
600
        const auto &Value = Entry.second;
403
600
        StringRef Scope = Value.first;
404
600
        return Scope.empty() || FData.isInScope(Scope);
405
600
      });
406
600
  return It != Range.second ? 
It26
:
Map.end()574
;
407
600
}
408
409
GenericTaintChecker::TaintPropagationRule
410
GenericTaintChecker::TaintPropagationRule::getTaintPropagationRule(
411
    const NameRuleMap &CustomPropagations, const FunctionData &FData,
412
799
    CheckerContext &C) {
413
799
  // TODO: Currently, we might lose precision here: we always mark a return
414
799
  // value as tainted even if it's just a pointer, pointing to tainted data.
415
799
416
799
  // Check for exact name match for functions without builtin substitutes.
417
799
  // Use qualified name, because these are C functions without namespace.
418
799
  TaintPropagationRule Rule =
419
799
      llvm::StringSwitch<TaintPropagationRule>(FData.FullName)
420
799
          // Source functions
421
799
          // TODO: Add support for vfscanf & family.
422
799
          .Case("fdopen", TaintPropagationRule({}, {ReturnValueIndex}))
423
799
          .Case("fopen", TaintPropagationRule({}, {ReturnValueIndex}))
424
799
          .Case("freopen", TaintPropagationRule({}, {ReturnValueIndex}))
425
799
          .Case("getch", TaintPropagationRule({}, {ReturnValueIndex}))
426
799
          .Case("getchar", TaintPropagationRule({}, {ReturnValueIndex}))
427
799
          .Case("getchar_unlocked",
428
799
                TaintPropagationRule({}, {ReturnValueIndex}))
429
799
          .Case("getenv", TaintPropagationRule({}, {ReturnValueIndex}))
430
799
          .Case("gets", TaintPropagationRule({}, {0, ReturnValueIndex}))
431
799
          .Case("scanf", TaintPropagationRule({}, {}, VariadicType::Dst, 1))
432
799
          .Case("socket",
433
799
                TaintPropagationRule({}, {ReturnValueIndex}, VariadicType::None,
434
799
                                     InvalidArgIndex,
435
799
                                     &TaintPropagationRule::postSocket))
436
799
          .Case("wgetch", TaintPropagationRule({}, {ReturnValueIndex}))
437
799
          // Propagating functions
438
799
          .Case("atoi", TaintPropagationRule({0}, {ReturnValueIndex}))
439
799
          .Case("atol", TaintPropagationRule({0}, {ReturnValueIndex}))
440
799
          .Case("atoll", TaintPropagationRule({0}, {ReturnValueIndex}))
441
799
          .Case("fgetc", TaintPropagationRule({0}, {ReturnValueIndex}))
442
799
          .Case("fgetln", TaintPropagationRule({0}, {ReturnValueIndex}))
443
799
          .Case("fgets", TaintPropagationRule({2}, {0, ReturnValueIndex}))
444
799
          .Case("fscanf", TaintPropagationRule({0}, {}, VariadicType::Dst, 2))
445
799
          .Case("getc", TaintPropagationRule({0}, {ReturnValueIndex}))
446
799
          .Case("getc_unlocked", TaintPropagationRule({0}, {ReturnValueIndex}))
447
799
          .Case("getdelim", TaintPropagationRule({3}, {0}))
448
799
          .Case("getline", TaintPropagationRule({2}, {0}))
449
799
          .Case("getw", TaintPropagationRule({0}, {ReturnValueIndex}))
450
799
          .Case("pread",
451
799
                TaintPropagationRule({0, 1, 2, 3}, {1, ReturnValueIndex}))
452
799
          .Case("read", TaintPropagationRule({0, 2}, {1, ReturnValueIndex}))
453
799
          .Case("strchr", TaintPropagationRule({0}, {ReturnValueIndex}))
454
799
          .Case("strrchr", TaintPropagationRule({0}, {ReturnValueIndex}))
455
799
          .Case("tolower", TaintPropagationRule({0}, {ReturnValueIndex}))
456
799
          .Case("toupper", TaintPropagationRule({0}, {ReturnValueIndex}))
457
799
          .Default(TaintPropagationRule());
458
799
459
799
  if (!Rule.isNull())
460
113
    return Rule;
461
686
462
686
  // Check if it's one of the memory setting/copying functions.
463
686
  // This check is specialized but faster then calling isCLibraryFunction.
464
686
  const FunctionDecl *FDecl = FData.FDecl;
465
686
  unsigned BId = 0;
466
686
  if ((BId = FDecl->getMemoryFunctionKind()))
467
249
    switch (BId) {
468
45
    case Builtin::BImemcpy:
469
45
    case Builtin::BImemmove:
470
45
    case Builtin::BIstrncpy:
471
45
    case Builtin::BIstrncat:
472
45
      return TaintPropagationRule({1, 2}, {0, ReturnValueIndex});
473
45
    case Builtin::BIstrlcpy:
474
0
    case Builtin::BIstrlcat:
475
0
      return TaintPropagationRule({1, 2}, {0});
476
2
    case Builtin::BIstrndup:
477
2
      return TaintPropagationRule({0, 1}, {ReturnValueIndex});
478
0
479
202
    default:
480
202
      break;
481
639
    };
482
639
483
639
  // Process all other functions which could be defined as builtins.
484
639
  if (Rule.isNull()) {
485
639
    if (C.isCLibraryFunction(FDecl, "snprintf"))
486
5
      return TaintPropagationRule({1}, {0, ReturnValueIndex}, VariadicType::Src,
487
5
                                  3);
488
634
    else if (C.isCLibraryFunction(FDecl, "sprintf"))
489
2
      return TaintPropagationRule({}, {0, ReturnValueIndex}, VariadicType::Src,
490
2
                                  2);
491
632
    else if (C.isCLibraryFunction(FDecl, "strcpy") ||
492
632
             
C.isCLibraryFunction(FDecl, "stpcpy")622
||
493
632
             
C.isCLibraryFunction(FDecl, "strcat")613
)
494
31
      return TaintPropagationRule({1}, {0, ReturnValueIndex});
495
601
    else if (C.isCLibraryFunction(FDecl, "bcopy"))
496
0
      return TaintPropagationRule({0, 2}, {1});
497
601
    else if (C.isCLibraryFunction(FDecl, "strdup") ||
498
601
             
C.isCLibraryFunction(FDecl, "strdupa")600
)
499
1
      return TaintPropagationRule({0}, {ReturnValueIndex});
500
600
    else if (C.isCLibraryFunction(FDecl, "wcsdup"))
501
0
      return TaintPropagationRule({0}, {ReturnValueIndex});
502
600
  }
503
600
504
600
  // Skipping the following functions, since they might be used for cleansing
505
600
  // or smart memory copy:
506
600
  // - memccpy - copying until hitting a special character.
507
600
508
600
  auto It = findFunctionInConfig(CustomPropagations, FData);
509
600
  if (It != CustomPropagations.end()) {
510
26
    const auto &Value = It->second;
511
26
    return Value.second;
512
26
  }
513
574
514
574
  return TaintPropagationRule();
515
574
}
516
517
void GenericTaintChecker::checkPreStmt(const CallExpr *CE,
518
854
                                       CheckerContext &C) const {
519
854
  Optional<FunctionData> FData = FunctionData::create(CE, C);
520
854
  if (!FData)
521
1
    return;
522
853
523
853
  // Check for taintedness related errors first: system call, uncontrolled
524
853
  // format string, tainted buffer size.
525
853
  if (checkPre(CE, *FData, C))
526
54
    return;
527
799
528
799
  // Marks the function's arguments and/or return value tainted if it present in
529
799
  // the list.
530
799
  if (addSourcesPre(CE, *FData, C))
531
225
    return;
532
574
533
574
  addFiltersPre(CE, *FData, C);
534
574
}
535
536
void GenericTaintChecker::checkPostStmt(const CallExpr *CE,
537
813
                                        CheckerContext &C) const {
538
813
  // Set the marked values as tainted. The return value only accessible from
539
813
  // checkPostStmt.
540
813
  propagateFromPre(CE, C);
541
813
}
542
543
void GenericTaintChecker::printState(raw_ostream &Out, ProgramStateRef State,
544
2
                                     const char *NL, const char *Sep) const {
545
2
  printTaint(State, Out, NL, Sep);
546
2
}
547
548
bool GenericTaintChecker::addSourcesPre(const CallExpr *CE,
549
                                        const FunctionData &FData,
550
799
                                        CheckerContext &C) const {
551
799
  // First, try generating a propagation rule for this function.
552
799
  TaintPropagationRule Rule = TaintPropagationRule::getTaintPropagationRule(
553
799
      this->CustomPropagations, FData, C);
554
799
  if (!Rule.isNull()) {
555
225
    ProgramStateRef State = Rule.process(CE, C);
556
225
    if (State) {
557
225
      C.addTransition(State);
558
225
      return true;
559
225
    }
560
574
  }
561
574
  return false;
562
574
}
563
564
bool GenericTaintChecker::addFiltersPre(const CallExpr *CE,
565
                                        const FunctionData &FData,
566
574
                                        CheckerContext &C) const {
567
574
  auto It = findFunctionInConfig(CustomFilters, FData);
568
574
  if (It == CustomFilters.end())
569
569
    return false;
570
5
571
5
  ProgramStateRef State = C.getState();
572
5
  const auto &Value = It->second;
573
5
  const ArgVector &Args = Value.second;
574
5
  for (unsigned ArgNum : Args) {
575
5
    if (ArgNum >= CE->getNumArgs())
576
0
      continue;
577
5
578
5
    const Expr *Arg = CE->getArg(ArgNum);
579
5
    Optional<SVal> V = getPointedToSVal(C, Arg);
580
5
    if (V)
581
5
      State = removeTaint(State, *V);
582
5
  }
583
5
584
5
  if (State != C.getState()) {
585
5
    C.addTransition(State);
586
5
    return true;
587
5
  }
588
0
  return false;
589
0
}
590
591
bool GenericTaintChecker::propagateFromPre(const CallExpr *CE,
592
813
                                           CheckerContext &C) const {
593
813
  ProgramStateRef State = C.getState();
594
813
595
813
  // Depending on what was tainted at pre-visit, we determined a set of
596
813
  // arguments which should be tainted after the function returns. These are
597
813
  // stored in the state as TaintArgsOnPostVisit set.
598
813
  TaintArgsOnPostVisitTy TaintArgs = State->get<TaintArgsOnPostVisit>();
599
813
  if (TaintArgs.isEmpty())
600
657
    return false;
601
156
602
199
  
for (unsigned ArgNum : TaintArgs)156
{
603
199
    // Special handling for the tainted return value.
604
199
    if (ArgNum == ReturnValueIndex) {
605
81
      State = addTaint(State, CE, C.getLocationContext());
606
81
      continue;
607
81
    }
608
118
609
118
    // The arguments are pointer arguments. The data they are pointing at is
610
118
    // tainted after the call.
611
118
    if (CE->getNumArgs() < (ArgNum + 1))
612
0
      return false;
613
118
    const Expr *Arg = CE->getArg(ArgNum);
614
118
    Optional<SVal> V = getPointedToSVal(C, Arg);
615
118
    if (V)
616
118
      State = addTaint(State, *V);
617
118
  }
618
156
619
156
  // Clear up the taint info from the state.
620
156
  State = State->remove<TaintArgsOnPostVisit>();
621
156
622
156
  if (State != C.getState()) {
623
156
    C.addTransition(State);
624
156
    return true;
625
156
  }
626
0
  return false;
627
0
}
628
629
bool GenericTaintChecker::checkPre(const CallExpr *CE,
630
                                   const FunctionData &FData,
631
853
                                   CheckerContext &C) const {
632
853
633
853
  if (checkUncontrolledFormatString(CE, C))
634
16
    return true;
635
837
636
837
  if (checkSystemCall(CE, FData.Name, C))
637
15
    return true;
638
822
639
822
  if (checkTaintedBufferSize(CE, FData.FDecl, C))
640
16
    return true;
641
806
642
806
  if (checkCustomSinks(CE, FData, C))
643
7
    return true;
644
799
645
799
  return false;
646
799
}
647
648
Optional<SVal> GenericTaintChecker::getPointedToSVal(CheckerContext &C,
649
319
                                                     const Expr *Arg) {
650
319
  ProgramStateRef State = C.getState();
651
319
  SVal AddrVal = C.getSVal(Arg->IgnoreParens());
652
319
  if (AddrVal.isUnknownOrUndef())
653
0
    return None;
654
319
655
319
  Optional<Loc> AddrLoc = AddrVal.getAs<Loc>();
656
319
  if (!AddrLoc)
657
65
    return None;
658
254
659
254
  QualType ArgTy = Arg->getType().getCanonicalType();
660
254
  if (!ArgTy->isPointerType())
661
0
    return State->getSVal(*AddrLoc);
662
254
663
254
  QualType ValTy = ArgTy->getPointeeType();
664
254
665
254
  // Do not dereference void pointers. Treat them as byte pointers instead.
666
254
  // FIXME: we might want to consider more than just the first byte.
667
254
  if (ValTy->isVoidType())
668
23
    ValTy = C.getASTContext().CharTy;
669
254
670
254
  return State->getSVal(*AddrLoc, ValTy);
671
254
}
672
673
ProgramStateRef
674
GenericTaintChecker::TaintPropagationRule::process(const CallExpr *CE,
675
225
                                                   CheckerContext &C) const {
676
225
  ProgramStateRef State = C.getState();
677
225
678
225
  // Check for taint in arguments.
679
225
  bool IsTainted = true;
680
225
  for (unsigned ArgNum : SrcArgs) {
681
172
    if (ArgNum >= CE->getNumArgs())
682
4
      continue;
683
168
684
168
    if ((IsTainted = isTaintedOrPointsToTainted(CE->getArg(ArgNum), State, C)))
685
59
      break;
686
168
  }
687
225
688
225
  // Check for taint in variadic arguments.
689
225
  if (!IsTainted && 
VariadicType::Src == VarType67
) {
690
3
    // Check if any of the arguments is tainted
691
4
    for (unsigned i = VariadicIndex; i < CE->getNumArgs(); 
++i1
) {
692
3
      if ((IsTainted = isTaintedOrPointsToTainted(CE->getArg(i), State, C)))
693
2
        break;
694
3
    }
695
3
  }
696
225
697
225
  if (PropagationFunc)
698
12
    IsTainted = PropagationFunc(IsTainted, CE, C);
699
225
700
225
  if (!IsTainted)
701
67
    return State;
702
158
703
158
  // Mark the arguments which should be tainted after the function returns.
704
158
  for (unsigned ArgNum : DstArgs) {
705
126
    // Should mark the return value?
706
126
    if (ArgNum == ReturnValueIndex) {
707
81
      State = State->add<TaintArgsOnPostVisit>(ReturnValueIndex);
708
81
      continue;
709
81
    }
710
45
711
45
    if (ArgNum >= CE->getNumArgs())
712
1
      continue;
713
44
714
44
    // Mark the given argument.
715
44
    State = State->add<TaintArgsOnPostVisit>(ArgNum);
716
44
  }
717
158
718
158
  // Mark all variadic arguments tainted if present.
719
158
  if (VariadicType::Dst == VarType) {
720
69
    // For all pointer and references that were passed in:
721
69
    //   If they are not pointing to const data, mark data as tainted.
722
69
    //   TODO: So far we are just going one level down; ideally we'd need to
723
69
    //         recurse here.
724
145
    for (unsigned i = VariadicIndex; i < CE->getNumArgs(); 
++i76
) {
725
76
      const Expr *Arg = CE->getArg(i);
726
76
      // Process pointer argument.
727
76
      const Type *ArgTy = Arg->getType().getTypePtr();
728
76
      QualType PType = ArgTy->getPointeeType();
729
76
      if ((!PType.isNull() && 
!PType.isConstQualified()74
) ||
730
76
          
(2
ArgTy->isReferenceType()2
&&
!Arg->getType().isConstQualified()0
))
731
74
        State = State->add<TaintArgsOnPostVisit>(i);
732
76
    }
733
69
  }
734
158
735
158
  return State;
736
158
}
737
738
// If argument 0(protocol domain) is network, the return value should get taint.
739
bool GenericTaintChecker::TaintPropagationRule::postSocket(bool /*IsTainted*/,
740
                                                           const CallExpr *CE,
741
12
                                                           CheckerContext &C) {
742
12
  SourceLocation DomLoc = CE->getArg(0)->getExprLoc();
743
12
  StringRef DomName = C.getMacroNameOrSpelling(DomLoc);
744
12
  // White list the internal communication protocols.
745
12
  if (DomName.equals("AF_SYSTEM") || DomName.equals("AF_LOCAL") ||
746
12
      DomName.equals("AF_UNIX") || 
DomName.equals("AF_RESERVED_36")10
)
747
2
    return false;
748
10
749
10
  return true;
750
10
}
751
752
150
bool GenericTaintChecker::isStdin(const Expr *E, CheckerContext &C) {
753
150
  ProgramStateRef State = C.getState();
754
150
  SVal Val = C.getSVal(E);
755
150
756
150
  // stdin is a pointer, so it would be a region.
757
150
  const MemRegion *MemReg = Val.getAsRegion();
758
150
759
150
  // The region should be symbolic, we do not know it's value.
760
150
  const SymbolicRegion *SymReg = dyn_cast_or_null<SymbolicRegion>(MemReg);
761
150
  if (!SymReg)
762
93
    return false;
763
57
764
57
  // Get it's symbol and find the declaration region it's pointing to.
765
57
  const SymbolRegionValue *Sm =
766
57
      dyn_cast<SymbolRegionValue>(SymReg->getSymbol());
767
57
  if (!Sm)
768
0
    return false;
769
57
  const DeclRegion *DeclReg = dyn_cast_or_null<DeclRegion>(Sm->getRegion());
770
57
  if (!DeclReg)
771
0
    return false;
772
57
773
57
  // This region corresponds to a declaration, find out if it's a global/extern
774
57
  // variable named stdin with the proper type.
775
57
  if (const auto *D = dyn_cast_or_null<VarDecl>(DeclReg->getDecl())) {
776
57
    D = D->getCanonicalDecl();
777
57
    if ((D->getName().find("stdin") != StringRef::npos) && 
D->isExternC()19
) {
778
19
      const auto *PtrTy = dyn_cast<PointerType>(D->getType().getTypePtr());
779
19
      if (PtrTy && PtrTy->getPointeeType().getCanonicalType() ==
780
19
                       C.getASTContext().getFILEType().getCanonicalType())
781
19
        return true;
782
38
    }
783
57
  }
784
38
  return false;
785
38
}
786
787
static bool getPrintfFormatArgumentNum(const CallExpr *CE,
788
                                       const CheckerContext &C,
789
853
                                       unsigned &ArgNum) {
790
853
  // Find if the function contains a format string argument.
791
853
  // Handles: fprintf, printf, sprintf, snprintf, vfprintf, vprintf, vsprintf,
792
853
  // vsnprintf, syslog, custom annotated functions.
793
853
  const FunctionDecl *FDecl = C.getCalleeDecl(CE);
794
853
  if (!FDecl)
795
0
    return false;
796
853
  for (const auto *Format : FDecl->specific_attrs<FormatAttr>()) {
797
82
    ArgNum = Format->getFormatIdx() - 1;
798
82
    if ((Format->getType()->getName() == "printf") && 
CE->getNumArgs() > ArgNum16
)
799
16
      return true;
800
82
  }
801
853
802
853
  // Or if a function is named setproctitle (this is a heuristic).
803
853
  
if (837
C.getCalleeName(CE).find("setproctitle") != StringRef::npos837
) {
804
12
    ArgNum = 0;
805
12
    return true;
806
12
  }
807
825
808
825
  return false;
809
825
}
810
811
bool GenericTaintChecker::generateReportIfTainted(const Expr *E, StringRef Msg,
812
110
                                                  CheckerContext &C) const {
813
110
  assert(E);
814
110
815
110
  // Check for taint.
816
110
  ProgramStateRef State = C.getState();
817
110
  Optional<SVal> PointedToSVal = getPointedToSVal(C, E);
818
110
  SVal TaintedSVal;
819
110
  if (PointedToSVal && 
isTainted(State, *PointedToSVal)45
)
820
31
    TaintedSVal = *PointedToSVal;
821
79
  else if (isTainted(State, E, C.getLocationContext()))
822
23
    TaintedSVal = C.getSVal(E);
823
56
  else
824
56
    return false;
825
54
826
54
  // Generate diagnostic.
827
54
  if (ExplodedNode *N = C.generateNonFatalErrorNode()) {
828
54
    initBugType();
829
54
    auto report = std::make_unique<PathSensitiveBugReport>(*BT, Msg, N);
830
54
    report->addRange(E->getSourceRange());
831
54
    report->addVisitor(std::make_unique<TaintBugVisitor>(TaintedSVal));
832
54
    C.emitReport(std::move(report));
833
54
    return true;
834
54
  }
835
0
  return false;
836
0
}
837
838
bool GenericTaintChecker::checkUncontrolledFormatString(
839
853
    const CallExpr *CE, CheckerContext &C) const {
840
853
  // Check if the function contains a format string argument.
841
853
  unsigned ArgNum = 0;
842
853
  if (!getPrintfFormatArgumentNum(CE, C, ArgNum))
843
825
    return false;
844
28
845
28
  // If either the format string content or the pointer itself are tainted,
846
28
  // warn.
847
28
  return generateReportIfTainted(CE->getArg(ArgNum),
848
28
                                 MsgUncontrolledFormatString, C);
849
28
}
850
851
bool GenericTaintChecker::checkSystemCall(const CallExpr *CE, StringRef Name,
852
837
                                          CheckerContext &C) const {
853
837
  // TODO: It might make sense to run this check on demand. In some cases,
854
837
  // we should check if the environment has been cleansed here. We also might
855
837
  // need to know if the user was reset before these calls(seteuid).
856
837
  unsigned ArgNum = llvm::StringSwitch<unsigned>(Name)
857
837
                        .Case("system", 0)
858
837
                        .Case("popen", 0)
859
837
                        .Case("execl", 0)
860
837
                        .Case("execle", 0)
861
837
                        .Case("execlp", 0)
862
837
                        .Case("execv", 0)
863
837
                        .Case("execvp", 0)
864
837
                        .Case("execvP", 0)
865
837
                        .Case("execve", 0)
866
837
                        .Case("dlopen", 0)
867
837
                        .Default(InvalidArgIndex);
868
837
869
837
  if (ArgNum == InvalidArgIndex || 
CE->getNumArgs() < (ArgNum + 1)19
)
870
819
    return false;
871
18
872
18
  return generateReportIfTainted(CE->getArg(ArgNum), MsgSanitizeSystemArgs, C);
873
18
}
874
875
// TODO: Should this check be a part of the CString checker?
876
// If yes, should taint be a global setting?
877
bool GenericTaintChecker::checkTaintedBufferSize(const CallExpr *CE,
878
                                                 const FunctionDecl *FDecl,
879
822
                                                 CheckerContext &C) const {
880
822
  // If the function has a buffer size argument, set ArgNum.
881
822
  unsigned ArgNum = InvalidArgIndex;
882
822
  unsigned BId = 0;
883
822
  if ((BId = FDecl->getMemoryFunctionKind()))
884
257
    switch (BId) {
885
32
    case Builtin::BImemcpy:
886
32
    case Builtin::BImemmove:
887
32
    case Builtin::BIstrncpy:
888
32
      ArgNum = 2;
889
32
      break;
890
32
    case Builtin::BIstrndup:
891
2
      ArgNum = 1;
892
2
      break;
893
223
    default:
894
223
      break;
895
822
    };
896
822
897
822
  if (ArgNum == InvalidArgIndex) {
898
788
    if (C.isCLibraryFunction(FDecl, "malloc") ||
899
788
        
C.isCLibraryFunction(FDecl, "calloc")773
||
900
788
        
C.isCLibraryFunction(FDecl, "alloca")771
)
901
17
      ArgNum = 0;
902
771
    else if (C.isCLibraryFunction(FDecl, "memccpy"))
903
1
      ArgNum = 3;
904
770
    else if (C.isCLibraryFunction(FDecl, "realloc"))
905
0
      ArgNum = 1;
906
770
    else if (C.isCLibraryFunction(FDecl, "bcopy"))
907
2
      ArgNum = 2;
908
788
  }
909
822
910
822
  return ArgNum != InvalidArgIndex && 
CE->getNumArgs() > ArgNum54
&&
911
822
         
generateReportIfTainted(CE->getArg(ArgNum), MsgTaintedBufferSize, C)51
;
912
822
}
913
914
bool GenericTaintChecker::checkCustomSinks(const CallExpr *CE,
915
                                           const FunctionData &FData,
916
806
                                           CheckerContext &C) const {
917
806
  auto It = findFunctionInConfig(CustomSinks, FData);
918
806
  if (It == CustomSinks.end())
919
797
    return false;
920
9
921
9
  const auto &Value = It->second;
922
9
  const GenericTaintChecker::ArgVector &Args = Value.second;
923
13
  for (unsigned ArgNum : Args) {
924
13
    if (ArgNum >= CE->getNumArgs())
925
0
      continue;
926
13
927
13
    if (generateReportIfTainted(CE->getArg(ArgNum), MsgCustomSink, C))
928
7
      return true;
929
13
  }
930
9
931
9
  
return false2
;
932
9
}
933
934
18
void ento::registerGenericTaintChecker(CheckerManager &Mgr) {
935
18
  auto *Checker = Mgr.registerChecker<GenericTaintChecker>();
936
18
  std::string Option{"Config"};
937
18
  StringRef ConfigFile =
938
18
      Mgr.getAnalyzerOptions().getCheckerStringOption(Checker, Option);
939
18
  llvm::Optional<TaintConfig> Config =
940
18
      getConfiguration<TaintConfig>(Mgr, Checker, Option, ConfigFile);
941
18
  if (Config)
942
4
    Checker->parseConfiguration(Mgr, Option, std::move(Config.getValue()));
943
18
}
944
945
18
bool ento::shouldRegisterGenericTaintChecker(const LangOptions &LO) {
946
18
  return true;
947
18
}