2424#include " clang/StaticAnalyzer/Core/CheckerManager.h"
2525#include " clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
2626#include " clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h"
27- #include " llvm/ADT/StringMap.h"
2827#include " llvm/Support/YAMLTraits.h"
28+ #include < algorithm>
2929#include < limits>
30+ #include < unordered_map>
3031#include < utility>
3132
3233using namespace clang ;
@@ -56,19 +57,20 @@ class GenericTaintChecker
5657
5758 // / Used to parse the configuration file.
5859 struct TaintConfiguration {
59- using NameArgsPair = std::pair< std::string, ArgVector>;
60+ using NameScopeArgs = std::tuple<std::string, std::string, ArgVector>;
6061
6162 struct Propagation {
6263 std::string Name;
64+ std::string Scope;
6365 ArgVector SrcArgs;
6466 SignedArgVector DstArgs;
6567 VariadicType VarType;
6668 unsigned VarIndex;
6769 };
6870
6971 std::vector<Propagation> Propagations;
70- std::vector<NameArgsPair > Filters;
71- std::vector<NameArgsPair > Sinks;
72+ std::vector<NameScopeArgs > Filters;
73+ std::vector<NameScopeArgs > Sinks;
7274
7375 TaintConfiguration () = default ;
7476 TaintConfiguration (const TaintConfiguration &) = default ;
@@ -97,18 +99,49 @@ class GenericTaintChecker
9799 BT.reset (new BugType (this , " Use of Untrusted Data" , " Untrusted Data" ));
98100 }
99101
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+
100133 // / Catch taint related bugs. Check if tainted data is passed to a
101134 // / 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 ,
103136 CheckerContext &C) const ;
104137
105138 // / 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 ;
108141
109142 // / Mark filter's arguments not tainted on a pre-visit. Returns true on
110143 // / matching.
111- bool addFiltersPre (const CallExpr *CE, StringRef Name ,
144+ bool addFiltersPre (const CallExpr *CE, const FunctionData &FData ,
112145 CheckerContext &C) const ;
113146
114147 // / Propagate taint generated at pre-visit. Returns true on matching.
@@ -149,16 +182,25 @@ class GenericTaintChecker
149182 // / Check if tainted data is used as a custom sink's parameter.
150183 static constexpr llvm::StringLiteral MsgCustomSink =
151184 " 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 ,
153186 CheckerContext &C) const ;
154187
155188 // / Generate a report if the expression is tainted or points to tainted data.
156189 bool generateReportIfTainted (const Expr *E, StringRef Msg,
157190 CheckerContext &C) const ;
158191
159192 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);
162204
163205 // / A struct used to specify taint propagation rules for a function.
164206 // /
@@ -200,8 +242,7 @@ class GenericTaintChecker
200242 // / Get the propagation rule for a given function.
201243 static TaintPropagationRule
202244 getTaintPropagationRule (const NameRuleMap &CustomPropagations,
203- const FunctionDecl *FDecl, StringRef Name,
204- CheckerContext &C);
245+ const FunctionData &FData, CheckerContext &C);
205246
206247 void addSrcArg (unsigned A) { SrcArgs.push_back (A); }
207248 void addDstArg (unsigned A) { DstArgs.push_back (A); }
@@ -236,14 +277,15 @@ class GenericTaintChecker
236277 CheckerContext &C);
237278 };
238279
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.
241282 NameRuleMap CustomPropagations;
242283
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.
244286 NameArgMap CustomFilters;
245287
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.
247289 NameArgMap CustomSinks;
248290};
249291
@@ -260,7 +302,7 @@ constexpr llvm::StringLiteral GenericTaintChecker::MsgCustomSink;
260302using TaintConfig = GenericTaintChecker::TaintConfiguration;
261303
262304LLVM_YAML_IS_SEQUENCE_VECTOR (TaintConfig::Propagation)
263- LLVM_YAML_IS_SEQUENCE_VECTOR(TaintConfig::NameArgsPair )
305+ LLVM_YAML_IS_SEQUENCE_VECTOR(TaintConfig::NameScopeArgs )
264306
265307namespace llvm {
266308namespace yaml {
@@ -275,6 +317,7 @@ template <> struct MappingTraits<TaintConfig> {
275317template <> struct MappingTraits <TaintConfig::Propagation> {
276318 static void mapping (IO &IO, TaintConfig::Propagation &Propagation) {
277319 IO.mapRequired (" Name" , Propagation.Name );
320+ IO.mapOptional (" Scope" , Propagation.Scope );
278321 IO.mapOptional (" SrcArgs" , Propagation.SrcArgs );
279322 IO.mapOptional (" DstArgs" , Propagation.DstArgs );
280323 IO.mapOptional (" VariadicType" , Propagation.VarType ,
@@ -292,10 +335,11 @@ template <> struct ScalarEnumerationTraits<GenericTaintChecker::VariadicType> {
292335 }
293336};
294337
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));
299343 }
300344};
301345} // namespace yaml
@@ -328,31 +372,51 @@ void GenericTaintChecker::parseConfiguration(CheckerManager &Mgr,
328372 const std::string &Option,
329373 TaintConfiguration &&Config) {
330374 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 }));
334381 }
335382
336383 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))));
339387 }
340388
341389 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))));
343393 }
344394}
345395
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+
346409GenericTaintChecker::TaintPropagationRule
347410GenericTaintChecker::TaintPropagationRule::getTaintPropagationRule (
348- const NameRuleMap &CustomPropagations, const FunctionDecl *FDecl ,
349- StringRef Name, CheckerContext &C) {
411+ const NameRuleMap &CustomPropagations, const FunctionData &FData ,
412+ CheckerContext &C) {
350413 // TODO: Currently, we might lose precision here: we always mark a return
351414 // value as tainted even if it's just a pointer, pointing to tainted data.
352415
353416 // Check for exact name match for functions without builtin substitutes.
417+ // Use qualified name, because these are C functions without namespace.
354418 TaintPropagationRule Rule =
355- llvm::StringSwitch<TaintPropagationRule>(Name )
419+ llvm::StringSwitch<TaintPropagationRule>(FData. FullName )
356420 // Source functions
357421 // TODO: Add support for vfscanf & family.
358422 .Case (" fdopen" , TaintPropagationRule ({}, {ReturnValueIndex}))
@@ -397,6 +461,7 @@ GenericTaintChecker::TaintPropagationRule::getTaintPropagationRule(
397461
398462 // Check if it's one of the memory setting/copying functions.
399463 // This check is specialized but faster then calling isCLibraryFunction.
464+ const FunctionDecl *FDecl = FData.FDecl ;
400465 unsigned BId = 0 ;
401466 if ((BId = FDecl->getMemoryFunctionKind ()))
402467 switch (BId) {
@@ -440,35 +505,32 @@ GenericTaintChecker::TaintPropagationRule::getTaintPropagationRule(
440505 // or smart memory copy:
441506 // - memccpy - copying until hitting a special character.
442507
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+ }
446513
447514 return TaintPropagationRule ();
448515}
449516
450517void GenericTaintChecker::checkPreStmt (const CallExpr *CE,
451518 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)
459521 return ;
460522
461523 // Check for taintedness related errors first: system call, uncontrolled
462524 // format string, tainted buffer size.
463- if (checkPre (CE, FDecl, Name , C))
525+ if (checkPre (CE, *FData , C))
464526 return ;
465527
466528 // Marks the function's arguments and/or return value tainted if it present in
467529 // the list.
468- if (addSourcesPre (CE, FDecl, Name , C))
530+ if (addSourcesPre (CE, *FData , C))
469531 return ;
470532
471- addFiltersPre (CE, Name , C);
533+ addFiltersPre (CE, *FData , C);
472534}
473535
474536void GenericTaintChecker::checkPostStmt (const CallExpr *CE,
@@ -484,12 +546,11 @@ void GenericTaintChecker::printState(raw_ostream &Out, ProgramStateRef State,
484546}
485547
486548bool GenericTaintChecker::addSourcesPre (const CallExpr *CE,
487- const FunctionDecl *FDecl,
488- StringRef Name,
549+ const FunctionData &FData,
489550 CheckerContext &C) const {
490551 // First, try generating a propagation rule for this function.
491552 TaintPropagationRule Rule = TaintPropagationRule::getTaintPropagationRule (
492- this ->CustomPropagations , FDecl, Name , C);
553+ this ->CustomPropagations , FData , C);
493554 if (!Rule.isNull ()) {
494555 ProgramStateRef State = Rule.process (CE, C);
495556 if (State) {
@@ -500,14 +561,16 @@ bool GenericTaintChecker::addSourcesPre(const CallExpr *CE,
500561 return false ;
501562}
502563
503- bool GenericTaintChecker::addFiltersPre (const CallExpr *CE, StringRef Name,
564+ bool GenericTaintChecker::addFiltersPre (const CallExpr *CE,
565+ const FunctionData &FData,
504566 CheckerContext &C) const {
505- auto It = CustomFilters. find (Name );
567+ auto It = findFunctionInConfig (CustomFilters, FData );
506568 if (It == CustomFilters.end ())
507569 return false ;
508570
509571 ProgramStateRef State = C.getState ();
510- const ArgVector &Args = It->getValue ();
572+ const auto &Value = It->second ;
573+ const ArgVector &Args = Value.second ;
511574 for (unsigned ArgNum : Args) {
512575 if (ArgNum >= CE->getNumArgs ())
513576 continue ;
@@ -564,19 +627,19 @@ bool GenericTaintChecker::propagateFromPre(const CallExpr *CE,
564627}
565628
566629bool GenericTaintChecker::checkPre (const CallExpr *CE,
567- const FunctionDecl *FDecl, StringRef Name ,
630+ const FunctionData &FData ,
568631 CheckerContext &C) const {
569632
570633 if (checkUncontrolledFormatString (CE, C))
571634 return true ;
572635
573- if (checkSystemCall (CE, Name, C))
636+ if (checkSystemCall (CE, FData. Name , C))
574637 return true ;
575638
576- if (checkTaintedBufferSize (CE, FDecl, C))
639+ if (checkTaintedBufferSize (CE, FData. FDecl , C))
577640 return true ;
578641
579- if (checkCustomSinks (CE, Name , C))
642+ if (checkCustomSinks (CE, FData , C))
580643 return true ;
581644
582645 return false ;
@@ -595,7 +658,7 @@ Optional<SVal> GenericTaintChecker::getPointedToSVal(CheckerContext &C,
595658
596659 QualType ArgTy = Arg->getType ().getCanonicalType ();
597660 if (!ArgTy->isPointerType ())
598- return None ;
661+ return State-> getSVal (*AddrLoc) ;
599662
600663 QualType ValTy = ArgTy->getPointeeType ();
601664
@@ -848,13 +911,15 @@ bool GenericTaintChecker::checkTaintedBufferSize(const CallExpr *CE,
848911 generateReportIfTainted (CE->getArg (ArgNum), MsgTaintedBufferSize, C);
849912}
850913
851- bool GenericTaintChecker::checkCustomSinks (const CallExpr *CE, StringRef Name,
914+ bool GenericTaintChecker::checkCustomSinks (const CallExpr *CE,
915+ const FunctionData &FData,
852916 CheckerContext &C) const {
853- auto It = CustomSinks. find (Name );
917+ auto It = findFunctionInConfig (CustomSinks, FData );
854918 if (It == CustomSinks.end ())
855919 return false ;
856920
857- const GenericTaintChecker::ArgVector &Args = It->getValue ();
921+ const auto &Value = It->second ;
922+ const GenericTaintChecker::ArgVector &Args = Value.second ;
858923 for (unsigned ArgNum : Args) {
859924 if (ArgNum >= CE->getNumArgs ())
860925 continue ;
0 commit comments