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