24
24
#include " clang/StaticAnalyzer/Core/CheckerManager.h"
25
25
#include " clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
26
26
#include " clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h"
27
- #include " llvm/ADT/StringMap.h"
28
27
#include " llvm/Support/YAMLTraits.h"
28
+ #include < algorithm>
29
29
#include < limits>
30
+ #include < unordered_map>
30
31
#include < utility>
31
32
32
33
using namespace clang ;
@@ -56,19 +57,20 @@ class GenericTaintChecker
56
57
57
58
// / Used to parse the configuration file.
58
59
struct TaintConfiguration {
59
- using NameArgsPair = std::pair< std::string, ArgVector>;
60
+ using NameScopeArgs = std::tuple<std::string, std::string, ArgVector>;
60
61
61
62
struct Propagation {
62
63
std::string Name;
64
+ std::string Scope;
63
65
ArgVector SrcArgs;
64
66
SignedArgVector DstArgs;
65
67
VariadicType VarType;
66
68
unsigned VarIndex;
67
69
};
68
70
69
71
std::vector<Propagation> Propagations;
70
- std::vector<NameArgsPair > Filters;
71
- std::vector<NameArgsPair > Sinks;
72
+ std::vector<NameScopeArgs > Filters;
73
+ std::vector<NameScopeArgs > Sinks;
72
74
73
75
TaintConfiguration () = default ;
74
76
TaintConfiguration (const TaintConfiguration &) = default ;
@@ -97,18 +99,49 @@ class GenericTaintChecker
97
99
BT.reset (new BugType (this , " Use of Untrusted Data" , " Untrusted Data" ));
98
100
}
99
101
102
+ struct FunctionData {
103
+ FunctionData () = delete ;
104
+ FunctionData (const FunctionData &) = default ;
105
+ FunctionData (FunctionData &&) = default ;
106
+ FunctionData &operator =(const FunctionData &) = delete ;
107
+ FunctionData &operator =(FunctionData &&) = delete ;
108
+
109
+ static Optional<FunctionData> create (const CallExpr *CE,
110
+ const CheckerContext &C) {
111
+ const FunctionDecl *FDecl = C.getCalleeDecl (CE);
112
+ if (!FDecl || (FDecl->getKind () != Decl::Function &&
113
+ FDecl->getKind () != Decl::CXXMethod))
114
+ return None;
115
+
116
+ StringRef Name = C.getCalleeName (FDecl);
117
+ std::string FullName = FDecl->getQualifiedNameAsString ();
118
+ if (Name.empty () || FullName.empty ())
119
+ return None;
120
+
121
+ return FunctionData{FDecl, Name, FullName};
122
+ }
123
+
124
+ bool isInScope (StringRef Scope) const {
125
+ return StringRef (FullName).startswith (Scope);
126
+ }
127
+
128
+ const FunctionDecl *const FDecl;
129
+ const StringRef Name;
130
+ const std::string FullName;
131
+ };
132
+
100
133
// / Catch taint related bugs. Check if tainted data is passed to a
101
134
// / system call etc. Returns true on matching.
102
- bool checkPre (const CallExpr *CE, const FunctionDecl *FDecl, StringRef Name ,
135
+ bool checkPre (const CallExpr *CE, const FunctionData &FData ,
103
136
CheckerContext &C) const ;
104
137
105
138
// / Add taint sources on a pre-visit. Returns true on matching.
106
- bool addSourcesPre (const CallExpr *CE, const FunctionDecl *FDecl ,
107
- StringRef Name, CheckerContext &C) const ;
139
+ bool addSourcesPre (const CallExpr *CE, const FunctionData &FData ,
140
+ CheckerContext &C) const ;
108
141
109
142
// / Mark filter's arguments not tainted on a pre-visit. Returns true on
110
143
// / matching.
111
- bool addFiltersPre (const CallExpr *CE, StringRef Name ,
144
+ bool addFiltersPre (const CallExpr *CE, const FunctionData &FData ,
112
145
CheckerContext &C) const ;
113
146
114
147
// / Propagate taint generated at pre-visit. Returns true on matching.
@@ -149,16 +182,25 @@ class GenericTaintChecker
149
182
// / Check if tainted data is used as a custom sink's parameter.
150
183
static constexpr llvm::StringLiteral MsgCustomSink =
151
184
" Untrusted data is passed to a user-defined sink" ;
152
- bool checkCustomSinks (const CallExpr *CE, StringRef Name ,
185
+ bool checkCustomSinks (const CallExpr *CE, const FunctionData &FData ,
153
186
CheckerContext &C) const ;
154
187
155
188
// / Generate a report if the expression is tainted or points to tainted data.
156
189
bool generateReportIfTainted (const Expr *E, StringRef Msg,
157
190
CheckerContext &C) const ;
158
191
159
192
struct TaintPropagationRule ;
160
- using NameRuleMap = llvm::StringMap<TaintPropagationRule>;
161
- using NameArgMap = llvm::StringMap<ArgVector>;
193
+ template <typename T>
194
+ using ConfigDataMap =
195
+ std::unordered_multimap<std::string, std::pair<std::string, T>>;
196
+ using NameRuleMap = ConfigDataMap<TaintPropagationRule>;
197
+ using NameArgMap = ConfigDataMap<ArgVector>;
198
+
199
+ // / Find a function with the given name and scope. Returns the first match
200
+ // / or the end of the map.
201
+ template <typename T>
202
+ static auto findFunctionInConfig (const ConfigDataMap<T> &Map,
203
+ const FunctionData &FData);
162
204
163
205
// / A struct used to specify taint propagation rules for a function.
164
206
// /
@@ -200,8 +242,7 @@ class GenericTaintChecker
200
242
// / Get the propagation rule for a given function.
201
243
static TaintPropagationRule
202
244
getTaintPropagationRule (const NameRuleMap &CustomPropagations,
203
- const FunctionDecl *FDecl, StringRef Name,
204
- CheckerContext &C);
245
+ const FunctionData &FData, CheckerContext &C);
205
246
206
247
void addSrcArg (unsigned A) { SrcArgs.push_back (A); }
207
248
void addDstArg (unsigned A) { DstArgs.push_back (A); }
@@ -236,14 +277,15 @@ class GenericTaintChecker
236
277
CheckerContext &C);
237
278
};
238
279
239
- // / Defines a map between the propagation function's name and
240
- // / TaintPropagationRule.
280
+ // / Defines a map between the propagation function's name, scope
281
+ // / and TaintPropagationRule.
241
282
NameRuleMap CustomPropagations;
242
283
243
- // / Defines a map between the filter function's name and filtering args.
284
+ // / Defines a map between the filter function's name, scope and filtering
285
+ // / args.
244
286
NameArgMap CustomFilters;
245
287
246
- // / Defines a map between the sink function's name and sinking args.
288
+ // / Defines a map between the sink function's name, scope and sinking args.
247
289
NameArgMap CustomSinks;
248
290
};
249
291
@@ -260,7 +302,7 @@ constexpr llvm::StringLiteral GenericTaintChecker::MsgCustomSink;
260
302
using TaintConfig = GenericTaintChecker::TaintConfiguration;
261
303
262
304
LLVM_YAML_IS_SEQUENCE_VECTOR (TaintConfig::Propagation)
263
- LLVM_YAML_IS_SEQUENCE_VECTOR(TaintConfig::NameArgsPair )
305
+ LLVM_YAML_IS_SEQUENCE_VECTOR(TaintConfig::NameScopeArgs )
264
306
265
307
namespace llvm {
266
308
namespace yaml {
@@ -275,6 +317,7 @@ template <> struct MappingTraits<TaintConfig> {
275
317
template <> struct MappingTraits <TaintConfig::Propagation> {
276
318
static void mapping (IO &IO, TaintConfig::Propagation &Propagation) {
277
319
IO.mapRequired (" Name" , Propagation.Name );
320
+ IO.mapOptional (" Scope" , Propagation.Scope );
278
321
IO.mapOptional (" SrcArgs" , Propagation.SrcArgs );
279
322
IO.mapOptional (" DstArgs" , Propagation.DstArgs );
280
323
IO.mapOptional (" VariadicType" , Propagation.VarType ,
@@ -292,10 +335,11 @@ template <> struct ScalarEnumerationTraits<GenericTaintChecker::VariadicType> {
292
335
}
293
336
};
294
337
295
- template <> struct MappingTraits <TaintConfig::NameArgsPair> {
296
- static void mapping (IO &IO, TaintConfig::NameArgsPair &NameArg) {
297
- IO.mapRequired (" Name" , NameArg.first );
298
- IO.mapRequired (" Args" , NameArg.second );
338
+ template <> struct MappingTraits <TaintConfig::NameScopeArgs> {
339
+ static void mapping (IO &IO, TaintConfig::NameScopeArgs &NSA) {
340
+ IO.mapRequired (" Name" , std::get<0 >(NSA));
341
+ IO.mapOptional (" Scope" , std::get<1 >(NSA));
342
+ IO.mapRequired (" Args" , std::get<2 >(NSA));
299
343
}
300
344
};
301
345
} // namespace yaml
@@ -328,31 +372,51 @@ void GenericTaintChecker::parseConfiguration(CheckerManager &Mgr,
328
372
const std::string &Option,
329
373
TaintConfiguration &&Config) {
330
374
for (auto &P : Config.Propagations ) {
331
- GenericTaintChecker::CustomPropagations.try_emplace (
332
- P.Name , std::move (P.SrcArgs ),
333
- convertToArgVector (Mgr, Option, P.DstArgs ), P.VarType , P.VarIndex );
375
+ GenericTaintChecker::CustomPropagations.emplace (
376
+ P.Name ,
377
+ std::make_pair (P.Scope , TaintPropagationRule{
378
+ std::move (P.SrcArgs ),
379
+ convertToArgVector (Mgr, Option, P.DstArgs ),
380
+ P.VarType , P.VarIndex }));
334
381
}
335
382
336
383
for (auto &F : Config.Filters ) {
337
- GenericTaintChecker::CustomFilters.try_emplace (F.first ,
338
- std::move (F.second ));
384
+ GenericTaintChecker::CustomFilters.emplace (
385
+ std::get<0 >(F),
386
+ std::make_pair (std::move (std::get<1 >(F)), std::move (std::get<2 >(F))));
339
387
}
340
388
341
389
for (auto &S : Config.Sinks ) {
342
- GenericTaintChecker::CustomSinks.try_emplace (S.first , std::move (S.second ));
390
+ GenericTaintChecker::CustomSinks.emplace (
391
+ std::get<0 >(S),
392
+ std::make_pair (std::move (std::get<1 >(S)), std::move (std::get<2 >(S))));
343
393
}
344
394
}
345
395
396
+ template <typename T>
397
+ auto GenericTaintChecker::findFunctionInConfig (const ConfigDataMap<T> &Map,
398
+ const FunctionData &FData) {
399
+ auto Range = Map.equal_range (FData.Name );
400
+ auto It =
401
+ std::find_if (Range.first , Range.second , [&FData](const auto &Entry) {
402
+ const auto &Value = Entry.second ;
403
+ StringRef Scope = Value.first ;
404
+ return Scope.empty () || FData.isInScope (Scope);
405
+ });
406
+ return It != Range.second ? It : Map.end ();
407
+ }
408
+
346
409
GenericTaintChecker::TaintPropagationRule
347
410
GenericTaintChecker::TaintPropagationRule::getTaintPropagationRule (
348
- const NameRuleMap &CustomPropagations, const FunctionDecl *FDecl ,
349
- StringRef Name, CheckerContext &C) {
411
+ const NameRuleMap &CustomPropagations, const FunctionData &FData ,
412
+ CheckerContext &C) {
350
413
// TODO: Currently, we might lose precision here: we always mark a return
351
414
// value as tainted even if it's just a pointer, pointing to tainted data.
352
415
353
416
// Check for exact name match for functions without builtin substitutes.
417
+ // Use qualified name, because these are C functions without namespace.
354
418
TaintPropagationRule Rule =
355
- llvm::StringSwitch<TaintPropagationRule>(Name )
419
+ llvm::StringSwitch<TaintPropagationRule>(FData. FullName )
356
420
// Source functions
357
421
// TODO: Add support for vfscanf & family.
358
422
.Case (" fdopen" , TaintPropagationRule ({}, {ReturnValueIndex}))
@@ -397,6 +461,7 @@ GenericTaintChecker::TaintPropagationRule::getTaintPropagationRule(
397
461
398
462
// Check if it's one of the memory setting/copying functions.
399
463
// This check is specialized but faster then calling isCLibraryFunction.
464
+ const FunctionDecl *FDecl = FData.FDecl ;
400
465
unsigned BId = 0 ;
401
466
if ((BId = FDecl->getMemoryFunctionKind ()))
402
467
switch (BId) {
@@ -440,35 +505,32 @@ GenericTaintChecker::TaintPropagationRule::getTaintPropagationRule(
440
505
// or smart memory copy:
441
506
// - memccpy - copying until hitting a special character.
442
507
443
- auto It = CustomPropagations.find (Name);
444
- if (It != CustomPropagations.end ())
445
- return It->getValue ();
508
+ auto It = findFunctionInConfig (CustomPropagations, FData);
509
+ if (It != CustomPropagations.end ()) {
510
+ const auto &Value = It->second ;
511
+ return Value.second ;
512
+ }
446
513
447
514
return TaintPropagationRule ();
448
515
}
449
516
450
517
void GenericTaintChecker::checkPreStmt (const CallExpr *CE,
451
518
CheckerContext &C) const {
452
- const FunctionDecl *FDecl = C.getCalleeDecl (CE);
453
- // Check for non-global functions.
454
- if (!FDecl || FDecl->getKind () != Decl::Function)
455
- return ;
456
-
457
- StringRef Name = C.getCalleeName (FDecl);
458
- if (Name.empty ())
519
+ Optional<FunctionData> FData = FunctionData::create (CE, C);
520
+ if (!FData)
459
521
return ;
460
522
461
523
// Check for taintedness related errors first: system call, uncontrolled
462
524
// format string, tainted buffer size.
463
- if (checkPre (CE, FDecl, Name , C))
525
+ if (checkPre (CE, *FData , C))
464
526
return ;
465
527
466
528
// Marks the function's arguments and/or return value tainted if it present in
467
529
// the list.
468
- if (addSourcesPre (CE, FDecl, Name , C))
530
+ if (addSourcesPre (CE, *FData , C))
469
531
return ;
470
532
471
- addFiltersPre (CE, Name , C);
533
+ addFiltersPre (CE, *FData , C);
472
534
}
473
535
474
536
void GenericTaintChecker::checkPostStmt (const CallExpr *CE,
@@ -484,12 +546,11 @@ void GenericTaintChecker::printState(raw_ostream &Out, ProgramStateRef State,
484
546
}
485
547
486
548
bool GenericTaintChecker::addSourcesPre (const CallExpr *CE,
487
- const FunctionDecl *FDecl,
488
- StringRef Name,
549
+ const FunctionData &FData,
489
550
CheckerContext &C) const {
490
551
// First, try generating a propagation rule for this function.
491
552
TaintPropagationRule Rule = TaintPropagationRule::getTaintPropagationRule (
492
- this ->CustomPropagations , FDecl, Name , C);
553
+ this ->CustomPropagations , FData , C);
493
554
if (!Rule.isNull ()) {
494
555
ProgramStateRef State = Rule.process (CE, C);
495
556
if (State) {
@@ -500,14 +561,16 @@ bool GenericTaintChecker::addSourcesPre(const CallExpr *CE,
500
561
return false ;
501
562
}
502
563
503
- bool GenericTaintChecker::addFiltersPre (const CallExpr *CE, StringRef Name,
564
+ bool GenericTaintChecker::addFiltersPre (const CallExpr *CE,
565
+ const FunctionData &FData,
504
566
CheckerContext &C) const {
505
- auto It = CustomFilters. find (Name );
567
+ auto It = findFunctionInConfig (CustomFilters, FData );
506
568
if (It == CustomFilters.end ())
507
569
return false ;
508
570
509
571
ProgramStateRef State = C.getState ();
510
- const ArgVector &Args = It->getValue ();
572
+ const auto &Value = It->second ;
573
+ const ArgVector &Args = Value.second ;
511
574
for (unsigned ArgNum : Args) {
512
575
if (ArgNum >= CE->getNumArgs ())
513
576
continue ;
@@ -564,19 +627,19 @@ bool GenericTaintChecker::propagateFromPre(const CallExpr *CE,
564
627
}
565
628
566
629
bool GenericTaintChecker::checkPre (const CallExpr *CE,
567
- const FunctionDecl *FDecl, StringRef Name ,
630
+ const FunctionData &FData ,
568
631
CheckerContext &C) const {
569
632
570
633
if (checkUncontrolledFormatString (CE, C))
571
634
return true ;
572
635
573
- if (checkSystemCall (CE, Name, C))
636
+ if (checkSystemCall (CE, FData. Name , C))
574
637
return true ;
575
638
576
- if (checkTaintedBufferSize (CE, FDecl, C))
639
+ if (checkTaintedBufferSize (CE, FData. FDecl , C))
577
640
return true ;
578
641
579
- if (checkCustomSinks (CE, Name , C))
642
+ if (checkCustomSinks (CE, FData , C))
580
643
return true ;
581
644
582
645
return false ;
@@ -595,7 +658,7 @@ Optional<SVal> GenericTaintChecker::getPointedToSVal(CheckerContext &C,
595
658
596
659
QualType ArgTy = Arg->getType ().getCanonicalType ();
597
660
if (!ArgTy->isPointerType ())
598
- return None ;
661
+ return State-> getSVal (*AddrLoc) ;
599
662
600
663
QualType ValTy = ArgTy->getPointeeType ();
601
664
@@ -848,13 +911,15 @@ bool GenericTaintChecker::checkTaintedBufferSize(const CallExpr *CE,
848
911
generateReportIfTainted (CE->getArg (ArgNum), MsgTaintedBufferSize, C);
849
912
}
850
913
851
- bool GenericTaintChecker::checkCustomSinks (const CallExpr *CE, StringRef Name,
914
+ bool GenericTaintChecker::checkCustomSinks (const CallExpr *CE,
915
+ const FunctionData &FData,
852
916
CheckerContext &C) const {
853
- auto It = CustomSinks. find (Name );
917
+ auto It = findFunctionInConfig (CustomSinks, FData );
854
918
if (It == CustomSinks.end ())
855
919
return false ;
856
920
857
- const GenericTaintChecker::ArgVector &Args = It->getValue ();
921
+ const auto &Value = It->second ;
922
+ const GenericTaintChecker::ArgVector &Args = Value.second ;
858
923
for (unsigned ArgNum : Args) {
859
924
if (ArgNum >= CE->getNumArgs ())
860
925
continue ;
0 commit comments