boga95 updated this revision to Diff 191668.
boga95 retitled this revision from "[analyzer] Make GenericTaintChecker 
configurable" to "[analyzer] Add custom filter functions for 
GenericTaintChecker".

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D59516/new/

https://reviews.llvm.org/D59516

Files:
  include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h
  include/clang/StaticAnalyzer/Core/PathSensitive/TaintTag.h
  lib/StaticAnalyzer/Checkers/GenericTaintChecker.cpp
  lib/StaticAnalyzer/Core/ProgramState.cpp
  test/Analysis/taint-generic.c

Index: test/Analysis/taint-generic.c
===================================================================
--- test/Analysis/taint-generic.c
+++ test/Analysis/taint-generic.c
@@ -296,13 +296,13 @@
     *(volatile int *) 0; // no-warning
 }
 
-
 // Test configuration
 int mySource1();
 void mySource2(int*);
 void myScanf(const char*, ...);
 int myPropagator(int, int*);
 int mySnprintf(char*, size_t, const char*, ...);
+void myFilter(int*);
 void mySink(int, int, int);
 
 void testConfigurationSources1() {
@@ -329,6 +329,12 @@
   Buffer[y] = 1; // expected-warning {{Out of bound memory access }}
 }
 
+void testConfigurationFilter() {
+  int x = mySource1();
+  myFilter(&x);
+  Buffer[x] = 1; // no-warning
+}
+
 void testConfigurationSinks() {
   int x = mySource1();
   mySink(x, 1, 2); // expected-warning {{Untrusted data is passed to a user defined sink}}
Index: lib/StaticAnalyzer/Core/ProgramState.cpp
===================================================================
--- lib/StaticAnalyzer/Core/ProgramState.cpp
+++ lib/StaticAnalyzer/Core/ProgramState.cpp
@@ -658,20 +658,20 @@
   return true;
 }
 
-ProgramStateRef ProgramState::addTaint(const Stmt *S,
+ProgramStateRef ProgramState::setTaint(const Stmt *S,
                                            const LocationContext *LCtx,
                                            TaintTagType Kind) const {
   if (const Expr *E = dyn_cast_or_null<Expr>(S))
     S = E->IgnoreParens();
 
-  return addTaint(getSVal(S, LCtx), Kind);
+  return setTaint(getSVal(S, LCtx), Kind);
 }
 
-ProgramStateRef ProgramState::addTaint(SVal V,
+ProgramStateRef ProgramState::setTaint(SVal V,
                                        TaintTagType Kind) const {
   SymbolRef Sym = V.getAsSymbol();
   if (Sym)
-    return addTaint(Sym, Kind);
+    return setTaint(Sym, Kind);
 
   // If the SVal represents a structure, try to mass-taint all values within the
   // structure. For now it only works efficiently on lazy compound values that
@@ -685,22 +685,22 @@
   if (auto LCV = V.getAs<nonloc::LazyCompoundVal>()) {
     if (Optional<SVal> binding = getStateManager().StoreMgr->getDefaultBinding(*LCV)) {
       if (SymbolRef Sym = binding->getAsSymbol())
-        return addPartialTaint(Sym, LCV->getRegion(), Kind);
+        return setPartialTaint(Sym, LCV->getRegion(), Kind);
     }
   }
 
   const MemRegion *R = V.getAsRegion();
-  return addTaint(R, Kind);
+  return setTaint(R, Kind);
 }
 
-ProgramStateRef ProgramState::addTaint(const MemRegion *R,
+ProgramStateRef ProgramState::setTaint(const MemRegion *R,
                                            TaintTagType Kind) const {
   if (const SymbolicRegion *SR = dyn_cast_or_null<SymbolicRegion>(R))
-    return addTaint(SR->getSymbol(), Kind);
+    return setTaint(SR->getSymbol(), Kind);
   return this;
 }
 
-ProgramStateRef ProgramState::addTaint(SymbolRef Sym,
+ProgramStateRef ProgramState::setTaint(SymbolRef Sym,
                                            TaintTagType Kind) const {
   // If this is a symbol cast, remove the cast before adding the taint. Taint
   // is cast agnostic.
@@ -712,7 +712,7 @@
   return NewState;
 }
 
-ProgramStateRef ProgramState::addPartialTaint(SymbolRef ParentSym,
+ProgramStateRef ProgramState::setPartialTaint(SymbolRef ParentSym,
                                               const SubRegion *SubRegion,
                                               TaintTagType Kind) const {
   // Ignore partial taint if the entire parent symbol is already tainted.
@@ -721,7 +721,7 @@
 
   // Partial taint applies if only a portion of the symbol is tainted.
   if (SubRegion == SubRegion->getBaseRegion())
-    return addTaint(ParentSym, Kind);
+    return setTaint(ParentSym, Kind);
 
   const TaintedSubRegions *SavedRegs = get<DerivedSymTaint>(ParentSym);
   TaintedSubRegions Regs =
@@ -779,7 +779,7 @@
       continue;
 
     if (const TaintTagType *Tag = get<TaintMap>(*SI)) {
-      if (*Tag == Kind)
+      if (*Tag != TaintTagNotTainted && *Tag == Kind)
         return true;
     }
 
Index: lib/StaticAnalyzer/Checkers/GenericTaintChecker.cpp
===================================================================
--- lib/StaticAnalyzer/Checkers/GenericTaintChecker.cpp
+++ lib/StaticAnalyzer/Checkers/GenericTaintChecker.cpp
@@ -31,6 +31,28 @@
 using namespace ento;
 
 namespace {
+/// A struct to store tainted argument and taint type as a pair in the program
+/// state.
+struct TaintArgTypePair {
+  unsigned Arg;
+  TaintTagType TagType;
+
+  bool operator==(const TaintArgTypePair &X) const {
+    return Arg == X.Arg && TagType == X.TagType;
+  }
+
+  bool operator<(const TaintArgTypePair &X) const {
+    if (Arg != X.Arg)
+      return Arg < X.Arg;
+    return TagType < X.TagType;
+  }
+
+  void Profile(llvm::FoldingSetNodeID &ID) const {
+    ID.AddInteger(Arg);
+    ID.AddInteger(TagType);
+  }
+};
+
 class GenericTaintChecker
     : public Checker<check::PostStmt<CallExpr>, check::PreStmt<CallExpr>> {
 public:
@@ -83,10 +105,16 @@
 
   /// Catch taint related bugs. Check if tainted data is passed to a
   /// system call etc.
-  bool checkPre(const CallExpr *CE, CheckerContext &C) const;
+  bool checkPre(const CallExpr *CE, const FunctionDecl *FDecl, StringRef Name,
+                CheckerContext &C) const;
 
   /// Add taint sources on a pre-visit.
-  void addSourcesPre(const CallExpr *CE, CheckerContext &C) const;
+  bool addSourcesPre(const CallExpr *CE, const FunctionDecl *FDecl,
+                     StringRef Name, CheckerContext &C) const;
+
+  /// Mark filter's arguments not tainted on a pre-visit.
+  bool addFiltersPre(const CallExpr *CE, StringRef Name,
+                     CheckerContext &C) const;
 
   /// Propagate taint generated at pre-visit.
   bool propagateFromPre(const CallExpr *CE, CheckerContext &C) const;
@@ -288,7 +316,7 @@
 /// to the call post-visit. The values are unsigned integers, which are either
 /// ReturnValueIndex, or indexes of the pointer/reference argument, which
 /// points to data, which should be tainted on return.
-REGISTER_SET_WITH_PROGRAMSTATE(TaintArgsOnPostVisit, unsigned)
+REGISTER_SET_WITH_PROGRAMSTATE(TaintArgsOnPostVisit, TaintArgTypePair)
 
 void GenericTaintChecker::getConfiguration(StringRef ConfigFile) {
   if (ConfigFile.trim().empty())
@@ -437,14 +465,25 @@
 
 void GenericTaintChecker::checkPreStmt(const CallExpr *CE,
                                        CheckerContext &C) const {
+  const FunctionDecl *FDecl = C.getCalleeDecl(CE);
+  if (!FDecl || FDecl->getKind() != Decl::Function)
+    return;
+
+  StringRef Name = C.getCalleeName(FDecl);
+  if (Name.empty())
+    return;
+
   // Check for taintedness related errors first: system call, uncontrolled
   // format string, tainted buffer size.
-  if (checkPre(CE, C))
+  if (checkPre(CE, FDecl, Name, C))
     return;
 
   // Marks the function's arguments and/or return value tainted if it present in
   // the list.
-  addSourcesPre(CE, C);
+  if (addSourcesPre(CE, FDecl, Name, C))
+    return;
+
+  addFiltersPre(CE, Name, C);
 }
 
 void GenericTaintChecker::checkPostStmt(const CallExpr *CE,
@@ -454,31 +493,45 @@
   propagateFromPre(CE, C);
 }
 
-void GenericTaintChecker::addSourcesPre(const CallExpr *CE,
+bool GenericTaintChecker::addSourcesPre(const CallExpr *CE,
+                                        const FunctionDecl *FDecl,
+                                        StringRef Name,
                                         CheckerContext &C) const {
-  ProgramStateRef State = nullptr;
-  const FunctionDecl *FDecl = C.getCalleeDecl(CE);
-  if (!FDecl || FDecl->getKind() != Decl::Function)
-    return;
-
-  StringRef Name = C.getCalleeName(FDecl);
-  if (Name.empty())
-    return;
-
   // First, try generating a propagation rule for this function.
   TaintPropagationRule Rule =
       TaintPropagationRule::getTaintPropagationRule(FDecl, Name, C);
   if (!Rule.isNull()) {
-    State = Rule.process(CE, C);
+    ProgramStateRef State = Rule.process(CE, C);
     if (!State)
-      return;
+      return false;
     C.addTransition(State);
-    return;
   }
+  return true;
+}
 
-  if (!State)
-    return;
-  C.addTransition(State);
+bool GenericTaintChecker::addFiltersPre(const CallExpr *CE, StringRef Name,
+                                        CheckerContext &C) const {
+  auto It = CustomFilters.find(Name);
+  if (It == CustomFilters.end())
+    return false;
+
+  ProgramStateRef State = C.getState();
+  const GenericTaintChecker::ArgVector &Args = It->getValue();
+  for (unsigned ArgNum : Args) {
+    if (ArgNum >= CE->getNumArgs()) {
+      llvm::errs() << "Skip out of bound filter Arg: " << Name << ":" << ArgNum
+                   << '\n';
+      continue;
+    }
+
+    State = State->add<TaintArgsOnPostVisit>({ArgNum, TaintTagNotTainted});
+  }
+
+  if (State != C.getState()) {
+    C.addTransition(State);
+    return true;
+  }
+  return false;
 }
 
 bool GenericTaintChecker::propagateFromPre(const CallExpr *CE,
@@ -492,10 +545,12 @@
   if (TaintArgs.isEmpty())
     return false;
 
-  for (unsigned ArgNum : TaintArgs) {
+  for (auto ArgTypePair : TaintArgs) {
+    unsigned ArgNum = ArgTypePair.Arg;
+    TaintTagType TagType = ArgTypePair.TagType;
     // Special handling for the tainted return value.
     if (ArgNum == ReturnValueIndex) {
-      State = State->addTaint(CE, C.getLocationContext());
+      State = State->setTaint(CE, C.getLocationContext(), TagType);
       continue;
     }
 
@@ -506,7 +561,7 @@
     const Expr *Arg = CE->getArg(ArgNum);
     Optional<SVal> V = getPointedToSVal(C, Arg);
     if (V)
-      State = State->addTaint(*V);
+      State = State->setTaint(*V, TagType);
   }
 
   // Clear up the taint info from the state.
@@ -520,19 +575,12 @@
 }
 
 bool GenericTaintChecker::checkPre(const CallExpr *CE,
+                                   const FunctionDecl *FDecl, StringRef Name,
                                    CheckerContext &C) const {
 
   if (checkUncontrolledFormatString(CE, C))
     return true;
 
-  const FunctionDecl *FDecl = C.getCalleeDecl(CE);
-  if (!FDecl || FDecl->getKind() != Decl::Function)
-    return false;
-
-  StringRef Name = C.getCalleeName(FDecl);
-  if (Name.empty())
-    return false;
-
   if (checkSystemCall(CE, Name, C))
     return true;
 
@@ -607,7 +655,8 @@
   for (unsigned ArgNum : DstArgs) {
     // Should mark the return value?
     if (ArgNum == ReturnValueIndex) {
-      State = State->add<TaintArgsOnPostVisit>(ReturnValueIndex);
+      State =
+          State->add<TaintArgsOnPostVisit>({ReturnValueIndex, TaintTagGeneric});
       continue;
     }
 
@@ -619,7 +668,7 @@
     }
 
     // Mark the given argument.
-    State = State->add<TaintArgsOnPostVisit>(ArgNum);
+    State = State->add<TaintArgsOnPostVisit>({ArgNum, TaintTagGeneric});
   }
 
   // Mark all variadic arguments tainted if present.
@@ -635,7 +684,7 @@
       QualType PType = ArgTy->getPointeeType();
       if ((!PType.isNull() && !PType.isConstQualified()) ||
           (ArgTy->isReferenceType() && !Arg->getType().isConstQualified()))
-        State = State->add<TaintArgsOnPostVisit>(i);
+        State = State->add<TaintArgsOnPostVisit>({i, TaintTagGeneric});
     }
   }
 
@@ -825,7 +874,7 @@
   if (It == CustomSinks.end())
     return false;
 
-  const GenericTaintChecker::ArgVector& Args = It->getValue();
+  const GenericTaintChecker::ArgVector &Args = It->getValue();
   for (unsigned ArgNum : Args) {
     if (ArgNum >= CE->getNumArgs()) {
       llvm::errs() << "Skip out of bound sink Arg: " << Name << ":" << ArgNum
Index: include/clang/StaticAnalyzer/Core/PathSensitive/TaintTag.h
===================================================================
--- include/clang/StaticAnalyzer/Core/PathSensitive/TaintTag.h
+++ include/clang/StaticAnalyzer/Core/PathSensitive/TaintTag.h
@@ -21,7 +21,8 @@
 /// taint.
 using TaintTagType = unsigned;
 
-static const TaintTagType TaintTagGeneric = 0;
+static const TaintTagType TaintTagNotTainted = 0;
+static const TaintTagType TaintTagGeneric = 1;
 
 } // namespace ento
 } // namespace clang
Index: include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h
===================================================================
--- include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h
+++ include/clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h
@@ -369,27 +369,27 @@
 
   /// Create a new state in which the statement is marked as tainted.
   LLVM_NODISCARD ProgramStateRef
-  addTaint(const Stmt *S, const LocationContext *LCtx,
+  setTaint(const Stmt *S, const LocationContext *LCtx,
            TaintTagType Kind = TaintTagGeneric) const;
 
   /// Create a new state in which the value is marked as tainted.
   LLVM_NODISCARD ProgramStateRef
-  addTaint(SVal V, TaintTagType Kind = TaintTagGeneric) const;
+  setTaint(SVal V, TaintTagType Kind = TaintTagGeneric) const;
 
   /// Create a new state in which the symbol is marked as tainted.
-  LLVM_NODISCARD ProgramStateRef addTaint(SymbolRef S,
+  LLVM_NODISCARD ProgramStateRef setTaint(SymbolRef S,
                                TaintTagType Kind = TaintTagGeneric) const;
 
   /// Create a new state in which the region symbol is marked as tainted.
   LLVM_NODISCARD ProgramStateRef
-  addTaint(const MemRegion *R, TaintTagType Kind = TaintTagGeneric) const;
+  setTaint(const MemRegion *R, TaintTagType Kind = TaintTagGeneric) const;
 
   /// Create a new state in a which a sub-region of a given symbol is tainted.
   /// This might be necessary when referring to regions that can not have an
   /// individual symbol, e.g. if they are represented by the default binding of
   /// a LazyCompoundVal.
   LLVM_NODISCARD ProgramStateRef
-  addPartialTaint(SymbolRef ParentSym, const SubRegion *SubRegion,
+  setPartialTaint(SymbolRef ParentSym, const SubRegion *SubRegion,
                   TaintTagType Kind = TaintTagGeneric) const;
 
   /// Check if the statement is tainted in the current state.
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to