aboutsummaryrefslogtreecommitdiff
path: root/contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/Taint.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/Taint.cpp')
-rw-r--r--contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/Taint.cpp326
1 files changed, 326 insertions, 0 deletions
diff --git a/contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/Taint.cpp b/contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/Taint.cpp
new file mode 100644
index 000000000000..0bb5739db4b7
--- /dev/null
+++ b/contrib/llvm-project/clang/lib/StaticAnalyzer/Checkers/Taint.cpp
@@ -0,0 +1,326 @@
+//=== Taint.cpp - Taint tracking and basic propagation rules. ------*- C++ -*-//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// Defines basic, non-domain-specific mechanisms for tracking tainted values.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/StaticAnalyzer/Checkers/Taint.h"
+#include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h"
+#include <optional>
+
+using namespace clang;
+using namespace ento;
+using namespace taint;
+
+// Fully tainted symbols.
+REGISTER_MAP_WITH_PROGRAMSTATE(TaintMap, SymbolRef, TaintTagType)
+
+// Partially tainted symbols.
+REGISTER_MAP_FACTORY_WITH_PROGRAMSTATE(TaintedSubRegions, const SubRegion *,
+ TaintTagType)
+REGISTER_MAP_WITH_PROGRAMSTATE(DerivedSymTaint, SymbolRef, TaintedSubRegions)
+
+void taint::printTaint(ProgramStateRef State, raw_ostream &Out, const char *NL,
+ const char *Sep) {
+ TaintMapTy TM = State->get<TaintMap>();
+
+ if (!TM.isEmpty())
+ Out << "Tainted symbols:" << NL;
+
+ for (const auto &I : TM)
+ Out << I.first << " : " << I.second << NL;
+}
+
+void taint::dumpTaint(ProgramStateRef State) {
+ printTaint(State, llvm::errs());
+}
+
+ProgramStateRef taint::addTaint(ProgramStateRef State, const Stmt *S,
+ const LocationContext *LCtx,
+ TaintTagType Kind) {
+ return addTaint(State, State->getSVal(S, LCtx), Kind);
+}
+
+ProgramStateRef taint::addTaint(ProgramStateRef State, SVal V,
+ TaintTagType Kind) {
+ SymbolRef Sym = V.getAsSymbol();
+ if (Sym)
+ return addTaint(State, 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
+ // were conjured during a conservative evaluation of a function - either as
+ // return values of functions that return structures or arrays by value, or as
+ // values of structures or arrays passed into the function by reference,
+ // directly or through pointer aliasing. Such lazy compound values are
+ // characterized by having exactly one binding in their captured store within
+ // their parent region, which is a conjured symbol default-bound to the base
+ // region of the parent region.
+ if (auto LCV = V.getAs<nonloc::LazyCompoundVal>()) {
+ if (std::optional<SVal> binding =
+ State->getStateManager().getStoreManager().getDefaultBinding(
+ *LCV)) {
+ if (SymbolRef Sym = binding->getAsSymbol())
+ return addPartialTaint(State, Sym, LCV->getRegion(), Kind);
+ }
+ }
+
+ const MemRegion *R = V.getAsRegion();
+ return addTaint(State, R, Kind);
+}
+
+ProgramStateRef taint::addTaint(ProgramStateRef State, const MemRegion *R,
+ TaintTagType Kind) {
+ if (const SymbolicRegion *SR = dyn_cast_or_null<SymbolicRegion>(R))
+ return addTaint(State, SR->getSymbol(), Kind);
+ return State;
+}
+
+ProgramStateRef taint::addTaint(ProgramStateRef State, SymbolRef Sym,
+ TaintTagType Kind) {
+ // If this is a symbol cast, remove the cast before adding the taint. Taint
+ // is cast agnostic.
+ while (const SymbolCast *SC = dyn_cast<SymbolCast>(Sym))
+ Sym = SC->getOperand();
+
+ ProgramStateRef NewState = State->set<TaintMap>(Sym, Kind);
+ assert(NewState);
+ return NewState;
+}
+
+ProgramStateRef taint::removeTaint(ProgramStateRef State, SVal V) {
+ SymbolRef Sym = V.getAsSymbol();
+ if (Sym)
+ return removeTaint(State, Sym);
+
+ const MemRegion *R = V.getAsRegion();
+ return removeTaint(State, R);
+}
+
+ProgramStateRef taint::removeTaint(ProgramStateRef State, const MemRegion *R) {
+ if (const SymbolicRegion *SR = dyn_cast_or_null<SymbolicRegion>(R))
+ return removeTaint(State, SR->getSymbol());
+ return State;
+}
+
+ProgramStateRef taint::removeTaint(ProgramStateRef State, SymbolRef Sym) {
+ // If this is a symbol cast, remove the cast before adding the taint. Taint
+ // is cast agnostic.
+ while (const SymbolCast *SC = dyn_cast<SymbolCast>(Sym))
+ Sym = SC->getOperand();
+
+ ProgramStateRef NewState = State->remove<TaintMap>(Sym);
+ assert(NewState);
+ return NewState;
+}
+
+ProgramStateRef taint::addPartialTaint(ProgramStateRef State,
+ SymbolRef ParentSym,
+ const SubRegion *SubRegion,
+ TaintTagType Kind) {
+ // Ignore partial taint if the entire parent symbol is already tainted.
+ if (const TaintTagType *T = State->get<TaintMap>(ParentSym))
+ if (*T == Kind)
+ return State;
+
+ // Partial taint applies if only a portion of the symbol is tainted.
+ if (SubRegion == SubRegion->getBaseRegion())
+ return addTaint(State, ParentSym, Kind);
+
+ const TaintedSubRegions *SavedRegs = State->get<DerivedSymTaint>(ParentSym);
+ TaintedSubRegions::Factory &F = State->get_context<TaintedSubRegions>();
+ TaintedSubRegions Regs = SavedRegs ? *SavedRegs : F.getEmptyMap();
+
+ Regs = F.add(Regs, SubRegion, Kind);
+ ProgramStateRef NewState = State->set<DerivedSymTaint>(ParentSym, Regs);
+ assert(NewState);
+ return NewState;
+}
+
+bool taint::isTainted(ProgramStateRef State, const Stmt *S,
+ const LocationContext *LCtx, TaintTagType Kind) {
+ return !getTaintedSymbolsImpl(State, S, LCtx, Kind, /*ReturnFirstOnly=*/true)
+ .empty();
+}
+
+bool taint::isTainted(ProgramStateRef State, SVal V, TaintTagType Kind) {
+ return !getTaintedSymbolsImpl(State, V, Kind, /*ReturnFirstOnly=*/true)
+ .empty();
+}
+
+bool taint::isTainted(ProgramStateRef State, const MemRegion *Reg,
+ TaintTagType K) {
+ return !getTaintedSymbolsImpl(State, Reg, K, /*ReturnFirstOnly=*/true)
+ .empty();
+}
+
+bool taint::isTainted(ProgramStateRef State, SymbolRef Sym, TaintTagType Kind) {
+ return !getTaintedSymbolsImpl(State, Sym, Kind, /*ReturnFirstOnly=*/true)
+ .empty();
+}
+
+std::vector<SymbolRef> taint::getTaintedSymbols(ProgramStateRef State,
+ const Stmt *S,
+ const LocationContext *LCtx,
+ TaintTagType Kind) {
+ return getTaintedSymbolsImpl(State, S, LCtx, Kind, /*ReturnFirstOnly=*/false);
+}
+
+std::vector<SymbolRef> taint::getTaintedSymbols(ProgramStateRef State, SVal V,
+ TaintTagType Kind) {
+ return getTaintedSymbolsImpl(State, V, Kind, /*ReturnFirstOnly=*/false);
+}
+
+std::vector<SymbolRef> taint::getTaintedSymbols(ProgramStateRef State,
+ SymbolRef Sym,
+ TaintTagType Kind) {
+ return getTaintedSymbolsImpl(State, Sym, Kind, /*ReturnFirstOnly=*/false);
+}
+
+std::vector<SymbolRef> taint::getTaintedSymbols(ProgramStateRef State,
+ const MemRegion *Reg,
+ TaintTagType Kind) {
+ return getTaintedSymbolsImpl(State, Reg, Kind, /*ReturnFirstOnly=*/false);
+}
+
+std::vector<SymbolRef> taint::getTaintedSymbolsImpl(ProgramStateRef State,
+ const Stmt *S,
+ const LocationContext *LCtx,
+ TaintTagType Kind,
+ bool returnFirstOnly) {
+ SVal val = State->getSVal(S, LCtx);
+ return getTaintedSymbolsImpl(State, val, Kind, returnFirstOnly);
+}
+
+std::vector<SymbolRef> taint::getTaintedSymbolsImpl(ProgramStateRef State,
+ SVal V, TaintTagType Kind,
+ bool returnFirstOnly) {
+ if (SymbolRef Sym = V.getAsSymbol())
+ return getTaintedSymbolsImpl(State, Sym, Kind, returnFirstOnly);
+ if (const MemRegion *Reg = V.getAsRegion())
+ return getTaintedSymbolsImpl(State, Reg, Kind, returnFirstOnly);
+ return {};
+}
+
+std::vector<SymbolRef> taint::getTaintedSymbolsImpl(ProgramStateRef State,
+ const MemRegion *Reg,
+ TaintTagType K,
+ bool returnFirstOnly) {
+ std::vector<SymbolRef> TaintedSymbols;
+ if (!Reg)
+ return TaintedSymbols;
+
+ // Element region (array element) is tainted if the offset is tainted.
+ if (const ElementRegion *ER = dyn_cast<ElementRegion>(Reg)) {
+ std::vector<SymbolRef> TaintedIndex =
+ getTaintedSymbolsImpl(State, ER->getIndex(), K, returnFirstOnly);
+ llvm::append_range(TaintedSymbols, TaintedIndex);
+ if (returnFirstOnly && !TaintedSymbols.empty())
+ return TaintedSymbols; // return early if needed
+ }
+
+ // Symbolic region is tainted if the corresponding symbol is tainted.
+ if (const SymbolicRegion *SR = dyn_cast<SymbolicRegion>(Reg)) {
+ std::vector<SymbolRef> TaintedRegions =
+ getTaintedSymbolsImpl(State, SR->getSymbol(), K, returnFirstOnly);
+ llvm::append_range(TaintedSymbols, TaintedRegions);
+ if (returnFirstOnly && !TaintedSymbols.empty())
+ return TaintedSymbols; // return early if needed
+ }
+
+ // Any subregion (including Element and Symbolic regions) is tainted if its
+ // super-region is tainted.
+ if (const SubRegion *ER = dyn_cast<SubRegion>(Reg)) {
+ std::vector<SymbolRef> TaintedSubRegions =
+ getTaintedSymbolsImpl(State, ER->getSuperRegion(), K, returnFirstOnly);
+ llvm::append_range(TaintedSymbols, TaintedSubRegions);
+ if (returnFirstOnly && !TaintedSymbols.empty())
+ return TaintedSymbols; // return early if needed
+ }
+
+ return TaintedSymbols;
+}
+
+std::vector<SymbolRef> taint::getTaintedSymbolsImpl(ProgramStateRef State,
+ SymbolRef Sym,
+ TaintTagType Kind,
+ bool returnFirstOnly) {
+ std::vector<SymbolRef> TaintedSymbols;
+ if (!Sym)
+ return TaintedSymbols;
+
+ // HACK:https://discourse.llvm.org/t/rfc-make-istainted-and-complex-symbols-friends/79570
+ if (const auto &Opts = State->getAnalysisManager().getAnalyzerOptions();
+ Sym->computeComplexity() > Opts.MaxTaintedSymbolComplexity) {
+ return {};
+ }
+
+ // Traverse all the symbols this symbol depends on to see if any are tainted.
+ for (SymbolRef SubSym : Sym->symbols()) {
+ if (!isa<SymbolData>(SubSym))
+ continue;
+
+ if (const TaintTagType *Tag = State->get<TaintMap>(SubSym)) {
+ if (*Tag == Kind) {
+ TaintedSymbols.push_back(SubSym);
+ if (returnFirstOnly)
+ return TaintedSymbols; // return early if needed
+ }
+ }
+
+ if (const auto *SD = dyn_cast<SymbolDerived>(SubSym)) {
+ // If this is a SymbolDerived with a tainted parent, it's also tainted.
+ std::vector<SymbolRef> TaintedParents = getTaintedSymbolsImpl(
+ State, SD->getParentSymbol(), Kind, returnFirstOnly);
+ llvm::append_range(TaintedSymbols, TaintedParents);
+ if (returnFirstOnly && !TaintedSymbols.empty())
+ return TaintedSymbols; // return early if needed
+
+ // If this is a SymbolDerived with the same parent symbol as another
+ // tainted SymbolDerived and a region that's a sub-region of that
+ // tainted symbol, it's also tainted.
+ if (const TaintedSubRegions *Regs =
+ State->get<DerivedSymTaint>(SD->getParentSymbol())) {
+ const TypedValueRegion *R = SD->getRegion();
+ for (auto I : *Regs) {
+ // FIXME: The logic to identify tainted regions could be more
+ // complete. For example, this would not currently identify
+ // overlapping fields in a union as tainted. To identify this we can
+ // check for overlapping/nested byte offsets.
+ if (Kind == I.second && R->isSubRegionOf(I.first)) {
+ TaintedSymbols.push_back(SD->getParentSymbol());
+ if (returnFirstOnly && !TaintedSymbols.empty())
+ return TaintedSymbols; // return early if needed
+ }
+ }
+ }
+ }
+
+ // If memory region is tainted, data is also tainted.
+ if (const auto *SRV = dyn_cast<SymbolRegionValue>(SubSym)) {
+ std::vector<SymbolRef> TaintedRegions =
+ getTaintedSymbolsImpl(State, SRV->getRegion(), Kind, returnFirstOnly);
+ llvm::append_range(TaintedSymbols, TaintedRegions);
+ if (returnFirstOnly && !TaintedSymbols.empty())
+ return TaintedSymbols; // return early if needed
+ }
+
+ // If this is a SymbolCast from a tainted value, it's also tainted.
+ if (const auto *SC = dyn_cast<SymbolCast>(SubSym)) {
+ std::vector<SymbolRef> TaintedCasts =
+ getTaintedSymbolsImpl(State, SC->getOperand(), Kind, returnFirstOnly);
+ llvm::append_range(TaintedSymbols, TaintedCasts);
+ if (returnFirstOnly && !TaintedSymbols.empty())
+ return TaintedSymbols; // return early if needed
+ }
+ }
+ return TaintedSymbols;
+}