1 1.1 joerg //=== Taint.cpp - Taint tracking and basic propagation rules. ------*- C++ -*-// 2 1.1 joerg // 3 1.1 joerg // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 1.1 joerg // See https://llvm.org/LICENSE.txt for license information. 5 1.1 joerg // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 1.1 joerg // 7 1.1 joerg //===----------------------------------------------------------------------===// 8 1.1 joerg // 9 1.1 joerg // Defines basic, non-domain-specific mechanisms for tracking tainted values. 10 1.1 joerg // 11 1.1 joerg //===----------------------------------------------------------------------===// 12 1.1 joerg 13 1.1 joerg #include "Taint.h" 14 1.1 joerg #include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h" 15 1.1 joerg #include "clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h" 16 1.1 joerg 17 1.1 joerg using namespace clang; 18 1.1 joerg using namespace ento; 19 1.1 joerg using namespace taint; 20 1.1 joerg 21 1.1 joerg // Fully tainted symbols. 22 1.1 joerg REGISTER_MAP_WITH_PROGRAMSTATE(TaintMap, SymbolRef, TaintTagType) 23 1.1 joerg 24 1.1 joerg // Partially tainted symbols. 25 1.1 joerg REGISTER_MAP_FACTORY_WITH_PROGRAMSTATE(TaintedSubRegions, const SubRegion *, 26 1.1 joerg TaintTagType) 27 1.1 joerg REGISTER_MAP_WITH_PROGRAMSTATE(DerivedSymTaint, SymbolRef, TaintedSubRegions) 28 1.1 joerg 29 1.1 joerg void taint::printTaint(ProgramStateRef State, raw_ostream &Out, const char *NL, 30 1.1 joerg const char *Sep) { 31 1.1 joerg TaintMapTy TM = State->get<TaintMap>(); 32 1.1 joerg 33 1.1 joerg if (!TM.isEmpty()) 34 1.1 joerg Out << "Tainted symbols:" << NL; 35 1.1 joerg 36 1.1 joerg for (const auto &I : TM) 37 1.1 joerg Out << I.first << " : " << I.second << NL; 38 1.1 joerg } 39 1.1 joerg 40 1.1.1.2 joerg void dumpTaint(ProgramStateRef State) { printTaint(State, llvm::errs()); } 41 1.1 joerg 42 1.1 joerg ProgramStateRef taint::addTaint(ProgramStateRef State, const Stmt *S, 43 1.1 joerg const LocationContext *LCtx, 44 1.1 joerg TaintTagType Kind) { 45 1.1 joerg return addTaint(State, State->getSVal(S, LCtx), Kind); 46 1.1 joerg } 47 1.1 joerg 48 1.1 joerg ProgramStateRef taint::addTaint(ProgramStateRef State, SVal V, 49 1.1 joerg TaintTagType Kind) { 50 1.1 joerg SymbolRef Sym = V.getAsSymbol(); 51 1.1 joerg if (Sym) 52 1.1 joerg return addTaint(State, Sym, Kind); 53 1.1 joerg 54 1.1 joerg // If the SVal represents a structure, try to mass-taint all values within the 55 1.1 joerg // structure. For now it only works efficiently on lazy compound values that 56 1.1 joerg // were conjured during a conservative evaluation of a function - either as 57 1.1 joerg // return values of functions that return structures or arrays by value, or as 58 1.1 joerg // values of structures or arrays passed into the function by reference, 59 1.1 joerg // directly or through pointer aliasing. Such lazy compound values are 60 1.1 joerg // characterized by having exactly one binding in their captured store within 61 1.1 joerg // their parent region, which is a conjured symbol default-bound to the base 62 1.1 joerg // region of the parent region. 63 1.1 joerg if (auto LCV = V.getAs<nonloc::LazyCompoundVal>()) { 64 1.1 joerg if (Optional<SVal> binding = 65 1.1.1.2 joerg State->getStateManager().getStoreManager().getDefaultBinding( 66 1.1.1.2 joerg *LCV)) { 67 1.1 joerg if (SymbolRef Sym = binding->getAsSymbol()) 68 1.1 joerg return addPartialTaint(State, Sym, LCV->getRegion(), Kind); 69 1.1 joerg } 70 1.1 joerg } 71 1.1 joerg 72 1.1 joerg const MemRegion *R = V.getAsRegion(); 73 1.1 joerg return addTaint(State, R, Kind); 74 1.1 joerg } 75 1.1 joerg 76 1.1 joerg ProgramStateRef taint::addTaint(ProgramStateRef State, const MemRegion *R, 77 1.1 joerg TaintTagType Kind) { 78 1.1 joerg if (const SymbolicRegion *SR = dyn_cast_or_null<SymbolicRegion>(R)) 79 1.1 joerg return addTaint(State, SR->getSymbol(), Kind); 80 1.1 joerg return State; 81 1.1 joerg } 82 1.1 joerg 83 1.1 joerg ProgramStateRef taint::addTaint(ProgramStateRef State, SymbolRef Sym, 84 1.1 joerg TaintTagType Kind) { 85 1.1 joerg // If this is a symbol cast, remove the cast before adding the taint. Taint 86 1.1 joerg // is cast agnostic. 87 1.1 joerg while (const SymbolCast *SC = dyn_cast<SymbolCast>(Sym)) 88 1.1 joerg Sym = SC->getOperand(); 89 1.1 joerg 90 1.1 joerg ProgramStateRef NewState = State->set<TaintMap>(Sym, Kind); 91 1.1 joerg assert(NewState); 92 1.1 joerg return NewState; 93 1.1 joerg } 94 1.1 joerg 95 1.1.1.2 joerg ProgramStateRef taint::removeTaint(ProgramStateRef State, SVal V) { 96 1.1.1.2 joerg SymbolRef Sym = V.getAsSymbol(); 97 1.1.1.2 joerg if (Sym) 98 1.1.1.2 joerg return removeTaint(State, Sym); 99 1.1.1.2 joerg 100 1.1.1.2 joerg const MemRegion *R = V.getAsRegion(); 101 1.1.1.2 joerg return removeTaint(State, R); 102 1.1.1.2 joerg } 103 1.1.1.2 joerg 104 1.1.1.2 joerg ProgramStateRef taint::removeTaint(ProgramStateRef State, const MemRegion *R) { 105 1.1.1.2 joerg if (const SymbolicRegion *SR = dyn_cast_or_null<SymbolicRegion>(R)) 106 1.1.1.2 joerg return removeTaint(State, SR->getSymbol()); 107 1.1.1.2 joerg return State; 108 1.1.1.2 joerg } 109 1.1.1.2 joerg 110 1.1.1.2 joerg ProgramStateRef taint::removeTaint(ProgramStateRef State, SymbolRef Sym) { 111 1.1.1.2 joerg // If this is a symbol cast, remove the cast before adding the taint. Taint 112 1.1.1.2 joerg // is cast agnostic. 113 1.1.1.2 joerg while (const SymbolCast *SC = dyn_cast<SymbolCast>(Sym)) 114 1.1.1.2 joerg Sym = SC->getOperand(); 115 1.1.1.2 joerg 116 1.1.1.2 joerg ProgramStateRef NewState = State->remove<TaintMap>(Sym); 117 1.1.1.2 joerg assert(NewState); 118 1.1.1.2 joerg return NewState; 119 1.1.1.2 joerg } 120 1.1.1.2 joerg 121 1.1 joerg ProgramStateRef taint::addPartialTaint(ProgramStateRef State, 122 1.1 joerg SymbolRef ParentSym, 123 1.1 joerg const SubRegion *SubRegion, 124 1.1 joerg TaintTagType Kind) { 125 1.1 joerg // Ignore partial taint if the entire parent symbol is already tainted. 126 1.1 joerg if (const TaintTagType *T = State->get<TaintMap>(ParentSym)) 127 1.1 joerg if (*T == Kind) 128 1.1 joerg return State; 129 1.1 joerg 130 1.1 joerg // Partial taint applies if only a portion of the symbol is tainted. 131 1.1 joerg if (SubRegion == SubRegion->getBaseRegion()) 132 1.1 joerg return addTaint(State, ParentSym, Kind); 133 1.1 joerg 134 1.1 joerg const TaintedSubRegions *SavedRegs = State->get<DerivedSymTaint>(ParentSym); 135 1.1 joerg TaintedSubRegions::Factory &F = State->get_context<TaintedSubRegions>(); 136 1.1 joerg TaintedSubRegions Regs = SavedRegs ? *SavedRegs : F.getEmptyMap(); 137 1.1 joerg 138 1.1 joerg Regs = F.add(Regs, SubRegion, Kind); 139 1.1 joerg ProgramStateRef NewState = State->set<DerivedSymTaint>(ParentSym, Regs); 140 1.1 joerg assert(NewState); 141 1.1 joerg return NewState; 142 1.1 joerg } 143 1.1 joerg 144 1.1 joerg bool taint::isTainted(ProgramStateRef State, const Stmt *S, 145 1.1 joerg const LocationContext *LCtx, TaintTagType Kind) { 146 1.1 joerg SVal val = State->getSVal(S, LCtx); 147 1.1 joerg return isTainted(State, val, Kind); 148 1.1 joerg } 149 1.1 joerg 150 1.1 joerg bool taint::isTainted(ProgramStateRef State, SVal V, TaintTagType Kind) { 151 1.1.1.2 joerg if (SymbolRef Sym = V.getAsSymbol()) 152 1.1 joerg return isTainted(State, Sym, Kind); 153 1.1 joerg if (const MemRegion *Reg = V.getAsRegion()) 154 1.1 joerg return isTainted(State, Reg, Kind); 155 1.1 joerg return false; 156 1.1 joerg } 157 1.1 joerg 158 1.1 joerg bool taint::isTainted(ProgramStateRef State, const MemRegion *Reg, 159 1.1 joerg TaintTagType K) { 160 1.1 joerg if (!Reg) 161 1.1 joerg return false; 162 1.1 joerg 163 1.1 joerg // Element region (array element) is tainted if either the base or the offset 164 1.1 joerg // are tainted. 165 1.1 joerg if (const ElementRegion *ER = dyn_cast<ElementRegion>(Reg)) 166 1.1 joerg return isTainted(State, ER->getSuperRegion(), K) || 167 1.1 joerg isTainted(State, ER->getIndex(), K); 168 1.1 joerg 169 1.1 joerg if (const SymbolicRegion *SR = dyn_cast<SymbolicRegion>(Reg)) 170 1.1 joerg return isTainted(State, SR->getSymbol(), K); 171 1.1 joerg 172 1.1 joerg if (const SubRegion *ER = dyn_cast<SubRegion>(Reg)) 173 1.1 joerg return isTainted(State, ER->getSuperRegion(), K); 174 1.1 joerg 175 1.1 joerg return false; 176 1.1 joerg } 177 1.1 joerg 178 1.1 joerg bool taint::isTainted(ProgramStateRef State, SymbolRef Sym, TaintTagType Kind) { 179 1.1 joerg if (!Sym) 180 1.1 joerg return false; 181 1.1 joerg 182 1.1 joerg // Traverse all the symbols this symbol depends on to see if any are tainted. 183 1.1 joerg for (SymExpr::symbol_iterator SI = Sym->symbol_begin(), 184 1.1.1.2 joerg SE = Sym->symbol_end(); 185 1.1.1.2 joerg SI != SE; ++SI) { 186 1.1 joerg if (!isa<SymbolData>(*SI)) 187 1.1 joerg continue; 188 1.1 joerg 189 1.1 joerg if (const TaintTagType *Tag = State->get<TaintMap>(*SI)) { 190 1.1 joerg if (*Tag == Kind) 191 1.1 joerg return true; 192 1.1 joerg } 193 1.1 joerg 194 1.1 joerg if (const auto *SD = dyn_cast<SymbolDerived>(*SI)) { 195 1.1 joerg // If this is a SymbolDerived with a tainted parent, it's also tainted. 196 1.1 joerg if (isTainted(State, SD->getParentSymbol(), Kind)) 197 1.1 joerg return true; 198 1.1 joerg 199 1.1 joerg // If this is a SymbolDerived with the same parent symbol as another 200 1.1 joerg // tainted SymbolDerived and a region that's a sub-region of that tainted 201 1.1 joerg // symbol, it's also tainted. 202 1.1 joerg if (const TaintedSubRegions *Regs = 203 1.1 joerg State->get<DerivedSymTaint>(SD->getParentSymbol())) { 204 1.1 joerg const TypedValueRegion *R = SD->getRegion(); 205 1.1 joerg for (auto I : *Regs) { 206 1.1 joerg // FIXME: The logic to identify tainted regions could be more 207 1.1 joerg // complete. For example, this would not currently identify 208 1.1 joerg // overlapping fields in a union as tainted. To identify this we can 209 1.1 joerg // check for overlapping/nested byte offsets. 210 1.1 joerg if (Kind == I.second && R->isSubRegionOf(I.first)) 211 1.1 joerg return true; 212 1.1 joerg } 213 1.1 joerg } 214 1.1 joerg } 215 1.1 joerg 216 1.1 joerg // If memory region is tainted, data is also tainted. 217 1.1 joerg if (const auto *SRV = dyn_cast<SymbolRegionValue>(*SI)) { 218 1.1 joerg if (isTainted(State, SRV->getRegion(), Kind)) 219 1.1 joerg return true; 220 1.1 joerg } 221 1.1 joerg 222 1.1 joerg // If this is a SymbolCast from a tainted value, it's also tainted. 223 1.1 joerg if (const auto *SC = dyn_cast<SymbolCast>(*SI)) { 224 1.1 joerg if (isTainted(State, SC->getOperand(), Kind)) 225 1.1 joerg return true; 226 1.1 joerg } 227 1.1 joerg } 228 1.1 joerg 229 1.1 joerg return false; 230 1.1 joerg } 231 1.1 joerg 232 1.1 joerg PathDiagnosticPieceRef TaintBugVisitor::VisitNode(const ExplodedNode *N, 233 1.1 joerg BugReporterContext &BRC, 234 1.1 joerg PathSensitiveBugReport &BR) { 235 1.1 joerg 236 1.1 joerg // Find the ExplodedNode where the taint was first introduced 237 1.1 joerg if (!isTainted(N->getState(), V) || 238 1.1 joerg isTainted(N->getFirstPred()->getState(), V)) 239 1.1 joerg return nullptr; 240 1.1 joerg 241 1.1 joerg const Stmt *S = N->getStmtForDiagnostics(); 242 1.1 joerg if (!S) 243 1.1 joerg return nullptr; 244 1.1 joerg 245 1.1 joerg const LocationContext *NCtx = N->getLocationContext(); 246 1.1 joerg PathDiagnosticLocation L = 247 1.1 joerg PathDiagnosticLocation::createBegin(S, BRC.getSourceManager(), NCtx); 248 1.1 joerg if (!L.isValid() || !L.asLocation().isValid()) 249 1.1 joerg return nullptr; 250 1.1 joerg 251 1.1 joerg return std::make_shared<PathDiagnosticEventPiece>(L, "Taint originated here"); 252 1.1 joerg } 253