Skip to content

Commit 9150682

Browse files
authored
Merge pull request #1757 from jbj/pyrameterized-taint
C++: Use pyrameterized modules for TaintTracking
2 parents 3501778 + 7c4938c commit 9150682

40 files changed

+1578
-1380
lines changed

change-notes/1.22/analysis-cpp.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
- The predicate `Variable.getAnAssignedValue()` now reports assignments to fields resulting from aggregate initialization (` = {...}`).
2626
- The predicate `TypeMention.toString()` has been simplified to always return the string "`type mention`". This may improve performance when using `Element.toString()` or its descendants.
2727
- The `semmle.code.cpp.security.TaintTracking` library now considers a pointer difference calculation as blocking taint flow.
28+
- The second copy of the interprocedural `TaintTracking` library has been renamed from `TaintTracking::Configuration2` to `TaintTracking2::Configuration`, and the old name is now deprecated. Import `semmle.code.cpp.dataflow.TaintTracking2` to access the new name.
2829
- Fixed the `LocalScopeVariableReachability.qll` library's handling of loops with an entry condition is both always true upon first entry, and where there is more than one control flow path through the loop condition. This change increases the accuracy of the `LocalScopeVariableReachability.qll` library and queries which depend on it.
2930
- The `semmle.code.cpp.models` library now models data flow through `std::swap`.
3031
- There is a new `Variable.isThreadLocal()` predicate. It can be used to tell whether a variable is `thread_local`.

change-notes/1.22/analysis-java.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,4 +16,4 @@
1616
removes false positives that arose from paths through impossible `toString()`
1717
calls.
1818
* The library `VCS.qll` and all queries that imported it have been removed.
19-
19+
* The second copy of the interprocedural `TaintTracking` library has been renamed from `TaintTracking::Configuration2` to `TaintTracking2::Configuration`, and the old name is now deprecated. Import `semmle.code.java.dataflow.TaintTracking2` to access the new name.

config/identical-files.json

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,21 @@
2525
"cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImplCommon.qll",
2626
"csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImplCommon.qll"
2727
],
28+
"Taint tracking C/C++": [
29+
"cpp/ql/src/semmle/code/cpp/dataflow/internal/tainttracking1/TaintTrackingImpl.qll",
30+
"cpp/ql/src/semmle/code/cpp/dataflow/internal/tainttracking2/TaintTrackingImpl.qll"
31+
],
32+
"Taint tracking C#": [
33+
"csharp/ql/src/semmle/code/csharp/dataflow/internal/tainttracking1/TaintTrackingImpl.qll",
34+
"csharp/ql/src/semmle/code/csharp/dataflow/internal/tainttracking2/TaintTrackingImpl.qll",
35+
"csharp/ql/src/semmle/code/csharp/dataflow/internal/tainttracking3/TaintTrackingImpl.qll",
36+
"csharp/ql/src/semmle/code/csharp/dataflow/internal/tainttracking4/TaintTrackingImpl.qll",
37+
"csharp/ql/src/semmle/code/csharp/dataflow/internal/tainttracking5/TaintTrackingImpl.qll"
38+
],
39+
"Taint tracking Java": [
40+
"java/ql/src/semmle/code/java/dataflow/internal/tainttracking1/TaintTrackingImpl.qll",
41+
"java/ql/src/semmle/code/java/dataflow/internal/tainttracking2/TaintTrackingImpl.qll"
42+
],
2843
"IR Instruction": [
2944
"cpp/ql/src/semmle/code/cpp/ir/implementation/raw/Instruction.qll",
3045
"cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/Instruction.qll",

cpp/ql/src/semmle/code/cpp/dataflow/TaintTracking.qll

Lines changed: 5 additions & 250 deletions
Original file line numberDiff line numberDiff line change
@@ -9,259 +9,14 @@
99
*/
1010
import semmle.code.cpp.dataflow.DataFlow
1111
import semmle.code.cpp.dataflow.DataFlow2
12-
import semmle.code.cpp.models.interfaces.DataFlow
13-
import semmle.code.cpp.models.interfaces.Taint
1412

1513
module TaintTracking {
14+
import semmle.code.cpp.dataflow.internal.tainttracking1.TaintTrackingImpl
15+
private import semmle.code.cpp.dataflow.TaintTracking2
1616

1717
/**
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.
5419
*/
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;
26722
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
/**
2+
* Provides classes for performing local (intra-procedural) and
3+
* global (inter-procedural) taint-tracking analyses.
4+
*
5+
* We define _taint propagation_ informally to mean that a substantial part of
6+
* the information from the source is preserved at the sink. For example, taint
7+
* propagates from `x` to `x + 100`, but it does not propagate from `x` to `x >
8+
* 100` since we consider a single bit of information to be too little.
9+
*/
10+
module TaintTracking2 {
11+
import semmle.code.cpp.dataflow.internal.tainttracking2.TaintTrackingImpl
12+
}

0 commit comments

Comments
 (0)