Coverage Report

Created: 2021-03-06 07:03

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