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