Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 64c160b

Browse files
committed
Python taint-tracking: Fix ambiguous flow through class instantiation. Tweak the path query to ensure edge to sink is always present.
1 parent d31e55f commit 64c160b

13 files changed

Lines changed: 407 additions & 345 deletions

File tree

python/ql/src/semmle/python/dataflow/Implementation.qll

Lines changed: 38 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -194,11 +194,16 @@ class TaintTrackingNode extends TTaintTrackingNode {
194194
}
195195

196196
TaintTrackingNode getASuccessor(string edgeLabel) {
197+
this.isVisible() and
197198
result = this.unlabeledSuccessor*().labeledSuccessor(edgeLabel)
198199
}
199200

200201
TaintTrackingNode getASuccessor() {
201202
result = this.getASuccessor(_)
203+
or
204+
this.isVisible() and
205+
result = this.unlabeledSuccessor+() and
206+
result.isSink()
202207
}
203208

204209
private TaintTrackingNode unlabeledSuccessor() {
@@ -210,6 +215,12 @@ class TaintTrackingNode extends TTaintTrackingNode {
210215
this.getConfiguration().(TaintTrackingImplementation).flowStep(this, result, label)
211216
}
212217

218+
private predicate isVisible() {
219+
any(TaintTrackingNode pred).labeledSuccessor(_) = this
220+
or
221+
this.isSource()
222+
}
223+
213224
}
214225

215226
class TaintTrackingImplementation extends string {
@@ -552,6 +563,33 @@ class TaintTrackingImplementation extends string {
552563
)
553564
}
554565

566+
predicate instantionStep(TaintTrackingNode src, DataFlow::Node node, TaintTrackingContext context, AttributePath path, TaintKind kind, string edgeLabel) {
567+
exists(PythonFunctionValue init, EssaVariable self, TaintTrackingContext callee |
568+
instantionCall(node.asCfgNode(), src, init, context, callee) and
569+
this.taintedDefinition(_, self.getDefinition(), callee, path, kind) and
570+
self.getSourceVariable().(Variable).isSelf() and
571+
BaseFlow::reaches_exit(self) and
572+
self.getScope() = init.getScope()
573+
) and
574+
edgeLabel = "instantiation"
575+
}
576+
577+
predicate instantionCall(CallNode call, TaintTrackingNode argnode, PythonFunctionObjectInternal init, TaintTrackingContext caller, TaintTrackingContext callee) {
578+
exists(ClassValue cls |
579+
call.getFunction().pointsTo(cls) and
580+
cls.lookup("__init__") = init
581+
|
582+
exists(int arg, TaintKind callerKind, AttributePath callerPath |
583+
exists(DataFlow::Node argument |
584+
argnode = TTaintTrackingNode_(argument, caller, callerPath, callerKind, this) and
585+
call.getArg(arg-1) = argument.asCfgNode() and
586+
callee = TParamContext(callerKind, callerPath, arg)
587+
)
588+
)
589+
)
590+
}
591+
592+
555593
pragma [noinline]
556594
predicate callTaintStep(TaintTrackingNode src, DataFlow::Node node, TaintTrackingContext context, AttributePath path, TaintKind kind, string edgeLabel) {
557595
exists(DataFlow::Node srcnode, CallNode call, TaintKind srckind, string name |
@@ -763,42 +801,6 @@ class TaintTrackingImplementation extends string {
763801
)
764802
}
765803

766-
predicate instantionStep(TaintTrackingNode src, DataFlow::Node node, TaintTrackingContext context, AttributePath path, TaintKind kind, string edgeLabel) {
767-
exists(DataFlow::Node srcnode, PythonFunctionValue init, EssaVariable self, TaintTrackingContext callee |
768-
instantionCall(node.asCfgNode(), init, context, callee) and
769-
src = TTaintTrackingNode_(srcnode, callee, path, kind, this) and
770-
srcnode.asVariable() = self and
771-
self.getSourceVariable().(Variable).isSelf() and
772-
BaseFlow::reaches_exit(self) and
773-
self.getScope() = init.getScope()
774-
) and
775-
edgeLabel = "instantiation"
776-
}
777-
778-
predicate instantionCall(CallNode call, PythonFunctionObjectInternal init, TaintTrackingContext caller, TaintTrackingContext callee) {
779-
exists(ClassValue cls |
780-
call.getFunction().pointsTo(cls) and
781-
cls.lookup("__init__") = init
782-
|
783-
exists(int arg, TaintKind callerKind, AttributePath callerPath |
784-
exists(TaintTrackingNode tainted, DataFlow::Node argument |
785-
tainted = TTaintTrackingNode_(argument, caller, callerPath, callerKind, this) and
786-
call.getArg(arg-1) = argument.asCfgNode() and
787-
callee = TParamContext(callerKind, callerPath, arg)
788-
)
789-
)
790-
or
791-
callee = TNoParam() and
792-
caller = TNoParam()
793-
)
794-
}
795-
796-
predicate crossCallFlow(TaintTrackingNode taintedArg, TaintTrackingNode call) {
797-
this.parameterStep(taintedArg, _, _, _, _, _) and
798-
this.flowReaches(taintedArg, call) and
799-
call.getNode().asCfgNode().(CallNode).getArg(_) = taintedArg.getNode().asCfgNode()
800-
}
801-
802804
}
803805

804806
/* Backwards compatibility with config-less taint-tracking */

python/ql/test/library-tests/taint/config/RockPaperScissors.expected

Lines changed: 47 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,51 +1,74 @@
11
edges
2-
| carrier.py:13:9:13:11 | explicit.carrier | carrier.py:14:12:14:14 | explicit.carrier |
3-
| carrier.py:14:12:14:14 | explicit.carrier | carrier.py:29:9:29:33 | explicit.carrier |
2+
| carrier.py:17:9:17:31 | .attr = simple.test | carrier.py:18:10:18:10 | .attr = simple.test |
3+
| carrier.py:17:25:17:30 | simple.test | carrier.py:17:9:17:31 | .attr = simple.test |
4+
| carrier.py:18:10:18:10 | .attr = simple.test | carrier.py:18:10:18:15 | simple.test |
45
| carrier.py:21:9:21:28 | explicit.carrier | carrier.py:22:10:22:10 | explicit.carrier |
56
| carrier.py:22:10:22:10 | explicit.carrier | carrier.py:22:10:22:22 | simple.test |
7+
| carrier.py:25:9:25:36 | .attr = simple.test | carrier.py:26:10:26:10 | .attr = simple.test |
8+
| carrier.py:25:13:25:35 | .attr = simple.test | carrier.py:25:9:25:36 | .attr = simple.test |
9+
| carrier.py:25:29:25:34 | simple.test | carrier.py:25:13:25:35 | .attr = simple.test |
10+
| carrier.py:26:10:26:10 | .attr = simple.test | carrier.py:26:10:26:21 | simple.test |
611
| carrier.py:29:9:29:33 | explicit.carrier | carrier.py:30:10:30:10 | explicit.carrier |
7-
| carrier.py:29:13:29:32 | explicit.carrier | carrier.py:13:9:13:11 | explicit.carrier |
12+
| carrier.py:29:13:29:32 | explicit.carrier | carrier.py:29:9:29:33 | explicit.carrier |
813
| carrier.py:30:10:30:10 | explicit.carrier | carrier.py:30:10:30:22 | simple.test |
9-
| deep.py:2:8:2:10 | simple.test | deep.py:3:12:3:14 | simple.test |
10-
| deep.py:3:12:3:14 | simple.test | deep.py:6:12:6:18 | simple.test |
11-
| deep.py:5:8:5:10 | simple.test | deep.py:6:15:6:17 | simple.test |
12-
| deep.py:6:12:6:18 | simple.test | deep.py:9:12:9:18 | simple.test |
13-
| deep.py:6:15:6:17 | simple.test | deep.py:2:8:2:10 | simple.test |
14-
| deep.py:8:8:8:10 | simple.test | deep.py:9:15:9:17 | simple.test |
15-
| deep.py:9:12:9:18 | simple.test | deep.py:12:12:12:18 | simple.test |
16-
| deep.py:9:15:9:17 | simple.test | deep.py:5:8:5:10 | simple.test |
17-
| deep.py:11:8:11:10 | simple.test | deep.py:12:15:12:17 | simple.test |
18-
| deep.py:12:12:12:18 | simple.test | deep.py:15:12:15:18 | simple.test |
19-
| deep.py:12:15:12:17 | simple.test | deep.py:8:8:8:10 | simple.test |
20-
| deep.py:14:8:14:10 | simple.test | deep.py:15:15:15:17 | simple.test |
21-
| deep.py:15:12:15:18 | simple.test | deep.py:18:12:18:18 | simple.test |
22-
| deep.py:15:15:15:17 | simple.test | deep.py:11:8:11:10 | simple.test |
23-
| deep.py:17:8:17:10 | simple.test | deep.py:18:15:18:17 | simple.test |
24-
| deep.py:18:12:18:18 | simple.test | deep.py:20:5:20:14 | simple.test |
25-
| deep.py:18:15:18:17 | simple.test | deep.py:14:8:14:10 | simple.test |
14+
| carrier.py:33:9:33:45 | .attr = explicit.carrier | carrier.py:34:9:34:9 | .attr = explicit.carrier |
15+
| carrier.py:33:25:33:44 | explicit.carrier | carrier.py:33:9:33:45 | .attr = explicit.carrier |
16+
| carrier.py:34:9:34:9 | .attr = explicit.carrier | carrier.py:34:9:34:14 | explicit.carrier |
17+
| carrier.py:34:9:34:14 | explicit.carrier | carrier.py:35:10:35:10 | explicit.carrier |
18+
| carrier.py:35:10:35:10 | explicit.carrier | carrier.py:35:10:35:22 | simple.test |
2619
| deep.py:20:5:20:14 | simple.test | deep.py:22:6:22:6 | simple.test |
27-
| deep.py:20:8:20:13 | simple.test | deep.py:17:8:17:10 | simple.test |
20+
| deep.py:20:8:20:13 | simple.test | deep.py:20:5:20:14 | simple.test |
21+
| module.py:3:13:3:18 | simple.test | test.py:85:8:85:13 | .dangerous = simple.test |
22+
| module.py:3:13:3:18 | simple.test | test.py:88:9:88:14 | .dangerous = simple.test |
23+
| module.py:3:13:3:18 | simple.test | test.py:110:11:110:16 | .dangerous = simple.test |
24+
| module.py:3:13:3:18 | simple.test | test.py:115:11:115:16 | .dangerous = simple.test |
2825
| module.py:3:13:3:18 | simple.test | test.py:155:20:155:38 | simple.test |
26+
| module.py:7:12:7:17 | simple.test | test.py:100:9:100:31 | simple.test |
2927
| rockpaperscissors.py:24:9:24:12 | rock | rockpaperscissors.py:25:9:25:9 | rock |
3028
| rockpaperscissors.py:25:9:25:9 | rock | rockpaperscissors.py:25:9:25:16 | scissors |
3129
| rockpaperscissors.py:25:9:25:16 | scissors | rockpaperscissors.py:25:9:25:23 | paper |
3230
| rockpaperscissors.py:25:9:25:23 | paper | rockpaperscissors.py:26:14:26:14 | paper |
3331
| test.py:6:9:6:14 | simple.test | test.py:7:10:7:10 | simple.test |
32+
| test.py:10:12:10:17 | simple.test | test.py:16:9:16:16 | simple.test |
33+
| test.py:10:12:10:17 | simple.test | test.py:24:9:24:16 | simple.test |
34+
| test.py:10:12:10:17 | simple.test | test.py:44:12:44:22 | simple.test |
3435
| test.py:12:10:12:12 | simple.test | test.py:13:10:13:12 | simple.test |
36+
| test.py:16:9:16:16 | simple.test | test.py:17:10:17:10 | simple.test |
3537
| test.py:20:9:20:14 | simple.test | test.py:21:10:21:10 | simple.test |
3638
| test.py:21:10:21:10 | simple.test | test.py:12:10:12:12 | simple.test |
39+
| test.py:24:9:24:16 | simple.test | test.py:25:10:25:10 | simple.test |
40+
| test.py:25:10:25:10 | simple.test | test.py:12:10:12:12 | simple.test |
3741
| test.py:37:13:37:18 | simple.test | test.py:41:14:41:14 | simple.test |
42+
| test.py:44:12:44:22 | simple.test | test.py:54:9:54:17 | simple.test |
43+
| test.py:46:11:46:13 | simple.test | test.py:47:10:47:12 | simple.test |
44+
| test.py:47:10:47:12 | simple.test | test.py:12:10:12:12 | simple.test |
3845
| test.py:49:17:49:19 | simple.test | test.py:51:14:51:16 | simple.test |
3946
| test.py:51:14:51:16 | simple.test | test.py:12:10:12:12 | simple.test |
47+
| test.py:54:9:54:17 | simple.test | test.py:55:11:55:11 | simple.test |
48+
| test.py:55:11:55:11 | simple.test | test.py:46:11:46:13 | simple.test |
4049
| test.py:62:13:62:18 | simple.test | test.py:63:17:63:17 | simple.test |
4150
| test.py:63:17:63:17 | simple.test | test.py:49:17:49:19 | simple.test |
4251
| test.py:67:13:67:18 | simple.test | test.py:70:17:70:17 | simple.test |
4352
| test.py:70:17:70:17 | simple.test | test.py:49:17:49:19 | simple.test |
44-
| test.py:72:9:72:11 | simple.test | test.py:73:12:73:14 | simple.test |
45-
| test.py:73:12:73:14 | simple.test | test.py:77:9:77:14 | simple.test |
4653
| test.py:76:9:76:14 | simple.test | test.py:77:13:77:13 | simple.test |
4754
| test.py:77:9:77:14 | simple.test | test.py:78:10:78:10 | simple.test |
48-
| test.py:77:13:77:13 | simple.test | test.py:72:9:72:11 | simple.test |
55+
| test.py:77:13:77:13 | simple.test | test.py:77:9:77:14 | simple.test |
56+
| test.py:85:8:85:13 | .dangerous = simple.test | test.py:88:9:88:14 | .dangerous = simple.test |
57+
| test.py:85:8:85:13 | .dangerous = simple.test | test.py:110:11:110:16 | .dangerous = simple.test |
58+
| test.py:85:8:85:13 | .dangerous = simple.test | test.py:115:11:115:16 | .dangerous = simple.test |
59+
| test.py:88:9:88:14 | .dangerous = simple.test | test.py:88:9:88:24 | simple.test |
60+
| test.py:88:9:88:24 | simple.test | test.py:89:10:89:10 | simple.test |
61+
| test.py:100:9:100:31 | simple.test | test.py:101:10:101:10 | simple.test |
62+
| test.py:105:12:105:14 | .x = simple.test | test.py:106:10:106:12 | .x = simple.test |
63+
| test.py:106:10:106:12 | .x = simple.test | test.py:106:10:106:14 | simple.test |
64+
| test.py:110:11:110:16 | .dangerous = simple.test | test.py:110:11:110:26 | simple.test |
65+
| test.py:110:11:110:26 | simple.test | test.py:111:10:111:10 | .x = simple.test |
66+
| test.py:111:10:111:10 | .x = simple.test | test.py:111:10:111:12 | simple.test |
67+
| test.py:115:11:115:16 | .dangerous = simple.test | test.py:115:11:115:26 | simple.test |
68+
| test.py:115:11:115:26 | simple.test | test.py:116:13:116:13 | .x = simple.test |
69+
| test.py:116:9:116:14 | .x = simple.test | test.py:117:12:117:12 | .x = simple.test |
70+
| test.py:116:13:116:13 | .x = simple.test | test.py:116:9:116:14 | .x = simple.test |
71+
| test.py:117:12:117:12 | .x = simple.test | test.py:105:12:105:14 | .x = simple.test |
4972
| test.py:126:13:126:25 | simple.test | test.py:130:21:130:21 | simple.test |
5073
| test.py:128:13:128:18 | simple.test | test.py:132:14:132:14 | simple.test |
5174
| test.py:155:20:155:38 | simple.test | test.py:156:6:156:11 | simple.test |

0 commit comments

Comments
 (0)