|
9 | 9 | */ |
10 | 10 | import semmle.code.cpp.dataflow.DataFlow |
11 | 11 | import semmle.code.cpp.dataflow.DataFlow2 |
12 | | -import semmle.code.cpp.models.interfaces.DataFlow |
13 | | -import semmle.code.cpp.models.interfaces.Taint |
14 | 12 |
|
15 | 13 | module TaintTracking { |
| 14 | + import semmle.code.cpp.dataflow.internal.tainttracking1.TaintTrackingImpl |
| 15 | + private import semmle.code.cpp.dataflow.TaintTracking2 |
16 | 16 |
|
17 | 17 | /** |
18 | | - * A configuration of interprocedural taint tracking analysis. This defines |
19 | | - * sources, sinks, and any other configurable aspect of the analysis. Each |
20 | | - * use of the taint tracking library must define its own unique extension of |
21 | | - * this abstract class. |
22 | | - * |
23 | | - * A taint-tracking configuration is a special data flow configuration |
24 | | - * (`DataFlow::Configuration`) that allows for flow through nodes that do not |
25 | | - * necessarily preserve values but are still relevant from a taint-tracking |
26 | | - * perspective. (For example, string concatenation, where one of the operands |
27 | | - * is tainted.) |
28 | | - * |
29 | | - * To create a configuration, extend this class with a subclass whose |
30 | | - * characteristic predicate is a unique singleton string. For example, write |
31 | | - * |
32 | | - * ``` |
33 | | - * class MyAnalysisConfiguration extends TaintTracking::Configuration { |
34 | | - * MyAnalysisConfiguration() { this = "MyAnalysisConfiguration" } |
35 | | - * // Override `isSource` and `isSink`. |
36 | | - * // Optionally override `isSanitizer`. |
37 | | - * // Optionally override `isSanitizerEdge`. |
38 | | - * // Optionally override `isAdditionalTaintStep`. |
39 | | - * } |
40 | | - * ``` |
41 | | - * |
42 | | - * Then, to query whether there is flow between some `source` and `sink`, |
43 | | - * write |
44 | | - * |
45 | | - * ``` |
46 | | - * exists(MyAnalysisConfiguration cfg | cfg.hasFlow(source, sink)) |
47 | | - * ``` |
48 | | - * |
49 | | - * Multiple configurations can coexist, but it is unsupported to depend on a |
50 | | - * `TaintTracking::Configuration` or a `DataFlow::Configuration` in the |
51 | | - * overridden predicates that define sources, sinks, or additional steps. |
52 | | - * Instead, the dependency should go to a `TaintTracking::Configuration2` or |
53 | | - * a `DataFlow{2,3,4}::Configuration`. |
| 18 | + * DEPRECATED: Use TaintTracking2::Configuration instead. |
54 | 19 | */ |
55 | | - abstract class Configuration extends DataFlow::Configuration { |
56 | | - bindingset[this] |
57 | | - Configuration() { any() } |
58 | | - |
59 | | - /** Holds if `source` is a taint source. */ |
60 | | - // overridden to provide taint-tracking specific qldoc |
61 | | - abstract override predicate isSource(DataFlow::Node source); |
62 | | - |
63 | | - /** Holds if `sink` is a taint sink. */ |
64 | | - // overridden to provide taint-tracking specific qldoc |
65 | | - abstract override predicate isSink(DataFlow::Node sink); |
66 | | - |
67 | | - /** |
68 | | - * Holds if taint should not flow into `node`. |
69 | | - */ |
70 | | - predicate isSanitizer(DataFlow::Node node) { none() } |
71 | | - |
72 | | - /** Holds if data flow from `node1` to `node2` is prohibited. */ |
73 | | - predicate isSanitizerEdge(DataFlow::Node node1, DataFlow::Node node2) { |
74 | | - none() |
75 | | - } |
76 | | - |
77 | | - /** |
78 | | - * Holds if the additional taint propagation step |
79 | | - * from `source` to `target` must be taken into account in the analysis. |
80 | | - * This step will only be followed if `target` is not in the `isSanitizer` |
81 | | - * predicate. |
82 | | - */ |
83 | | - predicate isAdditionalTaintStep(DataFlow::Node source, |
84 | | - DataFlow::Node target) |
85 | | - { none() } |
86 | | - |
87 | | - final override |
88 | | - predicate isBarrier(DataFlow::Node node) { isSanitizer(node) } |
89 | | - |
90 | | - /** DEPRECATED: use `isSanitizerEdge` instead. */ |
91 | | - override deprecated |
92 | | - predicate isBarrierEdge(DataFlow::Node node1, DataFlow::Node node2) { |
93 | | - this.isSanitizerEdge(node1, node2) |
94 | | - } |
95 | | - |
96 | | - final override |
97 | | - predicate isAdditionalFlowStep(DataFlow::Node source, DataFlow::Node target) { |
98 | | - this.isAdditionalTaintStep(source, target) |
99 | | - or |
100 | | - localTaintStep(source, target) |
101 | | - } |
102 | | - } |
103 | | - |
104 | | - /** |
105 | | - * A taint-tracking configuration that is backed by the `DataFlow2` library |
106 | | - * instead of `DataFlow`. Use this class when taint-tracking configurations |
107 | | - * or data-flow configurations must depend on each other. |
108 | | - * |
109 | | - * See `TaintTracking::Configuration` for the full documentation. |
110 | | - */ |
111 | | - abstract class Configuration2 extends DataFlow2::Configuration { |
112 | | - bindingset[this] |
113 | | - Configuration2() { any() } |
114 | | - |
115 | | - /** Holds if `source` is a taint source. */ |
116 | | - // overridden to provide taint-tracking specific qldoc |
117 | | - abstract override predicate isSource(DataFlow::Node source); |
118 | | - |
119 | | - /** Holds if `sink` is a taint sink. */ |
120 | | - // overridden to provide taint-tracking specific qldoc |
121 | | - abstract override predicate isSink(DataFlow::Node sink); |
122 | | - |
123 | | - /** |
124 | | - * Holds if taint should not flow into `node`. |
125 | | - */ |
126 | | - predicate isSanitizer(DataFlow::Node node) { none() } |
127 | | - |
128 | | - /** Holds if data flow from `node1` to `node2` is prohibited. */ |
129 | | - predicate isSanitizerEdge(DataFlow::Node node1, DataFlow::Node node2) { |
130 | | - none() |
131 | | - } |
132 | | - |
133 | | - /** |
134 | | - * Holds if the additional taint propagation step |
135 | | - * from `source` to `target` must be taken into account in the analysis. |
136 | | - * This step will only be followed if `target` is not in the `isSanitizer` |
137 | | - * predicate. |
138 | | - */ |
139 | | - predicate isAdditionalTaintStep(DataFlow::Node source, |
140 | | - DataFlow::Node target) |
141 | | - { none() } |
142 | | - |
143 | | - final override |
144 | | - predicate isBarrier(DataFlow::Node node) { isSanitizer(node) } |
145 | | - |
146 | | - /** DEPRECATED: use `isSanitizerEdge` instead. */ |
147 | | - override deprecated |
148 | | - predicate isBarrierEdge(DataFlow::Node node1, DataFlow::Node node2) { |
149 | | - this.isSanitizerEdge(node1, node2) |
150 | | - } |
151 | | - |
152 | | - final override |
153 | | - predicate isAdditionalFlowStep(DataFlow::Node source, DataFlow::Node target) { |
154 | | - this.isAdditionalTaintStep(source, target) |
155 | | - or |
156 | | - localTaintStep(source, target) |
157 | | - } |
158 | | - } |
159 | | - |
160 | | - /** |
161 | | - * Holds if taint propagates from `nodeFrom` to `nodeTo` in exactly one local |
162 | | - * (intra-procedural) step. |
163 | | - */ |
164 | | - predicate localTaintStep(DataFlow::Node nodeFrom, DataFlow::Node nodeTo) { |
165 | | - // Taint can flow into using ordinary data flow. |
166 | | - DataFlow::localFlowStep(nodeFrom, nodeTo) |
167 | | - or |
168 | | - // Taint can flow through expressions that alter the value but preserve |
169 | | - // more than one bit of it _or_ expressions that follow data through |
170 | | - // pointer indirections. |
171 | | - exists(Expr exprFrom, Expr exprTo | |
172 | | - exprFrom = nodeFrom.asExpr() and |
173 | | - exprTo = nodeTo.asExpr() |
174 | | - | |
175 | | - exprFrom = exprTo.getAChild() and |
176 | | - not noParentExprFlow(exprFrom, exprTo) and |
177 | | - not noFlowFromChildExpr(exprTo) |
178 | | - or |
179 | | - // Taint can flow from the `x` variable in `x++` to all subsequent |
180 | | - // accesses to the unmodified `x` variable. |
181 | | - // |
182 | | - // `DataFlow` without taint specifies flow from `++x` and `x += 1` into the |
183 | | - // variable `x` and thus into subsequent accesses because those expressions |
184 | | - // compute the same value as `x`. This is not the case for `x++`, which |
185 | | - // computes a different value, so we have to add that ourselves for taint |
186 | | - // tracking. The flow from expression `x` into `x++` etc. is handled in the |
187 | | - // case above. |
188 | | - exprTo = DataFlow::getAnAccessToAssignedVariable( |
189 | | - exprFrom.(PostfixCrementOperation) |
190 | | - ) |
191 | | - ) |
192 | | - or |
193 | | - // Taint can flow through modeled functions |
194 | | - exprToDefinitionByReferenceStep(nodeFrom.asExpr(), nodeTo.asDefiningArgument()) |
195 | | - } |
196 | | - |
197 | | - /** |
198 | | - * Holds if taint may propagate from `source` to `sink` in zero or more local |
199 | | - * (intra-procedural) steps. |
200 | | - */ |
201 | | - predicate localTaint(DataFlow::Node source, DataFlow::Node sink) { |
202 | | - localTaintStep*(source, sink) |
203 | | - } |
204 | | - |
205 | | - /** |
206 | | - * Holds if we do not propagate taint from `fromExpr` to `toExpr` |
207 | | - * even though `toExpr` is the AST parent of `fromExpr`. |
208 | | - */ |
209 | | - private predicate noParentExprFlow(Expr fromExpr, Expr toExpr) { |
210 | | - fromExpr = toExpr.(ConditionalExpr).getCondition() |
211 | | - or |
212 | | - fromExpr = toExpr.(CommaExpr).getLeftOperand() |
213 | | - or |
214 | | - fromExpr = toExpr.(AssignExpr).getLValue() // LHS of `=` |
215 | | - } |
216 | | - |
217 | | - /** |
218 | | - * Holds if we do not propagate taint from a child of `e` to `e` itself. |
219 | | - */ |
220 | | - private predicate noFlowFromChildExpr(Expr e) { |
221 | | - e instanceof ComparisonOperation |
222 | | - or |
223 | | - e instanceof LogicalAndExpr |
224 | | - or |
225 | | - e instanceof LogicalOrExpr |
226 | | - or |
227 | | - e instanceof Call |
228 | | - or |
229 | | - e instanceof SizeofOperator |
230 | | - or |
231 | | - e instanceof AlignofOperator |
232 | | - } |
233 | | - |
234 | | - private predicate exprToDefinitionByReferenceStep(Expr exprIn, Expr argOut) { |
235 | | - exists(DataFlowFunction f, Call call, FunctionOutput outModel, int argOutIndex | |
236 | | - call.getTarget() = f and |
237 | | - argOut = call.getArgument(argOutIndex) and |
238 | | - outModel.isOutParameterPointer(argOutIndex) and |
239 | | - exists(int argInIndex, FunctionInput inModel | |
240 | | - f.hasDataFlow(inModel, outModel) |
241 | | - | |
242 | | - // Taint flows from a pointer to a dereference, which DataFlow does not handle |
243 | | - // memcpy(&dest_var, tainted_ptr, len) |
244 | | - inModel.isInParameterPointer(argInIndex) and |
245 | | - exprIn = call.getArgument(argInIndex) |
246 | | - ) |
247 | | - ) |
248 | | - or |
249 | | - exists(TaintFunction f, Call call, FunctionOutput outModel, int argOutIndex | |
250 | | - call.getTarget() = f and |
251 | | - argOut = call.getArgument(argOutIndex) and |
252 | | - outModel.isOutParameterPointer(argOutIndex) and |
253 | | - exists(int argInIndex, FunctionInput inModel | |
254 | | - f.hasTaintFlow(inModel, outModel) |
255 | | - | |
256 | | - inModel.isInParameterPointer(argInIndex) and |
257 | | - exprIn = call.getArgument(argInIndex) |
258 | | - or |
259 | | - inModel.isInParameterPointer(argInIndex) and |
260 | | - call.passesByReference(argInIndex, exprIn) |
261 | | - or |
262 | | - inModel.isInParameter(argInIndex) and |
263 | | - exprIn = call.getArgument(argInIndex) |
264 | | - ) |
265 | | - ) |
266 | | - } |
| 20 | + deprecated |
| 21 | + class Configuration2 = TaintTracking2::Configuration; |
267 | 22 | } |
0 commit comments