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