Skip to content

Commit 25701f2

Browse files
committed
C++/C#/Java: Shared TaintTrackingImpl.qll
This file is now identical in all languages. Unifying this file led to the following changes: - The documentation spelling fixes and example from the C++ version were copied to the other versions and updated. - The steps through `NonLocalJumpNode` from C# were abstracted into a `globalAdditionalTaintStep` predicate that's empty for C++ and Java. - The `defaultTaintBarrier` predicate from Java is now present but empty on C++ and C#. - The C++ `isAdditionalFlowStep` predicate on `TaintTracking::Configuration` no longer includes `localFlowStep`. That should avoid some unnecessary tuple copying.
1 parent b4856e9 commit 25701f2

File tree

13 files changed

+566
-211
lines changed

13 files changed

+566
-211
lines changed

config/identical-files.json

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -25,18 +25,14 @@
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++": [
28+
"TaintTracking::Configuration Java/C++/C#": [
2929
"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#": [
30+
"cpp/ql/src/semmle/code/cpp/dataflow/internal/tainttracking2/TaintTrackingImpl.qll",
3331
"csharp/ql/src/semmle/code/csharp/dataflow/internal/tainttracking1/TaintTrackingImpl.qll",
3432
"csharp/ql/src/semmle/code/csharp/dataflow/internal/tainttracking2/TaintTrackingImpl.qll",
3533
"csharp/ql/src/semmle/code/csharp/dataflow/internal/tainttracking3/TaintTrackingImpl.qll",
3634
"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": [
35+
"csharp/ql/src/semmle/code/csharp/dataflow/internal/tainttracking5/TaintTrackingImpl.qll",
4036
"java/ql/src/semmle/code/java/dataflow/internal/tainttracking1/TaintTrackingImpl.qll",
4137
"java/ql/src/semmle/code/java/dataflow/internal/tainttracking2/TaintTrackingImpl.qll"
4238
],

cpp/ql/src/semmle/code/cpp/dataflow/internal/TaintTrackingUtil.qll

Lines changed: 23 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,10 +18,29 @@ private module DataFlow {
1818
* Holds if taint propagates from `nodeFrom` to `nodeTo` in exactly one local
1919
* (intra-procedural) step.
2020
*/
21-
predicate localTaintStep(DataFlow::Node nodeFrom, DataFlow::Node nodeTo) {
22-
// Taint can flow into using ordinary data flow.
23-
DataFlow::localFlowStep(nodeFrom, nodeTo)
24-
or
21+
predicate localTaintStep(DataFlow::Node src, DataFlow::Node sink) {
22+
DataFlow::localFlowStep(src, sink) or
23+
localAdditionalTaintStep(src, sink)
24+
}
25+
26+
/**
27+
* Holds if the additional step from `src` to `sink` should be included in all
28+
* global taint flow configurations but not in local taint.
29+
*/
30+
predicate globalAdditionalTaintStep(DataFlow::Node src, DataFlow::Node sink) { none() }
31+
32+
/**
33+
* Holds if `node` should be a barrier in all global taint flow configurations
34+
* but not in local taint.
35+
*/
36+
predicate defaultTaintBarrier(DataFlow::Node node) { none() }
37+
38+
/**
39+
* Holds if taint can flow in one local step from `nodeFrom` to `nodeTo` excluding
40+
* local data flow steps. That is, `nodeFrom` and `nodeTo` are likely to represent
41+
* different objects.
42+
*/
43+
predicate localAdditionalTaintStep(DataFlow::Node nodeFrom, DataFlow::Node nodeTo) {
2544
// Taint can flow through expressions that alter the value but preserve
2645
// more than one bit of it _or_ expressions that follow data through
2746
// pointer indirections.
Lines changed: 57 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,3 @@
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-
*/
101
import TaintTrackingParameter::Public
112
private import TaintTrackingParameter::Private
123

@@ -18,7 +9,7 @@ private import TaintTrackingParameter::Private
189
*
1910
* A taint-tracking configuration is a special data flow configuration
2011
* (`DataFlow::Configuration`) that allows for flow through nodes that do not
21-
* necessarily preserve values but are still relevant from a taint-tracking
12+
* necessarily preserve values but are still relevant from a taint tracking
2213
* perspective. (For example, string concatenation, where one of the operands
2314
* is tainted.)
2415
*
@@ -30,7 +21,9 @@ private import TaintTrackingParameter::Private
3021
* MyAnalysisConfiguration() { this = "MyAnalysisConfiguration" }
3122
* // Override `isSource` and `isSink`.
3223
* // Optionally override `isSanitizer`.
33-
* // Optionally override `isSanitizerEdge`.
24+
* // Optionally override `isSanitizerIn`.
25+
* // Optionally override `isSanitizerOut`.
26+
* // Optionally override `isSanitizerGuard`.
3427
* // Optionally override `isAdditionalTaintStep`.
3528
* }
3629
* ```
@@ -42,57 +35,79 @@ private import TaintTrackingParameter::Private
4235
* exists(MyAnalysisConfiguration cfg | cfg.hasFlow(source, sink))
4336
* ```
4437
*
45-
* Multiple configurations can coexist, but it is unsupported to depend on a
46-
* `TaintTracking::Configuration` or a `DataFlow::Configuration` in the
38+
* Multiple configurations can coexist, but it is unsupported to depend on
39+
* another `TaintTracking::Configuration` or a `DataFlow::Configuration` in the
4740
* overridden predicates that define sources, sinks, or additional steps.
48-
* Instead, the dependency should go to a `TaintTracking2::Configuration` or
49-
* a `DataFlow{2,3,4}::Configuration`.
41+
* Instead, the dependency should go to a `TaintTracking2::Configuration` or a
42+
* `DataFlow2::Configuration`, `DataFlow3::Configuration`, etc.
5043
*/
5144
abstract class Configuration extends DataFlow::Configuration {
5245
bindingset[this]
5346
Configuration() { any() }
5447

55-
/** Holds if `source` is a taint source. */
48+
/**
49+
* Holds if `source` is a relevant taint source.
50+
*
51+
* The smaller this predicate is, the faster `hasFlow()` will converge.
52+
*/
5653
// overridden to provide taint-tracking specific qldoc
5754
abstract override predicate isSource(DataFlow::Node source);
5855

59-
/** Holds if `sink` is a taint sink. */
56+
/**
57+
* Holds if `sink` is a relevant taint sink.
58+
*
59+
* The smaller this predicate is, the faster `hasFlow()` will converge.
60+
*/
6061
// overridden to provide taint-tracking specific qldoc
6162
abstract override predicate isSink(DataFlow::Node sink);
6263

63-
/**
64-
* Holds if taint should not flow into `node`.
65-
*/
64+
/** Holds if the node `node` is a taint sanitizer. */
6665
predicate isSanitizer(DataFlow::Node node) { none() }
6766

68-
/** Holds if data flow from `node1` to `node2` is prohibited. */
69-
predicate isSanitizerEdge(DataFlow::Node node1, DataFlow::Node node2) {
70-
none()
67+
final override predicate isBarrier(DataFlow::Node node) {
68+
isSanitizer(node) or
69+
defaultTaintBarrier(node)
70+
}
71+
72+
/** DEPRECATED: override `isSanitizerIn` and `isSanitizerOut` instead. */
73+
deprecated predicate isSanitizerEdge(DataFlow::Node node1, DataFlow::Node node2) { none() }
74+
75+
deprecated final override predicate isBarrierEdge(DataFlow::Node node1, DataFlow::Node node2) {
76+
isSanitizerEdge(node1, node2)
7177
}
7278

79+
/** Holds if data flow into `node` is prohibited. */
80+
predicate isSanitizerIn(DataFlow::Node node) { none() }
81+
82+
final override predicate isBarrierIn(DataFlow::Node node) { isSanitizerIn(node) }
83+
84+
/** Holds if data flow out of `node` is prohibited. */
85+
predicate isSanitizerOut(DataFlow::Node node) { none() }
86+
87+
final override predicate isBarrierOut(DataFlow::Node node) { isSanitizerOut(node) }
88+
89+
/** Holds if data flow through nodes guarded by `guard` is prohibited. */
90+
predicate isSanitizerGuard(DataFlow::BarrierGuard guard) { none() }
91+
92+
final override predicate isBarrierGuard(DataFlow::BarrierGuard guard) { isSanitizerGuard(guard) }
93+
7394
/**
74-
* Holds if the additional taint propagation step
75-
* from `source` to `target` must be taken into account in the analysis.
76-
* This step will only be followed if `target` is not in the `isSanitizer`
77-
* predicate.
95+
* Holds if the additional taint propagation step from `node1` to `node2`
96+
* must be taken into account in the analysis.
7897
*/
79-
predicate isAdditionalTaintStep(DataFlow::Node source,
80-
DataFlow::Node target)
81-
{ none() }
82-
83-
final override
84-
predicate isBarrier(DataFlow::Node node) { isSanitizer(node) }
98+
predicate isAdditionalTaintStep(DataFlow::Node node1, DataFlow::Node node2) { none() }
8599

86-
/** DEPRECATED: use `isSanitizerEdge` instead. */
87-
override deprecated
88-
predicate isBarrierEdge(DataFlow::Node node1, DataFlow::Node node2) {
89-
this.isSanitizerEdge(node1, node2)
100+
final override predicate isAdditionalFlowStep(DataFlow::Node node1, DataFlow::Node node2) {
101+
isAdditionalTaintStep(node1, node2) or
102+
localAdditionalTaintStep(node1, node2) or
103+
globalAdditionalTaintStep(node1, node2)
90104
}
91105

92-
final override
93-
predicate isAdditionalFlowStep(DataFlow::Node source, DataFlow::Node target) {
94-
this.isAdditionalTaintStep(source, target)
95-
or
96-
localTaintStep(source, target)
106+
/**
107+
* Holds if taint may flow from `source` to `sink` for this configuration.
108+
*/
109+
// overridden to provide taint-tracking specific qldoc
110+
override predicate hasFlow(DataFlow::Node source, DataFlow::Node sink) {
111+
super.hasFlow(source, sink)
97112
}
98113
}
Lines changed: 57 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,3 @@
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-
*/
101
import TaintTrackingParameter::Public
112
private import TaintTrackingParameter::Private
123

@@ -18,7 +9,7 @@ private import TaintTrackingParameter::Private
189
*
1910
* A taint-tracking configuration is a special data flow configuration
2011
* (`DataFlow::Configuration`) that allows for flow through nodes that do not
21-
* necessarily preserve values but are still relevant from a taint-tracking
12+
* necessarily preserve values but are still relevant from a taint tracking
2213
* perspective. (For example, string concatenation, where one of the operands
2314
* is tainted.)
2415
*
@@ -30,7 +21,9 @@ private import TaintTrackingParameter::Private
3021
* MyAnalysisConfiguration() { this = "MyAnalysisConfiguration" }
3122
* // Override `isSource` and `isSink`.
3223
* // Optionally override `isSanitizer`.
33-
* // Optionally override `isSanitizerEdge`.
24+
* // Optionally override `isSanitizerIn`.
25+
* // Optionally override `isSanitizerOut`.
26+
* // Optionally override `isSanitizerGuard`.
3427
* // Optionally override `isAdditionalTaintStep`.
3528
* }
3629
* ```
@@ -42,57 +35,79 @@ private import TaintTrackingParameter::Private
4235
* exists(MyAnalysisConfiguration cfg | cfg.hasFlow(source, sink))
4336
* ```
4437
*
45-
* Multiple configurations can coexist, but it is unsupported to depend on a
46-
* `TaintTracking::Configuration` or a `DataFlow::Configuration` in the
38+
* Multiple configurations can coexist, but it is unsupported to depend on
39+
* another `TaintTracking::Configuration` or a `DataFlow::Configuration` in the
4740
* overridden predicates that define sources, sinks, or additional steps.
48-
* Instead, the dependency should go to a `TaintTracking2::Configuration` or
49-
* a `DataFlow{2,3,4}::Configuration`.
41+
* Instead, the dependency should go to a `TaintTracking2::Configuration` or a
42+
* `DataFlow2::Configuration`, `DataFlow3::Configuration`, etc.
5043
*/
5144
abstract class Configuration extends DataFlow::Configuration {
5245
bindingset[this]
5346
Configuration() { any() }
5447

55-
/** Holds if `source` is a taint source. */
48+
/**
49+
* Holds if `source` is a relevant taint source.
50+
*
51+
* The smaller this predicate is, the faster `hasFlow()` will converge.
52+
*/
5653
// overridden to provide taint-tracking specific qldoc
5754
abstract override predicate isSource(DataFlow::Node source);
5855

59-
/** Holds if `sink` is a taint sink. */
56+
/**
57+
* Holds if `sink` is a relevant taint sink.
58+
*
59+
* The smaller this predicate is, the faster `hasFlow()` will converge.
60+
*/
6061
// overridden to provide taint-tracking specific qldoc
6162
abstract override predicate isSink(DataFlow::Node sink);
6263

63-
/**
64-
* Holds if taint should not flow into `node`.
65-
*/
64+
/** Holds if the node `node` is a taint sanitizer. */
6665
predicate isSanitizer(DataFlow::Node node) { none() }
6766

68-
/** Holds if data flow from `node1` to `node2` is prohibited. */
69-
predicate isSanitizerEdge(DataFlow::Node node1, DataFlow::Node node2) {
70-
none()
67+
final override predicate isBarrier(DataFlow::Node node) {
68+
isSanitizer(node) or
69+
defaultTaintBarrier(node)
70+
}
71+
72+
/** DEPRECATED: override `isSanitizerIn` and `isSanitizerOut` instead. */
73+
deprecated predicate isSanitizerEdge(DataFlow::Node node1, DataFlow::Node node2) { none() }
74+
75+
deprecated final override predicate isBarrierEdge(DataFlow::Node node1, DataFlow::Node node2) {
76+
isSanitizerEdge(node1, node2)
7177
}
7278

79+
/** Holds if data flow into `node` is prohibited. */
80+
predicate isSanitizerIn(DataFlow::Node node) { none() }
81+
82+
final override predicate isBarrierIn(DataFlow::Node node) { isSanitizerIn(node) }
83+
84+
/** Holds if data flow out of `node` is prohibited. */
85+
predicate isSanitizerOut(DataFlow::Node node) { none() }
86+
87+
final override predicate isBarrierOut(DataFlow::Node node) { isSanitizerOut(node) }
88+
89+
/** Holds if data flow through nodes guarded by `guard` is prohibited. */
90+
predicate isSanitizerGuard(DataFlow::BarrierGuard guard) { none() }
91+
92+
final override predicate isBarrierGuard(DataFlow::BarrierGuard guard) { isSanitizerGuard(guard) }
93+
7394
/**
74-
* Holds if the additional taint propagation step
75-
* from `source` to `target` must be taken into account in the analysis.
76-
* This step will only be followed if `target` is not in the `isSanitizer`
77-
* predicate.
95+
* Holds if the additional taint propagation step from `node1` to `node2`
96+
* must be taken into account in the analysis.
7897
*/
79-
predicate isAdditionalTaintStep(DataFlow::Node source,
80-
DataFlow::Node target)
81-
{ none() }
82-
83-
final override
84-
predicate isBarrier(DataFlow::Node node) { isSanitizer(node) }
98+
predicate isAdditionalTaintStep(DataFlow::Node node1, DataFlow::Node node2) { none() }
8599

86-
/** DEPRECATED: use `isSanitizerEdge` instead. */
87-
override deprecated
88-
predicate isBarrierEdge(DataFlow::Node node1, DataFlow::Node node2) {
89-
this.isSanitizerEdge(node1, node2)
100+
final override predicate isAdditionalFlowStep(DataFlow::Node node1, DataFlow::Node node2) {
101+
isAdditionalTaintStep(node1, node2) or
102+
localAdditionalTaintStep(node1, node2) or
103+
globalAdditionalTaintStep(node1, node2)
90104
}
91105

92-
final override
93-
predicate isAdditionalFlowStep(DataFlow::Node source, DataFlow::Node target) {
94-
this.isAdditionalTaintStep(source, target)
95-
or
96-
localTaintStep(source, target)
106+
/**
107+
* Holds if taint may flow from `source` to `sink` for this configuration.
108+
*/
109+
// overridden to provide taint-tracking specific qldoc
110+
override predicate hasFlow(DataFlow::Node source, DataFlow::Node sink) {
111+
super.hasFlow(source, sink)
97112
}
98113
}

csharp/ql/src/semmle/code/csharp/dataflow/internal/TaintTrackingPrivate.qll

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,20 @@ private import semmle.code.csharp.frameworks.JsonNET
1010
private import cil
1111
private import dotnet
1212

13+
/**
14+
* Holds if `node` should be a barrier in all global taint flow configurations
15+
* but not in local taint.
16+
*/
17+
predicate defaultTaintBarrier(DataFlow::Node node) { none() }
18+
19+
/**
20+
* Holds if the additional step from `src` to `sink` should be included in all
21+
* global taint flow configurations but not in local taint.
22+
*/
23+
predicate globalAdditionalTaintStep(DataFlow::Node pred, DataFlow::Node succ) {
24+
succ = pred.(DataFlow::NonLocalJumpNode).getAJumpSuccessor(false)
25+
}
26+
1327
private CIL::DataFlowNode asCilDataFlowNode(DataFlow::Node node) {
1428
result = node.asParameter() or
1529
result = node.asExpr()

0 commit comments

Comments
 (0)