Skip to content

Commit b1659be

Browse files
authored
Merge pull request github#12909 from michaelnebel/csharp/dataflowrefactor7
C#: Re-factor the experimental PotentialTimeBomb to use new API.
2 parents 77ec345 + d01674f commit b1659be

File tree

2 files changed

+69
-65
lines changed

2 files changed

+69
-65
lines changed

csharp/ql/src/experimental/Security Features/backdoor/PotentialTimeBomb.ql

Lines changed: 58 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -11,32 +11,16 @@
1111
*/
1212

1313
import csharp
14-
import DataFlow
14+
import Flow::PathGraph
1515

16-
query predicate nodes = PathGraph::nodes/3;
17-
18-
query predicate edges(DataFlow::PathNode a, DataFlow::PathNode b) {
19-
PathGraph::edges(a, b)
16+
query predicate edges(Flow::PathNode a, Flow::PathNode b) {
17+
Flow::PathGraph::edges(a, b)
2018
or
21-
exists(
22-
FlowsFromGetLastWriteTimeConfigToTimeSpanArithmeticCallable conf1,
23-
FlowsFromTimeSpanArithmeticToTimeComparisonCallable conf2
24-
|
25-
conf1 = a.getConfiguration() and
26-
conf1.isSink(a.getNode()) and
27-
conf2 = b.getConfiguration() and
28-
b.isSource()
29-
)
19+
FlowsFromGetLastWriteTimeConfigToTimeSpanArithmeticCallableConfig::isSink(a.getNode()) and
20+
FlowsFromTimeSpanArithmeticToTimeComparisonCallableConfig::isSource(b.getNode())
3021
or
31-
exists(
32-
FlowsFromTimeSpanArithmeticToTimeComparisonCallable conf1,
33-
FlowsFromTimeComparisonCallableToSelectionStatementCondition conf2
34-
|
35-
conf1 = a.getConfiguration() and
36-
conf1.isSink(a.getNode()) and
37-
conf2 = b.getConfiguration() and
38-
b.isSource()
39-
)
22+
FlowsFromTimeSpanArithmeticToTimeComparisonCallableConfig::isSink(a.getNode()) and
23+
FlowsFromTimeComparisonCallableToSelectionStatementConditionConfig::isSource(b.getNode())
4024
}
4125

4226
/**
@@ -78,22 +62,19 @@ class DateTimeStruct extends Struct {
7862
}
7963

8064
/**
81-
* Dataflow configuration to find flow from a GetLastWriteTime source to a DateTime arithmetic operation
65+
* Configuration to find flow from a GetLastWriteTime source to a DateTime arithmetic operation
8266
*/
83-
private class FlowsFromGetLastWriteTimeConfigToTimeSpanArithmeticCallable extends TaintTracking::Configuration
67+
private module FlowsFromGetLastWriteTimeConfigToTimeSpanArithmeticCallableConfig implements
68+
DataFlow::ConfigSig
8469
{
85-
FlowsFromGetLastWriteTimeConfigToTimeSpanArithmeticCallable() {
86-
this = "FlowsFromGetLastWriteTimeConfigToTimeSpanArithmeticCallable"
87-
}
88-
89-
override predicate isSource(DataFlow::Node source) {
70+
predicate isSource(DataFlow::Node source) {
9071
exists(Call call, GetLastWriteTimeMethod m |
9172
m.getACall() = call and
9273
source.asExpr() = call
9374
)
9475
}
9576

96-
override predicate isSink(DataFlow::Node sink) {
77+
predicate isSink(DataFlow::Node sink) {
9778
exists(Call call, DateTimeStruct dateTime |
9879
call.getAChild*() = sink.asExpr() and
9980
call = dateTime.getATimeSpanArithmeticCallable().getACall()
@@ -102,21 +83,24 @@ private class FlowsFromGetLastWriteTimeConfigToTimeSpanArithmeticCallable extend
10283
}
10384

10485
/**
105-
* Dataflow configuration to find flow from a DateTime arithmetic operation to a DateTime comparison operation
86+
* Tainttracking module to find flow from a GetLastWriteTime source to a DateTime arithmetic operation
10687
*/
107-
private class FlowsFromTimeSpanArithmeticToTimeComparisonCallable extends TaintTracking::Configuration
108-
{
109-
FlowsFromTimeSpanArithmeticToTimeComparisonCallable() {
110-
this = "FlowsFromTimeSpanArithmeticToTimeComparisonCallable"
111-
}
88+
private module FlowsFromGetLastWriteTimeConfigToTimeSpanArithmeticCallable =
89+
TaintTracking::Global<FlowsFromGetLastWriteTimeConfigToTimeSpanArithmeticCallableConfig>;
11290

113-
override predicate isSource(DataFlow::Node source) {
91+
/**
92+
* Configuration to find flow from a DateTime arithmetic operation to a DateTime comparison operation
93+
*/
94+
private module FlowsFromTimeSpanArithmeticToTimeComparisonCallableConfig implements
95+
DataFlow::ConfigSig
96+
{
97+
predicate isSource(DataFlow::Node source) {
11498
exists(DateTimeStruct dateTime, Call call | source.asExpr() = call |
11599
call = dateTime.getATimeSpanArithmeticCallable().getACall()
116100
)
117101
}
118102

119-
override predicate isSink(DataFlow::Node sink) {
103+
predicate isSink(DataFlow::Node sink) {
120104
exists(Call call, DateTimeStruct dateTime |
121105
call.getAnArgument().getAChild*() = sink.asExpr() and
122106
call = dateTime.getAComparisonCallable().getACall()
@@ -125,53 +109,69 @@ private class FlowsFromTimeSpanArithmeticToTimeComparisonCallable extends TaintT
125109
}
126110

127111
/**
128-
* Dataflow configuration to find flow from a DateTime comparison operation to a Selection Statement (such as an If)
112+
* Tainttracking module to find flow from a DateTime arithmetic operation to a DateTime comparison operation
129113
*/
130-
private class FlowsFromTimeComparisonCallableToSelectionStatementCondition extends TaintTracking::Configuration
131-
{
132-
FlowsFromTimeComparisonCallableToSelectionStatementCondition() {
133-
this = "FlowsFromTimeComparisonCallableToSelectionStatementCondition"
134-
}
114+
private module FlowsFromTimeSpanArithmeticToTimeComparisonCallable =
115+
TaintTracking::Global<FlowsFromTimeSpanArithmeticToTimeComparisonCallableConfig>;
135116

136-
override predicate isSource(DataFlow::Node source) {
117+
/**
118+
* Configuration to find flow from a DateTime comparison operation to a Selection Statement (such as an If)
119+
*/
120+
private module FlowsFromTimeComparisonCallableToSelectionStatementConditionConfig implements
121+
DataFlow::ConfigSig
122+
{
123+
predicate isSource(DataFlow::Node source) {
137124
exists(DateTimeStruct dateTime, Call call | source.asExpr() = call |
138125
call = dateTime.getAComparisonCallable().getACall()
139126
)
140127
}
141128

142-
override predicate isSink(DataFlow::Node sink) {
129+
predicate isSink(DataFlow::Node sink) {
143130
exists(SelectionStmt sel | sel.getCondition().getAChild*() = sink.asExpr())
144131
}
145132
}
146133

134+
/**
135+
* Tainttracking module to find flow from a DateTime comparison operation to a Selection Statement (such as an If)
136+
*/
137+
private module FlowsFromTimeComparisonCallableToSelectionStatementCondition =
138+
TaintTracking::Global<FlowsFromTimeComparisonCallableToSelectionStatementConditionConfig>;
139+
140+
private module Flow =
141+
DataFlow::MergePathGraph3<FlowsFromGetLastWriteTimeConfigToTimeSpanArithmeticCallable::PathNode,
142+
FlowsFromTimeSpanArithmeticToTimeComparisonCallable::PathNode,
143+
FlowsFromTimeComparisonCallableToSelectionStatementCondition::PathNode,
144+
FlowsFromGetLastWriteTimeConfigToTimeSpanArithmeticCallable::PathGraph,
145+
FlowsFromTimeSpanArithmeticToTimeComparisonCallable::PathGraph,
146+
FlowsFromTimeComparisonCallableToSelectionStatementCondition::PathGraph>;
147+
147148
/**
148149
* Holds if the last file modification date from the call to getLastWriteTimeMethodCall will be used in a DateTime arithmetic operation timeArithmeticCall,
149150
* which is then used for a DateTime comparison timeComparisonCall and the result flows to a Selection statement which is likely a TimeBomb trigger
150151
*/
151152
predicate isPotentialTimeBomb(
152-
DataFlow::PathNode pathSource, DataFlow::PathNode pathSink, Call getLastWriteTimeMethodCall,
153+
Flow::PathNode pathSource, Flow::PathNode pathSink, Call getLastWriteTimeMethodCall,
153154
Call timeArithmeticCall, Call timeComparisonCall, SelectionStmt selStatement
154155
) {
155-
exists(
156-
FlowsFromGetLastWriteTimeConfigToTimeSpanArithmeticCallable config1, Node sink,
157-
DateTimeStruct dateTime, FlowsFromTimeSpanArithmeticToTimeComparisonCallable config2,
158-
Node sink2, FlowsFromTimeComparisonCallableToSelectionStatementCondition config3, Node sink3
159-
|
160-
pathSource.getNode() = exprNode(getLastWriteTimeMethodCall) and
161-
config1.hasFlow(exprNode(getLastWriteTimeMethodCall), sink) and
156+
exists(DataFlow::Node sink, DateTimeStruct dateTime, DataFlow::Node sink2, DataFlow::Node sink3 |
157+
pathSource.getNode() = DataFlow::exprNode(getLastWriteTimeMethodCall) and
158+
FlowsFromGetLastWriteTimeConfigToTimeSpanArithmeticCallable::flow(DataFlow::exprNode(getLastWriteTimeMethodCall),
159+
sink) and
162160
timeArithmeticCall = dateTime.getATimeSpanArithmeticCallable().getACall() and
163161
timeArithmeticCall.getAChild*() = sink.asExpr() and
164-
config2.hasFlow(exprNode(timeArithmeticCall), sink2) and
162+
FlowsFromTimeSpanArithmeticToTimeComparisonCallable::flow(DataFlow::exprNode(timeArithmeticCall),
163+
sink2) and
165164
timeComparisonCall = dateTime.getAComparisonCallable().getACall() and
166165
timeComparisonCall.getAnArgument().getAChild*() = sink2.asExpr() and
167-
config3.hasFlow(exprNode(timeComparisonCall), sink3) and
166+
FlowsFromTimeComparisonCallableToSelectionStatementCondition::flow(DataFlow::exprNode(timeComparisonCall),
167+
sink3) and
168168
selStatement.getCondition().getAChild*() = sink3.asExpr() and
169169
pathSink.getNode() = sink3
170170
)
171171
}
172172

173173
from
174-
DataFlow::PathNode source, DataFlow::PathNode sink, Call getLastWriteTimeMethodCall,
174+
Flow::PathNode source, Flow::PathNode sink, Call getLastWriteTimeMethodCall,
175175
Call timeArithmeticCall, Call timeComparisonCall, SelectionStmt selStatement
176176
where
177177
isPotentialTimeBomb(source, sink, getLastWriteTimeMethodCall, timeArithmeticCall,

csharp/ql/test/experimental/Security Features/backdoor/PotentialTimeBomb.expected

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,21 @@
1+
nodes
2+
| test.cs:69:34:69:76 | call to method GetLastWriteTime : DateTime | semmle.label | call to method GetLastWriteTime : DateTime |
3+
| test.cs:71:13:71:71 | call to method CompareTo | semmle.label | call to method CompareTo |
4+
| test.cs:71:13:71:71 | call to method CompareTo : Int32 | semmle.label | call to method CompareTo : Int32 |
5+
| test.cs:71:13:71:76 | ... >= ... | semmle.label | ... >= ... |
6+
| test.cs:71:36:71:48 | access to local variable lastWriteTime | semmle.label | access to local variable lastWriteTime |
7+
| test.cs:71:36:71:70 | call to method AddHours | semmle.label | call to method AddHours |
8+
subpaths
19
edges
210
| test.cs:69:34:69:76 | call to method GetLastWriteTime : DateTime | test.cs:71:36:71:48 | access to local variable lastWriteTime |
311
| test.cs:71:13:71:71 | call to method CompareTo : Int32 | test.cs:71:13:71:76 | ... >= ... |
12+
| test.cs:71:36:71:48 | access to local variable lastWriteTime | test.cs:71:13:71:71 | call to method CompareTo |
13+
| test.cs:71:36:71:48 | access to local variable lastWriteTime | test.cs:71:13:71:71 | call to method CompareTo : Int32 |
414
| test.cs:71:36:71:48 | access to local variable lastWriteTime | test.cs:71:36:71:70 | call to method AddHours |
515
| test.cs:71:36:71:70 | call to method AddHours | test.cs:71:13:71:71 | call to method CompareTo |
616
| test.cs:71:36:71:70 | call to method AddHours | test.cs:71:13:71:71 | call to method CompareTo : Int32 |
17+
| test.cs:71:36:71:70 | call to method AddHours | test.cs:71:36:71:70 | call to method AddHours |
718
#select
819
| test.cs:71:9:74:9 | if (...) ... | test.cs:69:34:69:76 | call to method GetLastWriteTime : DateTime | test.cs:71:13:71:71 | call to method CompareTo | Possible TimeBomb logic triggered by an $@ that takes into account $@ from the $@ as part of the potential trigger. | test.cs:71:13:71:71 | call to method CompareTo | call to method CompareTo | test.cs:71:36:71:70 | call to method AddHours | offset | test.cs:69:34:69:76 | call to method GetLastWriteTime | last modification time of a file |
920
| test.cs:71:9:74:9 | if (...) ... | test.cs:69:34:69:76 | call to method GetLastWriteTime : DateTime | test.cs:71:13:71:71 | call to method CompareTo : Int32 | Possible TimeBomb logic triggered by an $@ that takes into account $@ from the $@ as part of the potential trigger. | test.cs:71:13:71:71 | call to method CompareTo | call to method CompareTo | test.cs:71:36:71:70 | call to method AddHours | offset | test.cs:69:34:69:76 | call to method GetLastWriteTime | last modification time of a file |
1021
| test.cs:71:9:74:9 | if (...) ... | test.cs:69:34:69:76 | call to method GetLastWriteTime : DateTime | test.cs:71:13:71:76 | ... >= ... | Possible TimeBomb logic triggered by an $@ that takes into account $@ from the $@ as part of the potential trigger. | test.cs:71:13:71:71 | call to method CompareTo | call to method CompareTo | test.cs:71:36:71:70 | call to method AddHours | offset | test.cs:69:34:69:76 | call to method GetLastWriteTime | last modification time of a file |
11-
nodes
12-
| test.cs:69:34:69:76 | call to method GetLastWriteTime : DateTime | semmle.label | call to method GetLastWriteTime : DateTime |
13-
| test.cs:71:13:71:71 | call to method CompareTo | semmle.label | call to method CompareTo |
14-
| test.cs:71:13:71:71 | call to method CompareTo : Int32 | semmle.label | call to method CompareTo : Int32 |
15-
| test.cs:71:13:71:76 | ... >= ... | semmle.label | ... >= ... |
16-
| test.cs:71:36:71:48 | access to local variable lastWriteTime | semmle.label | access to local variable lastWriteTime |
17-
| test.cs:71:36:71:70 | call to method AddHours | semmle.label | call to method AddHours |

0 commit comments

Comments
 (0)