Coverage Report

Created: 2020-09-19 12:23

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