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

Skip to content

Commit 74f1dd3

Browse files
committed
Python taint-tracking. Add some tests and fix up various parts of the implementation.
1 parent eed2090 commit 74f1dd3

22 files changed

Lines changed: 1045 additions & 42 deletions

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

Lines changed: 56 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -5,32 +5,34 @@ private import semmle.python.objects.ObjectInternal
55
newtype TTaintTrackingContext =
66
TNoParam()
77
or
8-
TParamContext(TaintKind param, int n) {
9-
exists(CallNode call |
10-
param.taints(call.getArg(n))
11-
)
8+
TParamContext(TaintKind param, AttributePath path, int n) {
9+
any(TaintTrackingImplementation impl).callWithTaintedArgument(_, _, _, _, n, path, param)
1210
}
1311

1412
class TaintTrackingContext extends TTaintTrackingContext {
1513

1614
string toString() {
1715
this = TNoParam() and result = "No context"
1816
or
19-
exists(TaintKind param, int n |
20-
this = TParamContext(param, n) and
21-
result = "Parameter " + n.toString() + " is " + param
17+
exists(TaintKind param, AttributePath path, int n |
18+
this = TParamContext(param, path, n) and
19+
result = "Parameter " + n.toString() + "(" + path.toString() + ") is " + param
2220
)
2321
}
2422

2523
TaintKind getParameterTaint(int n) {
26-
this = TParamContext(result, n)
24+
this = TParamContext(result, _, n)
25+
}
26+
27+
AttributePath getAttributePath() {
28+
this = TParamContext(_, result, _)
2729
}
2830

2931
TaintTrackingContext getCaller() {
30-
exists(TaintKind param, int n |
31-
this = TParamContext(param, n) and
32+
exists(TaintKind param, AttributePath path, int n |
33+
this = TParamContext(param, path, n) and
3234
exists(TaintTrackingImplementation impl |
33-
impl.callWithTaintedArgument(_, _, result, _, n, TNoAttribute(), param)
35+
impl.callWithTaintedArgument(_, _, result, _, n, path, param)
3436
)
3537
)
3638
}
@@ -158,7 +160,7 @@ class TaintTrackingImplementation extends string {
158160

159161
predicate isPathSink(TaintTrackingNode sink) {
160162
exists(DataFlow::Node sinknode, TaintKind kind |
161-
sink = TTaintTrackingNode_(sinknode, TNoParam(), TNoAttribute(), kind, this) and
163+
sink = TTaintTrackingNode_(sinknode, _, TNoAttribute(), kind, this) and
162164
this.(TaintTracking::Configuration).isSink(sinknode, kind)
163165
)
164166
}
@@ -181,20 +183,26 @@ class TaintTrackingImplementation extends string {
181183
this.importStep(src, node, context, path, kind)
182184
or
183185
this.fromImportStep(src, node, context, path, kind)
184-
or
185-
this.attributeLoadStep(src, node, context, path, kind)
186-
or
187-
this.getattrStep(src, node, context, path, kind)
186+
//or
187+
//this.attributeLoadStep(src, node, context, path, kind)
188+
//or
189+
//this.getattrStep(src, node, context, path, kind)
188190
or
189191
this.useStep(src, node, context, path, kind)
190192
or
191193
this.callTaintStep(src, node, context, path, kind)
192194
or
193-
this.callFlowStep(src, node, context, path, kind)
195+
this.returnFlowStep(src, node, context, path, kind)
196+
//or
197+
//this.iterationStep(src, node, context, path, kind)
198+
//or
199+
//this.yieldStep(src, node, context, path, kind)
200+
//or
201+
//this.subscriptStep(src, node, context, path, kind)
202+
//or
203+
//this.ifExprStep(src, node, context, path, kind)
194204
or
195-
this.iterationStep(src, node, context, path, kind)
196-
or
197-
this.yieldStep(src, node, context, path, kind)
205+
this.essaFlowStep(src, node, context, path, kind)
198206
or
199207
exists(DataFlow::Node srcnode, TaintKind srckind |
200208
this.(TaintTracking::Configuration).isAdditionalFlowStep(srcnode, node, srckind, kind) and
@@ -259,35 +267,40 @@ class TaintTrackingImplementation extends string {
259267
)
260268
}
261269

270+
//pragma [noinline]
271+
//predicate argumentFlowStep(TaintTrackingNode src, DataFlow::Node node, TaintTrackingContext context, AttributePath path, TaintKind kind) {
272+
// exists(CallNode call, PythonFunctionObjectInternal pyfunc, int arg |
273+
// this.callWithTaintedArgument(src, call, _, pyfunc, arg, path, kind) and
274+
// node.asCfgNode() = pyfunc.getParameter(arg) and
275+
// context = TParamContext(kind, arg)
276+
// )
277+
// // TO DO... named parameters
278+
//}
279+
262280
pragma [noinline]
263-
predicate callFlowStep(TaintTrackingNode src, DataFlow::Node node, TaintTrackingContext context, AttributePath path, TaintKind kind) {
264-
exists(CallNode call, PythonFunctionObjectInternal pyfunc, int arg |
265-
this.callWithTaintedArgument(src, call, _, pyfunc, arg, path, kind) and
266-
node.asCfgNode() = pyfunc.getParameter(arg) and
267-
context = TParamContext(kind, arg)
281+
predicate returnFlowStep(TaintTrackingNode src, DataFlow::Node node, TaintTrackingContext context, AttributePath path, TaintKind kind) {
282+
exists(CallNode call, PythonFunctionObjectInternal pyfunc, int arg, TaintKind callerKind, DataFlow::Node srcNode, AttributePath callerPath, TaintTrackingContext srcContext |
283+
src = TTaintTrackingNode_(srcNode, srcContext, path, kind, this) and
284+
this.callWithTaintedArgument(_, call, context, pyfunc, arg, callerPath, callerKind) and
285+
srcContext = TParamContext(callerKind, callerPath, arg) and
286+
node.asCfgNode() = call and
287+
srcNode.asCfgNode() = any(Return ret | ret.getScope() = pyfunc.getScope()).getValue().getAFlowNode()
268288
)
269-
or
270-
exists(CallNode call, PythonFunctionObjectInternal pyfunc, int arg |
271-
this.callWithTaintedArgument(src, call, context, pyfunc, arg, path, kind) and
272-
src.getContext() = TParamContext(kind, arg)
273-
)
274-
// TO DO... named parameters
275289
}
276290

277-
predicate callWithTaintedArgument(TaintTrackingNode src, CallNode call, TaintTrackingContext caller, PythonFunctionObjectInternal pyfunc, int arg, AttributePath path, TaintKind kind) {
291+
predicate callWithTaintedArgument(TaintTrackingNode src, CallNode call, TaintTrackingContext caller, CallableValue pyfunc, int arg, AttributePath path, TaintKind kind) {
278292
exists(DataFlow::Node srcnode |
279293
src = TTaintTrackingNode_(srcnode, caller, path, kind, this) and
280-
srcnode.asCfgNode() = call.getArg(arg) and
281-
pyfunc.getACall() = call
294+
srcnode.asCfgNode() = pyfunc.getArgumentForCall(call, arg)
282295
)
283296
}
284297

285298
pragma [noinline]
286299
predicate callTaintStep(TaintTrackingNode src, DataFlow::Node node, TaintTrackingContext context, AttributePath path, TaintKind kind) {
287-
exists(DataFlow::Node srcnode, CallNode call, string name |
288-
src = TTaintTrackingNode_(srcnode, context, path, kind, this) and
300+
exists(DataFlow::Node srcnode, CallNode call, TaintKind srckind, string name |
301+
src = TTaintTrackingNode_(srcnode, context, path, srckind, this) and
289302
call.getFunction().(AttrNode).getObject(name) = src.getNode().asCfgNode() and
290-
kind = src.getTaintKind().getTaintOfMethodResult(name) and
303+
kind = srckind.getTaintOfMethodResult(name) and
291304
node.asCfgNode() = call
292305
)
293306
}
@@ -366,7 +379,8 @@ class TaintTrackingImplementation extends string {
366379
src = TTaintTrackingNode_(srcnode, context, path, kind, this) and
367380
predvar = defn.getInput(pred) and
368381
not pred.unlikelySuccessor(defn.getBasicBlock()) and
369-
not predvar.(DataFlowExtension::DataFlowVariable).prunedSuccessor(defn.getVariable())
382+
not predvar.(DataFlowExtension::DataFlowVariable).prunedSuccessor(defn.getVariable()) and
383+
srcnode.asVariable() = predvar
370384
)
371385
}
372386

@@ -390,11 +404,11 @@ class TaintTrackingImplementation extends string {
390404

391405
pragma [noinline]
392406
predicate taintedParameterDefinition(TaintTrackingNode src, ParameterDefinition defn, TaintTrackingContext context, AttributePath path, TaintKind kind) {
393-
exists(DataFlow::Node srcnode |
394-
src = TTaintTrackingNode_(srcnode, context, path, kind, this) and
395-
defn.getDefiningNode() = srcnode.asCfgNode()
407+
exists(CallNode call, PythonFunctionObjectInternal pyfunc, int arg |
408+
this.callWithTaintedArgument(src, call, _, pyfunc, arg, path, kind) and
409+
defn.getDefiningNode() = pyfunc.getParameter(arg) and
410+
context = TParamContext(kind, path, arg)
396411
)
397-
// TO DO... class intializers
398412
}
399413

400414
pragma [noinline]
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
edges
2+
| carrier.py:21:5:21:5 | explicit.carrier at carrier.py:21 | carrier.py:22:10:22:10 | explicit.carrier at carrier.py:22 |
3+
| carrier.py:21:9:21:28 | explicit.carrier at carrier.py:21 | carrier.py:21:5:21:5 | explicit.carrier at carrier.py:21 |
4+
| carrier.py:22:10:22:10 | explicit.carrier at carrier.py:22 | carrier.py:22:10:22:22 | simple.test at carrier.py:22 |
5+
| rockpaperscissors.py:24:5:24:5 | rock at rockpaperscissors.py:24 | rockpaperscissors.py:25:9:25:9 | rock at rockpaperscissors.py:25 |
6+
| rockpaperscissors.py:24:9:24:12 | rock at rockpaperscissors.py:24 | rockpaperscissors.py:24:5:24:5 | rock at rockpaperscissors.py:24 |
7+
| rockpaperscissors.py:25:5:25:5 | paper at rockpaperscissors.py:25 | rockpaperscissors.py:26:14:26:14 | paper at rockpaperscissors.py:26 |
8+
| rockpaperscissors.py:25:9:25:9 | rock at rockpaperscissors.py:25 | rockpaperscissors.py:25:9:25:16 | scissors at rockpaperscissors.py:25 |
9+
| rockpaperscissors.py:25:9:25:16 | scissors at rockpaperscissors.py:25 | rockpaperscissors.py:25:9:25:23 | paper at rockpaperscissors.py:25 |
10+
| rockpaperscissors.py:25:9:25:23 | paper at rockpaperscissors.py:25 | rockpaperscissors.py:25:5:25:5 | paper at rockpaperscissors.py:25 |
11+
| test.py:6:5:6:5 | simple.test at test.py:6 | test.py:7:10:7:10 | simple.test at test.py:7 |
12+
| test.py:6:9:6:14 | simple.test at test.py:6 | test.py:6:5:6:5 | simple.test at test.py:6 |
13+
| test.py:12:10:12:12 | simple.test at test.py:12 | test.py:13:10:13:12 | simple.test at test.py:13 |
14+
| test.py:20:5:20:5 | simple.test at test.py:20 | test.py:21:10:21:10 | simple.test at test.py:21 |
15+
| test.py:20:9:20:14 | simple.test at test.py:20 | test.py:20:5:20:5 | simple.test at test.py:20 |
16+
| test.py:21:10:21:10 | simple.test at test.py:21 | test.py:12:10:12:12 | simple.test at test.py:12 |
17+
| test.py:37:9:37:9 | simple.test at test.py:37 | test.py:41:14:41:14 | simple.test at test.py:41 |
18+
| test.py:37:13:37:18 | simple.test at test.py:37 | test.py:37:9:37:9 | simple.test at test.py:37 |
19+
| test.py:49:17:49:19 | simple.test at test.py:49 | test.py:51:14:51:16 | simple.test at test.py:51 |
20+
| test.py:51:14:51:16 | simple.test at test.py:51 | test.py:12:10:12:12 | simple.test at test.py:12 |
21+
| test.py:62:9:62:9 | simple.test at test.py:62 | test.py:63:5:63:9 | simple.test at test.py:63 |
22+
| test.py:62:13:62:18 | simple.test at test.py:62 | test.py:62:9:62:9 | simple.test at test.py:62 |
23+
| test.py:63:5:63:9 | simple.test at test.py:63 | test.py:63:17:63:17 | simple.test at test.py:63 |
24+
| test.py:63:17:63:17 | simple.test at test.py:63 | test.py:49:17:49:19 | simple.test at test.py:49 |
25+
| test.py:67:9:67:9 | simple.test at test.py:67 | test.py:70:5:70:9 | simple.test at test.py:70 |
26+
| test.py:67:13:67:18 | simple.test at test.py:67 | test.py:67:9:67:9 | simple.test at test.py:67 |
27+
| test.py:70:5:70:9 | simple.test at test.py:70 | test.py:70:17:70:17 | simple.test at test.py:70 |
28+
| test.py:70:17:70:17 | simple.test at test.py:70 | test.py:49:17:49:19 | simple.test at test.py:49 |
29+
| test.py:126:9:126:9 | simple.test at test.py:126 | test.py:130:21:130:21 | simple.test at test.py:130 |
30+
| test.py:126:13:126:25 | simple.test at test.py:126 | test.py:126:9:126:9 | simple.test at test.py:126 |
31+
| test.py:128:9:128:9 | simple.test at test.py:128 | test.py:132:14:132:14 | simple.test at test.py:132 |
32+
| test.py:128:13:128:18 | simple.test at test.py:128 | test.py:128:9:128:9 | simple.test at test.py:128 |
33+
parents
34+
#select
35+
| rockpaperscissors.py:13:10:13:17 | ControlFlowNode for SCISSORS | rockpaperscissors.py:13:10:13:17 | scissors at rockpaperscissors.py:13 | rockpaperscissors.py:13:10:13:17 | scissors at rockpaperscissors.py:13 | $@ looses to $@. | rockpaperscissors.py:13:10:13:17 | ControlFlowNode for SCISSORS | scissors | rockpaperscissors.py:13:10:13:17 | ControlFlowNode for SCISSORS | scissors |
36+
| rockpaperscissors.py:16:11:16:14 | ControlFlowNode for ROCK | rockpaperscissors.py:16:11:16:14 | rock at rockpaperscissors.py:16 | rockpaperscissors.py:16:11:16:14 | rock at rockpaperscissors.py:16 | $@ looses to $@. | rockpaperscissors.py:16:11:16:14 | ControlFlowNode for ROCK | rock | rockpaperscissors.py:16:11:16:14 | ControlFlowNode for ROCK | rock |
37+
| rockpaperscissors.py:26:14:26:14 | ControlFlowNode for y | rockpaperscissors.py:24:9:24:12 | rock at rockpaperscissors.py:24 | rockpaperscissors.py:26:14:26:14 | paper at rockpaperscissors.py:26 | $@ looses to $@. | rockpaperscissors.py:24:9:24:12 | ControlFlowNode for ROCK | rock | rockpaperscissors.py:26:14:26:14 | ControlFlowNode for y | paper |
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
2+
/**
3+
* @kind path-problem
4+
*/
5+
6+
import python
7+
import semmle.python.security.TaintTracking
8+
import TaintLib
9+
import semmle.python.security.Paths
10+
11+
from RockPaperScissorConfig config, TaintedPathSource src, TaintedPathSink sink
12+
where config.hasFlowPath(src, sink)
13+
select sink.getSink(), src, sink, "$@ looses to $@.", src.getNode(), src.getTaintKind().toString(), sink.getNode(), sink.getTaintKind().toString()

0 commit comments

Comments
 (0)