clang 23.0.0git
Taint.cpp
Go to the documentation of this file.
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
17#include <optional>
18
19using namespace clang;
20using namespace ento;
21using namespace taint;
22
23// Fully tainted symbols.
25
26// Partially tainted symbols.
29REGISTER_MAP_WITH_PROGRAMSTATE(DerivedSymTaint, SymbolRef, TaintedSubRegions)
30
31void taint::printTaint(ProgramStateRef State, raw_ostream &Out, const char *NL,
32 const char *Sep) {
33 TaintMapTy TM = State->get<TaintMap>();
34
35 if (!TM.isEmpty())
36 Out << "Tainted symbols:" << NL;
37
38 for (const auto &I : TM)
39 Out << I.first << " : " << I.second << NL;
40}
41
43 printTaint(State, llvm::errs());
44}
45
47 const LocationContext *LCtx,
48 TaintTagType Kind) {
49 return addTaint(State, State->getSVal(E, LCtx), Kind);
50}
51
53 TaintTagType Kind) {
54 SymbolRef Sym = V.getAsSymbol();
55 if (Sym)
56 return addTaint(State, Sym, Kind);
57
58 // If the SVal represents a structure, try to mass-taint all values within the
59 // structure. For now it only works efficiently on lazy compound values that
60 // were conjured during a conservative evaluation of a function - either as
61 // return values of functions that return structures or arrays by value, or as
62 // values of structures or arrays passed into the function by reference,
63 // directly or through pointer aliasing. Such lazy compound values are
64 // characterized by having exactly one binding in their captured store within
65 // their parent region, which is a conjured symbol default-bound to the base
66 // region of the parent region.
67 if (auto LCV = V.getAs<nonloc::LazyCompoundVal>()) {
68 if (std::optional<SVal> binding =
69 State->getStateManager().getStoreManager().getDefaultBinding(
70 *LCV)) {
71 if (SymbolRef Sym = binding->getAsSymbol())
72 return addPartialTaint(State, Sym, LCV->getRegion(), Kind);
73 }
74 }
75
76 const MemRegion *R = V.getAsRegion();
77 return addTaint(State, R, Kind);
78}
79
81 TaintTagType Kind) {
82 if (const SymbolicRegion *SR = dyn_cast_or_null<SymbolicRegion>(R))
83 return addTaint(State, SR->getSymbol(), Kind);
84 return State;
85}
86
88 TaintTagType Kind) {
89 // If this is a symbol cast, remove the cast before adding the taint. Taint
90 // is cast agnostic.
91 while (const SymbolCast *SC = dyn_cast<SymbolCast>(Sym))
92 Sym = SC->getOperand();
93
94 ProgramStateRef NewState = State->set<TaintMap>(Sym, Kind);
95 assert(NewState);
96 return NewState;
97}
98
100 SymbolRef Sym = V.getAsSymbol();
101 if (Sym)
102 return removeTaint(State, Sym);
103
104 const MemRegion *R = V.getAsRegion();
105 return removeTaint(State, R);
106}
107
109 if (const SymbolicRegion *SR = dyn_cast_or_null<SymbolicRegion>(R))
110 return removeTaint(State, SR->getSymbol());
111 return State;
112}
113
115 // If this is a symbol cast, remove the cast before adding the taint. Taint
116 // is cast agnostic.
117 while (const SymbolCast *SC = dyn_cast<SymbolCast>(Sym))
118 Sym = SC->getOperand();
119
120 ProgramStateRef NewState = State->remove<TaintMap>(Sym);
121 assert(NewState);
122 return NewState;
123}
124
126 SymbolRef ParentSym,
127 const SubRegion *SubRegion,
128 TaintTagType Kind) {
129 // Ignore partial taint if the entire parent symbol is already tainted.
130 if (const TaintTagType *T = State->get<TaintMap>(ParentSym))
131 if (*T == Kind)
132 return State;
133
134 // Partial taint applies if only a portion of the symbol is tainted.
136 return addTaint(State, ParentSym, Kind);
137
138 const TaintedSubRegions *SavedRegs = State->get<DerivedSymTaint>(ParentSym);
139 TaintedSubRegions::Factory &F = State->get_context<TaintedSubRegions>();
140 TaintedSubRegions Regs = SavedRegs ? *SavedRegs : F.getEmptyMap();
141
142 Regs = F.add(Regs, SubRegion, Kind);
143 ProgramStateRef NewState = State->set<DerivedSymTaint>(ParentSym, Regs);
144 assert(NewState);
145 return NewState;
146}
147
149 const LocationContext *LCtx, TaintTagType Kind) {
150 return !getTaintedSymbolsImpl(State, E, LCtx, Kind, /*ReturnFirstOnly=*/true)
151 .empty();
152}
153
155 return !getTaintedSymbolsImpl(State, V, Kind, /*ReturnFirstOnly=*/true)
156 .empty();
157}
158
160 TaintTagType K) {
161 return !getTaintedSymbolsImpl(State, Reg, K, /*ReturnFirstOnly=*/true)
162 .empty();
163}
164
166 return !getTaintedSymbolsImpl(State, Sym, Kind, /*ReturnFirstOnly=*/true)
167 .empty();
168}
169
170std::vector<SymbolRef> taint::getTaintedSymbols(ProgramStateRef State,
171 const Expr *E,
172 const LocationContext *LCtx,
173 TaintTagType Kind) {
174 return getTaintedSymbolsImpl(State, E, LCtx, Kind,
175 /*ReturnFirstOnly=*/false);
176}
177
178std::vector<SymbolRef> taint::getTaintedSymbols(ProgramStateRef State, SVal V,
179 TaintTagType Kind) {
180 return getTaintedSymbolsImpl(State, V, Kind, /*ReturnFirstOnly=*/false);
181}
182
183std::vector<SymbolRef> taint::getTaintedSymbols(ProgramStateRef State,
184 SymbolRef Sym,
185 TaintTagType Kind) {
186 return getTaintedSymbolsImpl(State, Sym, Kind, /*ReturnFirstOnly=*/false);
187}
188
189std::vector<SymbolRef> taint::getTaintedSymbols(ProgramStateRef State,
190 const MemRegion *Reg,
191 TaintTagType Kind) {
192 return getTaintedSymbolsImpl(State, Reg, Kind, /*ReturnFirstOnly=*/false);
193}
194
196 const Expr *E,
197 const LocationContext *LCtx,
198 TaintTagType Kind,
199 bool returnFirstOnly) {
200 SVal val = State->getSVal(E, LCtx);
201 return getTaintedSymbolsImpl(State, val, Kind, returnFirstOnly);
202}
203
205 SVal V, TaintTagType Kind,
206 bool returnFirstOnly) {
207 if (SymbolRef Sym = V.getAsSymbol())
208 return getTaintedSymbolsImpl(State, Sym, Kind, returnFirstOnly);
209 if (const MemRegion *Reg = V.getAsRegion())
210 return getTaintedSymbolsImpl(State, Reg, Kind, returnFirstOnly);
211
212 if (auto LCV = V.getAs<nonloc::LazyCompoundVal>()) {
213 StoreManager &StoreMgr = State->getStateManager().getStoreManager();
214 if (auto DefaultVal = StoreMgr.getDefaultBinding(*LCV)) {
215 return getTaintedSymbolsImpl(State, *DefaultVal, Kind, returnFirstOnly);
216 }
217 }
218
219 return {};
220}
221
223 const MemRegion *Reg,
224 TaintTagType K,
225 bool returnFirstOnly) {
226 std::vector<SymbolRef> TaintedSymbols;
227 if (!Reg)
228 return TaintedSymbols;
229
230 // Element region (array element) is tainted if the offset is tainted.
231 if (const ElementRegion *ER = dyn_cast<ElementRegion>(Reg)) {
232 std::vector<SymbolRef> TaintedIndex =
233 getTaintedSymbolsImpl(State, ER->getIndex(), K, returnFirstOnly);
234 llvm::append_range(TaintedSymbols, TaintedIndex);
235 if (returnFirstOnly && !TaintedSymbols.empty())
236 return TaintedSymbols; // return early if needed
237 }
238
239 // Symbolic region is tainted if the corresponding symbol is tainted.
240 if (const SymbolicRegion *SR = dyn_cast<SymbolicRegion>(Reg)) {
241 std::vector<SymbolRef> TaintedRegions =
242 getTaintedSymbolsImpl(State, SR->getSymbol(), K, returnFirstOnly);
243 llvm::append_range(TaintedSymbols, TaintedRegions);
244 if (returnFirstOnly && !TaintedSymbols.empty())
245 return TaintedSymbols; // return early if needed
246 }
247
248 // Any subregion (including Element and Symbolic regions) is tainted if its
249 // super-region is tainted.
250 if (const SubRegion *ER = dyn_cast<SubRegion>(Reg)) {
251 std::vector<SymbolRef> TaintedSubRegions =
252 getTaintedSymbolsImpl(State, ER->getSuperRegion(), K, returnFirstOnly);
253 llvm::append_range(TaintedSymbols, TaintedSubRegions);
254 if (returnFirstOnly && !TaintedSymbols.empty())
255 return TaintedSymbols; // return early if needed
256 }
257
258 return TaintedSymbols;
259}
260
262 SymbolRef Sym,
263 TaintTagType Kind,
264 bool returnFirstOnly) {
265 std::vector<SymbolRef> TaintedSymbols;
266 if (!Sym)
267 return TaintedSymbols;
268
269 // HACK:https://discourse.llvm.org/t/rfc-make-istainted-and-complex-symbols-friends/79570
270 if (const auto &Opts = State->getAnalysisManager().getAnalyzerOptions();
271 Sym->computeComplexity() > Opts.MaxTaintedSymbolComplexity) {
272 return {};
273 }
274
275 // Traverse all the symbols this symbol depends on to see if any are tainted.
276 for (SymbolRef SubSym : Sym->symbols()) {
277 if (!isa<SymbolData>(SubSym))
278 continue;
279
280 if (const TaintTagType *Tag = State->get<TaintMap>(SubSym)) {
281 if (*Tag == Kind) {
282 TaintedSymbols.push_back(SubSym);
283 if (returnFirstOnly)
284 return TaintedSymbols; // return early if needed
285 }
286 }
287
288 if (const auto *SD = dyn_cast<SymbolDerived>(SubSym)) {
289 // If this is a SymbolDerived with a tainted parent, it's also tainted.
290 std::vector<SymbolRef> TaintedParents = getTaintedSymbolsImpl(
291 State, SD->getParentSymbol(), Kind, returnFirstOnly);
292 llvm::append_range(TaintedSymbols, TaintedParents);
293 if (returnFirstOnly && !TaintedSymbols.empty())
294 return TaintedSymbols; // return early if needed
295
296 // If this is a SymbolDerived with the same parent symbol as another
297 // tainted SymbolDerived and a region that's a sub-region of that
298 // tainted symbol, it's also tainted.
299 if (const TaintedSubRegions *Regs =
300 State->get<DerivedSymTaint>(SD->getParentSymbol())) {
301 const TypedValueRegion *R = SD->getRegion();
302 for (auto I : *Regs) {
303 // FIXME: The logic to identify tainted regions could be more
304 // complete. For example, this would not currently identify
305 // overlapping fields in a union as tainted. To identify this we can
306 // check for overlapping/nested byte offsets.
307 if (Kind == I.second && R->isSubRegionOf(I.first)) {
308 TaintedSymbols.push_back(SD->getParentSymbol());
309 if (returnFirstOnly && !TaintedSymbols.empty())
310 return TaintedSymbols; // return early if needed
311 }
312 }
313 }
314 }
315
316 // If memory region is tainted, data is also tainted.
317 if (const auto *SRV = dyn_cast<SymbolRegionValue>(SubSym)) {
318 std::vector<SymbolRef> TaintedRegions =
319 getTaintedSymbolsImpl(State, SRV->getRegion(), Kind, returnFirstOnly);
320 llvm::append_range(TaintedSymbols, TaintedRegions);
321 if (returnFirstOnly && !TaintedSymbols.empty())
322 return TaintedSymbols; // return early if needed
323 }
324
325 // If this is a SymbolCast from a tainted value, it's also tainted.
326 if (const auto *SC = dyn_cast<SymbolCast>(SubSym)) {
327 std::vector<SymbolRef> TaintedCasts =
328 getTaintedSymbolsImpl(State, SC->getOperand(), Kind, returnFirstOnly);
329 llvm::append_range(TaintedSymbols, TaintedCasts);
330 if (returnFirstOnly && !TaintedSymbols.empty())
331 return TaintedSymbols; // return early if needed
332 }
333 }
334 return TaintedSymbols;
335}
#define V(N, I)
#define REGISTER_MAP_WITH_PROGRAMSTATE(Name, Key, Value)
Declares an immutable map of type NameTy, suitable for placement into the ProgramState.
#define REGISTER_MAP_FACTORY_WITH_PROGRAMSTATE(Name, Key, Value)
Declares an immutable map type Name and registers the factory for such maps in the program state,...
This represents one expression.
Definition Expr.h:112
It wraps the AnalysisDeclContext to represent both the call stack with the help of StackFrameContext ...
ElementRegion is used to represent both array elements and casts.
Definition MemRegion.h:1232
MemRegion - The root abstract class for all memory regions.
Definition MemRegion.h:98
LLVM_ATTRIBUTE_RETURNS_NONNULL const MemRegion * getBaseRegion() const
SVal - This represents a symbolic expression, which can be either an L-value or an R-value.
Definition SVals.h:56
virtual std::optional< SVal > getDefaultBinding(Store store, const MemRegion *R)=0
Return the default value bound to a region in a given store.
SubRegion - A region that subsets another larger region.
Definition MemRegion.h:474
llvm::iterator_range< symbol_iterator > symbols() const
Definition SymExpr.h:107
virtual unsigned computeComplexity() const =0
Represents a cast expression.
SymbolicRegion - A special, "non-concrete" region.
Definition MemRegion.h:808
TypedValueRegion - An abstract class representing regions having a typed value.
Definition MemRegion.h:563
While nonloc::CompoundVal covers a few simple use cases, nonloc::LazyCompoundVal is a more performant...
Definition SVals.h:389
std::vector< SymbolRef > getTaintedSymbols(ProgramStateRef State, const Expr *E, const LocationContext *LCtx, TaintTagType Kind=TaintTagGeneric)
Returns the tainted Symbols for a given expression and state.
Definition Taint.cpp:170
ProgramStateRef removeTaint(ProgramStateRef State, SVal V)
Definition Taint.cpp:99
std::vector< SymbolRef > getTaintedSymbolsImpl(ProgramStateRef State, const Expr *E, const LocationContext *LCtx, TaintTagType Kind, bool returnFirstOnly)
Definition Taint.cpp:195
void printTaint(ProgramStateRef State, raw_ostream &Out, const char *nl="\n", const char *sep="")
ProgramStateRef addTaint(ProgramStateRef State, const Expr *E, const LocationContext *LCtx, TaintTagType Kind=TaintTagGeneric)
Create a new state in which the value of the expression is marked as tainted.
Definition Taint.cpp:46
ProgramStateRef addPartialTaint(ProgramStateRef State, SymbolRef ParentSym, const SubRegion *SubRegion, TaintTagType Kind=TaintTagGeneric)
Create a new state in a which a sub-region of a given symbol is tainted.
Definition Taint.cpp:125
bool isTainted(ProgramStateRef State, const Expr *E, const LocationContext *LCtx, TaintTagType Kind=TaintTagGeneric)
Check if the expression has a tainted value in the given state.
Definition Taint.cpp:148
LLVM_DUMP_METHOD void dumpTaint(ProgramStateRef State)
Definition Taint.cpp:42
unsigned TaintTagType
The type of taint, which helps to differentiate between different types of taint.
Definition Taint.h:25
IntrusiveRefCntPtr< const ProgramState > ProgramStateRef
const SymExpr * SymbolRef
Definition SymExpr.h:133
The JSON file list parser is used to communicate input to InstallAPI.
bool isa(CodeGen::Address addr)
Definition Address.h:330
for(const auto &A :T->param_types())