Skip to content

Commit 7a00fbc

Browse files
authored
Merge pull request #4154 from RasmusWL/python-more-complete-dataflow-tests
Python more complete dataflow tests
2 parents 2f48059 + 29bf98a commit 7a00fbc

File tree

8 files changed

+254
-45
lines changed

8 files changed

+254
-45
lines changed

python/ql/test/experimental/dataflow/consistency/dataflow-consistency.expected

Lines changed: 60 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,24 @@
11
uniqueEnclosingCallable
2+
| module.py:1:1:1:9 | GSSA Variable dangerous | Node should have one enclosing callable but has 0. |
3+
| module.py:1:13:1:18 | ControlFlowNode for SOURCE | Node should have one enclosing callable but has 0. |
4+
| module.py:2:1:2:4 | GSSA Variable safe | Node should have one enclosing callable but has 0. |
5+
| module.py:2:8:2:13 | ControlFlowNode for Str | Node should have one enclosing callable but has 0. |
6+
| module.py:5:1:5:21 | ControlFlowNode for FunctionExpr | Node should have one enclosing callable but has 0. |
7+
| module.py:5:5:5:18 | GSSA Variable dangerous_func | Node should have one enclosing callable but has 0. |
8+
| module.py:10:1:10:5 | GSSA Variable safe2 | Node should have one enclosing callable but has 0. |
9+
| module.py:10:9:10:14 | ControlFlowNode for Str | Node should have one enclosing callable but has 0. |
210
| test.py:0:0:0:0 | GSSA Variable __name__ | Node should have one enclosing callable but has 0. |
311
| test.py:0:0:0:0 | GSSA Variable __package__ | Node should have one enclosing callable but has 0. |
12+
| test.py:0:0:0:0 | GSSA Variable const_eq_clears_taint | Node should have one enclosing callable but has 0. |
13+
| test.py:0:0:0:0 | GSSA Variable const_eq_clears_taint2 | Node should have one enclosing callable but has 0. |
14+
| test.py:0:0:0:0 | GSSA Variable flow_from_generator | Node should have one enclosing callable but has 0. |
15+
| test.py:0:0:0:0 | GSSA Variable flow_in_generator | Node should have one enclosing callable but has 0. |
16+
| test.py:0:0:0:0 | GSSA Variable flow_in_iteration | Node should have one enclosing callable but has 0. |
17+
| test.py:0:0:0:0 | GSSA Variable flow_through_type_test_if_no_class | Node should have one enclosing callable but has 0. |
18+
| test.py:0:0:0:0 | GSSA Variable non_const_eq_preserves_taint | Node should have one enclosing callable but has 0. |
419
| test.py:0:0:0:0 | GSSA Variable test23 | Node should have one enclosing callable but has 0. |
520
| test.py:0:0:0:0 | GSSA Variable test24 | Node should have one enclosing callable but has 0. |
21+
| test.py:0:0:0:0 | GSSA Variable test_early_exit | Node should have one enclosing callable but has 0. |
622
| test.py:0:0:0:0 | GSSA Variable test_truth | Node should have one enclosing callable but has 0. |
723
| test.py:0:0:0:0 | GSSA Variable test_update_extend | Node should have one enclosing callable but has 0. |
824
| test.py:6:1:6:12 | ControlFlowNode for FunctionExpr | Node should have one enclosing callable but has 0. |
@@ -51,25 +67,51 @@ uniqueEnclosingCallable
5167
| test.py:99:5:99:10 | GSSA Variable test15 | Node should have one enclosing callable but has 0. |
5268
| test.py:103:1:103:13 | ControlFlowNode for FunctionExpr | Node should have one enclosing callable but has 0. |
5369
| test.py:103:5:103:10 | GSSA Variable test16 | Node should have one enclosing callable but has 0. |
54-
| test.py:108:1:108:17 | ControlFlowNode for FunctionExpr | Node should have one enclosing callable but has 0. |
55-
| test.py:108:5:108:10 | GSSA Variable test20 | Node should have one enclosing callable but has 0. |
56-
| test.py:118:1:118:17 | ControlFlowNode for FunctionExpr | Node should have one enclosing callable but has 0. |
57-
| test.py:118:5:118:10 | GSSA Variable test21 | Node should have one enclosing callable but has 0. |
70+
| test.py:107:1:107:16 | ControlFlowNode for ClassExpr | Node should have one enclosing callable but has 0. |
71+
| test.py:107:7:107:7 | GSSA Variable C | Node should have one enclosing callable but has 0. |
72+
| test.py:109:1:109:16 | ControlFlowNode for FunctionExpr | Node should have one enclosing callable but has 0. |
73+
| test.py:109:5:109:10 | GSSA Variable x_sink | Node should have one enclosing callable but has 0. |
74+
| test.py:112:1:112:13 | ControlFlowNode for FunctionExpr | Node should have one enclosing callable but has 0. |
75+
| test.py:112:5:112:10 | GSSA Variable test17 | Node should have one enclosing callable but has 0. |
76+
| test.py:117:1:117:13 | ControlFlowNode for FunctionExpr | Node should have one enclosing callable but has 0. |
77+
| test.py:117:5:117:10 | GSSA Variable test18 | Node should have one enclosing callable but has 0. |
78+
| test.py:123:1:123:13 | ControlFlowNode for FunctionExpr | Node should have one enclosing callable but has 0. |
79+
| test.py:123:5:123:10 | GSSA Variable test19 | Node should have one enclosing callable but has 0. |
5880
| test.py:128:1:128:17 | ControlFlowNode for FunctionExpr | Node should have one enclosing callable but has 0. |
59-
| test.py:128:5:128:10 | GSSA Variable test22 | Node should have one enclosing callable but has 0. |
60-
| test.py:139:20:139:38 | ControlFlowNode for ImportMember | Node should have one enclosing callable but has 0. |
61-
| test.py:139:33:139:38 | GSSA Variable unsafe | Node should have one enclosing callable but has 0. |
62-
| test.py:140:1:140:12 | ControlFlowNode for SINK() | Node should have one enclosing callable but has 0. |
63-
| test.py:140:1:140:12 | GSSA Variable unsafe | Node should have one enclosing callable but has 0. |
64-
| test.py:140:6:140:11 | ControlFlowNode for unsafe | Node should have one enclosing callable but has 0. |
65-
| test.py:142:1:142:13 | ControlFlowNode for FunctionExpr | Node should have one enclosing callable but has 0. |
66-
| test.py:142:5:142:10 | GSSA Variable test23 | Node should have one enclosing callable but has 0. |
67-
| test.py:146:1:146:13 | ControlFlowNode for FunctionExpr | Node should have one enclosing callable but has 0. |
68-
| test.py:146:5:146:10 | GSSA Variable test24 | Node should have one enclosing callable but has 0. |
69-
| test.py:151:1:151:29 | ControlFlowNode for FunctionExpr | Node should have one enclosing callable but has 0. |
70-
| test.py:151:5:151:22 | GSSA Variable test_update_extend | Node should have one enclosing callable but has 0. |
71-
| test.py:161:1:161:17 | ControlFlowNode for FunctionExpr | Node should have one enclosing callable but has 0. |
72-
| test.py:161:5:161:14 | GSSA Variable test_truth | Node should have one enclosing callable but has 0. |
81+
| test.py:128:5:128:10 | GSSA Variable test20 | Node should have one enclosing callable but has 0. |
82+
| test.py:138:1:138:17 | ControlFlowNode for FunctionExpr | Node should have one enclosing callable but has 0. |
83+
| test.py:138:5:138:10 | GSSA Variable test21 | Node should have one enclosing callable but has 0. |
84+
| test.py:148:1:148:17 | ControlFlowNode for FunctionExpr | Node should have one enclosing callable but has 0. |
85+
| test.py:148:5:148:10 | GSSA Variable test22 | Node should have one enclosing callable but has 0. |
86+
| test.py:159:20:159:38 | ControlFlowNode for ImportMember | Node should have one enclosing callable but has 0. |
87+
| test.py:159:33:159:38 | GSSA Variable unsafe | Node should have one enclosing callable but has 0. |
88+
| test.py:160:1:160:12 | ControlFlowNode for SINK() | Node should have one enclosing callable but has 0. |
89+
| test.py:160:1:160:12 | GSSA Variable unsafe | Node should have one enclosing callable but has 0. |
90+
| test.py:160:6:160:11 | ControlFlowNode for unsafe | Node should have one enclosing callable but has 0. |
91+
| test.py:162:1:162:13 | ControlFlowNode for FunctionExpr | Node should have one enclosing callable but has 0. |
92+
| test.py:162:5:162:10 | GSSA Variable test23 | Node should have one enclosing callable but has 0. |
93+
| test.py:166:1:166:13 | ControlFlowNode for FunctionExpr | Node should have one enclosing callable but has 0. |
94+
| test.py:166:5:166:10 | GSSA Variable test24 | Node should have one enclosing callable but has 0. |
95+
| test.py:171:1:171:29 | ControlFlowNode for FunctionExpr | Node should have one enclosing callable but has 0. |
96+
| test.py:171:5:171:22 | GSSA Variable test_update_extend | Node should have one enclosing callable but has 0. |
97+
| test.py:181:1:181:17 | ControlFlowNode for FunctionExpr | Node should have one enclosing callable but has 0. |
98+
| test.py:181:5:181:14 | GSSA Variable test_truth | Node should have one enclosing callable but has 0. |
99+
| test.py:192:1:192:22 | ControlFlowNode for FunctionExpr | Node should have one enclosing callable but has 0. |
100+
| test.py:192:5:192:19 | GSSA Variable test_early_exit | Node should have one enclosing callable but has 0. |
101+
| test.py:198:1:198:41 | ControlFlowNode for FunctionExpr | Node should have one enclosing callable but has 0. |
102+
| test.py:198:5:198:38 | GSSA Variable flow_through_type_test_if_no_class | Node should have one enclosing callable but has 0. |
103+
| test.py:205:1:205:24 | ControlFlowNode for FunctionExpr | Node should have one enclosing callable but has 0. |
104+
| test.py:205:5:205:21 | GSSA Variable flow_in_iteration | Node should have one enclosing callable but has 0. |
105+
| test.py:211:1:211:24 | ControlFlowNode for FunctionExpr | Node should have one enclosing callable but has 0. |
106+
| test.py:211:5:211:21 | GSSA Variable flow_in_generator | Node should have one enclosing callable but has 0. |
107+
| test.py:216:1:216:26 | ControlFlowNode for FunctionExpr | Node should have one enclosing callable but has 0. |
108+
| test.py:216:5:216:23 | GSSA Variable flow_from_generator | Node should have one enclosing callable but has 0. |
109+
| test.py:220:1:220:28 | ControlFlowNode for FunctionExpr | Node should have one enclosing callable but has 0. |
110+
| test.py:220:5:220:25 | GSSA Variable const_eq_clears_taint | Node should have one enclosing callable but has 0. |
111+
| test.py:226:1:226:29 | ControlFlowNode for FunctionExpr | Node should have one enclosing callable but has 0. |
112+
| test.py:226:5:226:26 | GSSA Variable const_eq_clears_taint2 | Node should have one enclosing callable but has 0. |
113+
| test.py:232:1:232:36 | ControlFlowNode for FunctionExpr | Node should have one enclosing callable but has 0. |
114+
| test.py:232:5:232:32 | GSSA Variable non_const_eq_preserves_taint | Node should have one enclosing callable but has 0. |
73115
uniqueType
74116
uniqueNodeLocation
75117
missingLocation
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
dangerous = SOURCE
2+
safe = "safe"
3+
4+
5+
def dangerous_func():
6+
return SOURCE
7+
8+
9+
safe2 = SOURCE
10+
safe2 = "safe"

python/ql/test/experimental/dataflow/consistency/test.py

Lines changed: 68 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,26 @@ def test16():
104104
t = module.dangerous_func()
105105
SINK(t)
106106

107+
class C(object): pass
108+
109+
def x_sink(arg):
110+
SINK(arg.x)
111+
112+
def test17():
113+
t = C()
114+
t.x = module.dangerous
115+
SINK(t.x)
116+
117+
def test18():
118+
t = C()
119+
t.x = module.dangerous
120+
t = hub(t)
121+
x_sink(t)
122+
123+
def test19():
124+
t = CUSTOM_SOURCE
125+
t = hub(TAINT_FROM_ARG(t))
126+
CUSTOM_SINK(t)
107127

108128
def test20(cond):
109129
if cond:
@@ -163,9 +183,55 @@ def test_truth():
163183
if t:
164184
SINK(t)
165185
else:
166-
SINK(t) # Regression: FP here
186+
SINK(t)
187+
if not t:
188+
SINK(t)
189+
else:
190+
SINK(t)
191+
192+
def test_early_exit():
193+
t = FALSEY
167194
if not t:
168-
SINK(t) # Regression: FP here
195+
return
196+
t
197+
198+
def flow_through_type_test_if_no_class():
199+
t = SOURCE
200+
if isinstance(t, str):
201+
SINK(t)
169202
else:
170203
SINK(t)
171204

205+
def flow_in_iteration():
206+
t = ITERABLE_SOURCE
207+
for i in t:
208+
i
209+
return i
210+
211+
def flow_in_generator():
212+
seq = [SOURCE]
213+
for i in seq:
214+
yield i
215+
216+
def flow_from_generator():
217+
for x in flow_in_generator():
218+
SINK(x)
219+
220+
def const_eq_clears_taint():
221+
tainted = SOURCE
222+
if tainted == "safe":
223+
SINK(tainted) # safe
224+
SINK(tainted) # unsafe
225+
226+
def const_eq_clears_taint2():
227+
tainted = SOURCE
228+
if tainted != "safe":
229+
return
230+
SINK(tainted) # safe
231+
232+
def non_const_eq_preserves_taint(x):
233+
tainted = SOURCE
234+
if tainted == tainted:
235+
SINK(tainted) # unsafe
236+
if tainted == x:
237+
SINK(tainted) # unsafe
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
| test.py:126:13:126:25 | ControlFlowNode for CUSTOM_SOURCE | test.py:130:21:130:21 | ControlFlowNode for t |
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
/**
2+
* This query is meant to catch the flows from `CUSTOM_SOURCE` to `CUSTOM_SINK`.
3+
*
4+
* This should be compared to
5+
* python/ql/test/library-tests/taint/dataflow/Dataflow.ql
6+
* A first goal is to have identical results; after that we
7+
* hope to remove the false positive.
8+
*/
9+
10+
import python
11+
import experimental.dataflow.DataFlow
12+
13+
class CustomTestConfiguration extends DataFlow::Configuration {
14+
CustomTestConfiguration() { this = "CustomTestConfiguration" }
15+
16+
override predicate isSource(DataFlow::Node node) {
17+
node.asCfgNode().(NameNode).getId() = "CUSTOM_SOURCE"
18+
}
19+
20+
override predicate isSink(DataFlow::Node node) {
21+
exists(CallNode call |
22+
call.getFunction().(NameNode).getId() in ["CUSTOM_SINK", "CUSTOM_SINK_F"] and
23+
node.asCfgNode() = call.getAnArg()
24+
)
25+
}
26+
}
27+
28+
from DataFlow::Node source, DataFlow::Node sink
29+
where exists(CustomTestConfiguration cfg | cfg.hasFlow(source, sink))
30+
select source, sink
Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
| module.py:6:12:6:17 | ControlFlowNode for SOURCE | test.py:101:10:101:10 | ControlFlowNode for t |
12
| test.py:3:10:3:15 | ControlFlowNode for SOURCE | test.py:3:10:3:15 | ControlFlowNode for SOURCE |
23
| test.py:6:9:6:14 | ControlFlowNode for SOURCE | test.py:7:10:7:10 | ControlFlowNode for s |
34
| test.py:10:12:10:17 | ControlFlowNode for SOURCE | test.py:13:10:13:12 | ControlFlowNode for arg |
@@ -7,10 +8,12 @@
78
| test.py:62:13:62:18 | ControlFlowNode for SOURCE | test.py:13:10:13:12 | ControlFlowNode for arg |
89
| test.py:67:13:67:18 | ControlFlowNode for SOURCE | test.py:13:10:13:12 | ControlFlowNode for arg |
910
| test.py:76:9:76:14 | ControlFlowNode for SOURCE | test.py:78:10:78:10 | ControlFlowNode for t |
10-
| test.py:108:13:108:18 | ControlFlowNode for SOURCE | test.py:112:14:112:14 | ControlFlowNode for t |
11-
| test.py:139:10:139:15 | ControlFlowNode for SOURCE | test.py:140:14:140:14 | ControlFlowNode for t |
12-
| test.py:143:9:143:14 | ControlFlowNode for SOURCE | test.py:145:10:145:10 | ControlFlowNode for s |
13-
| test.py:158:9:158:14 | ControlFlowNode for SOURCE | test.py:160:14:160:14 | ControlFlowNode for t |
14-
| test.py:158:9:158:14 | ControlFlowNode for SOURCE | test.py:162:14:162:14 | ControlFlowNode for t |
15-
| test.py:158:9:158:14 | ControlFlowNode for SOURCE | test.py:164:14:164:14 | ControlFlowNode for t |
16-
| test.py:158:9:158:14 | ControlFlowNode for SOURCE | test.py:166:14:166:14 | ControlFlowNode for t |
11+
| test.py:128:13:128:18 | ControlFlowNode for SOURCE | test.py:132:14:132:14 | ControlFlowNode for t |
12+
| test.py:159:10:159:15 | ControlFlowNode for SOURCE | test.py:160:14:160:14 | ControlFlowNode for t |
13+
| test.py:163:9:163:14 | ControlFlowNode for SOURCE | test.py:165:12:165:12 | ControlFlowNode for s |
14+
| test.py:178:9:178:14 | ControlFlowNode for SOURCE | test.py:180:14:180:14 | ControlFlowNode for t |
15+
| test.py:178:9:178:14 | ControlFlowNode for SOURCE | test.py:182:16:182:16 | ControlFlowNode for t |
16+
| test.py:178:9:178:14 | ControlFlowNode for SOURCE | test.py:184:16:184:16 | ControlFlowNode for t |
17+
| test.py:178:9:178:14 | ControlFlowNode for SOURCE | test.py:186:14:186:14 | ControlFlowNode for t |
18+
| test.py:195:9:195:14 | ControlFlowNode for SOURCE | test.py:197:14:197:14 | ControlFlowNode for t |
19+
| test.py:195:9:195:14 | ControlFlowNode for SOURCE | test.py:199:14:199:14 | ControlFlowNode for t |
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
dangerous = SOURCE
2+
safe = "safe"
3+
4+
5+
def dangerous_func():
6+
return SOURCE
7+
8+
9+
safe2 = SOURCE
10+
safe2 = "safe"

0 commit comments

Comments
 (0)