Python: Fix up dataflow configuration to act as expected. Keep undocumented for now.

This commit is contained in:
Mark Shannon
2019-04-04 16:40:57 +01:00
parent fa8b771944
commit df2000ea8e
8 changed files with 292 additions and 22 deletions

View File

@@ -0,0 +1 @@
import semmle.python.security.TaintTracking

View File

@@ -326,8 +326,6 @@ abstract class Sanitizer extends string {
private predicate valid_sanitizer(Sanitizer sanitizer) {
not exists(TaintTracking::Configuration c)
or
exists(DataFlow::Configuration c | c.isSanitizer(sanitizer))
or
exists(TaintTracking::Configuration c | c.isSanitizer(sanitizer))
}
@@ -600,7 +598,7 @@ private newtype TTaintedNode =
exists(DataFlow::Configuration config, TaintKind kind |
taint = TaintFlowImplementation::TTrackedTaint(kind) and
config.isSource(n) and context.getDepth() = 0 and
kind instanceof GenericFlowType
kind instanceof DataFlowType
)
or
TaintFlowImplementation::step(_, taint, context, n) and
@@ -864,8 +862,6 @@ library module TaintFlowImplementation {
(
not exists(TaintTracking::Configuration c)
or
exists(DataFlow::Configuration c | c.isExtension(fromnodenode))
or
exists(TaintTracking::Configuration c | c.isExtension(fromnodenode))
)
|
@@ -1090,8 +1086,6 @@ library module TaintFlowImplementation {
(
not exists(TaintTracking::Configuration c)
or
exists(DataFlow::Configuration c | c.isExtension(originnode))
or
exists(TaintTracking::Configuration c | c.isExtension(originnode))
) and
originnode.getASuccessorVariable() = var and
@@ -1537,16 +1531,12 @@ class CallContext extends TCallContext {
*/
module DataFlow {
class FlowType = TaintKind;
/** Generic taint kind, source and sink classes for convenience and
* compatibility with other language libraries
*/
class Node = ControlFlowNode;
class PathNode = TaintedNode;
class Extension = DataFlowExtension::DataFlowNode;
abstract class Configuration extends string {
@@ -1558,19 +1548,14 @@ module DataFlow {
abstract predicate isSink(Node sink);
predicate isSanitizer(Sanitizer sanitizer) { none() }
predicate isExtension(Extension extension) { none() }
predicate hasFlowPath(PathNode source, PathNode sink) {
private predicate hasFlowPath(TaintedNode source, TaintedNode sink) {
this.isSource(source.getNode()) and
this.isSink(sink.getNode()) and
source.getTaintKind() instanceof GenericFlowType and
sink.getTaintKind() instanceof GenericFlowType
source.getASuccessor*() = sink
}
predicate hasFlow(Node source, Node sink) {
exists(PathNode psource, PathNode psink |
exists(TaintedNode psource, TaintedNode psink |
psource.getNode() = source and
psink.getNode() = sink and
this.isSource(source) and
@@ -1583,10 +1568,10 @@ module DataFlow {
}
private class GenericFlowType extends DataFlow::FlowType {
private class DataFlowType extends TaintKind {
GenericFlowType() {
this = "Generic taint kind" and
DataFlowType() {
this = "Data flow" and
exists(DataFlow::Configuration c)
}

View File

@@ -0,0 +1,17 @@
import python
import semmle.python.dataflow.DataFlow
class TestConfiguration extends DataFlow::Configuration {
TestConfiguration() { this = "Test configuration" }
override predicate isSource(ControlFlowNode source) { source.(NameNode).getId() = "SOURCE" }
override predicate isSink(ControlFlowNode sink) {
exists(CallNode call |
call.getFunction().(NameNode).getId() = "SINK" and
sink = call.getAnArg()
)
}
}

View File

@@ -0,0 +1,16 @@
| test.py:3:10:3:15 | ControlFlowNode for SOURCE | test.py:3:10:3:15 | ControlFlowNode for SOURCE |
| test.py:6:9:6:14 | ControlFlowNode for SOURCE | test.py:7:10:7:10 | ControlFlowNode for s |
| test.py:10:12:10:17 | ControlFlowNode for SOURCE | test.py:13:10:13:12 | ControlFlowNode for arg |
| test.py:10:12:10:17 | ControlFlowNode for SOURCE | test.py:17:10:17:10 | ControlFlowNode for t |
| test.py:20:9:20:14 | ControlFlowNode for SOURCE | test.py:13:10:13:12 | ControlFlowNode for arg |
| test.py:37:13:37:18 | ControlFlowNode for SOURCE | test.py:41:14:41:14 | ControlFlowNode for t |
| test.py:62:13:62:18 | ControlFlowNode for SOURCE | test.py:13:10:13:12 | ControlFlowNode for arg |
| test.py:67:13:67:18 | ControlFlowNode for SOURCE | test.py:13:10:13:12 | ControlFlowNode for arg |
| test.py:76:9:76:14 | ControlFlowNode for SOURCE | test.py:78:10:78:10 | ControlFlowNode for t |
| test.py:108:13:108:18 | ControlFlowNode for SOURCE | test.py:112:14:112:14 | ControlFlowNode for t |
| test.py:139:10:139:15 | ControlFlowNode for SOURCE | test.py:140:14:140:14 | ControlFlowNode for t |
| test.py:143:9:143:14 | ControlFlowNode for SOURCE | test.py:145:10:145:10 | ControlFlowNode for s |
| test.py:148:10:148:15 | ControlFlowNode for SOURCE | test.py:152:10:152:13 | ControlFlowNode for Subscript |
| test.py:149:18:149:23 | ControlFlowNode for SOURCE | test.py:153:10:153:17 | ControlFlowNode for Subscript |
| test.py:158:9:158:14 | ControlFlowNode for SOURCE | test.py:160:14:160:14 | ControlFlowNode for t |
| test.py:158:9:158:14 | ControlFlowNode for SOURCE | test.py:166:14:166:14 | ControlFlowNode for t |

View File

@@ -0,0 +1,7 @@
import python
import Config
from TestConfiguration config, ControlFlowNode src, ControlFlowNode sink
where config.hasFlow(src, sink)
select src, sink

View File

@@ -0,0 +1,72 @@
| Taint Data flow | test.py:3 | SOURCE | |
| Taint Data flow | test.py:6 | SOURCE | |
| Taint Data flow | test.py:7 | s | |
| Taint Data flow | test.py:10 | SOURCE | |
| Taint Data flow | test.py:12 | arg | test.py:21 |
| Taint Data flow | test.py:12 | arg | test.py:25 |
| Taint Data flow | test.py:12 | arg | test.py:47 from test.py:55 |
| Taint Data flow | test.py:12 | arg | test.py:51 from test.py:63 |
| Taint Data flow | test.py:12 | arg | test.py:51 from test.py:70 |
| Taint Data flow | test.py:13 | arg | test.py:21 |
| Taint Data flow | test.py:13 | arg | test.py:25 |
| Taint Data flow | test.py:13 | arg | test.py:47 from test.py:55 |
| Taint Data flow | test.py:13 | arg | test.py:51 from test.py:63 |
| Taint Data flow | test.py:13 | arg | test.py:51 from test.py:70 |
| Taint Data flow | test.py:16 | source() | |
| Taint Data flow | test.py:17 | t | |
| Taint Data flow | test.py:20 | SOURCE | |
| Taint Data flow | test.py:21 | t | |
| Taint Data flow | test.py:24 | source() | |
| Taint Data flow | test.py:25 | t | |
| Taint Data flow | test.py:31 | SOURCE | |
| Taint Data flow | test.py:37 | SOURCE | |
| Taint Data flow | test.py:41 | t | |
| Taint Data flow | test.py:44 | source() | |
| Taint Data flow | test.py:46 | arg | test.py:55 |
| Taint Data flow | test.py:47 | arg | test.py:55 |
| Taint Data flow | test.py:49 | arg | test.py:63 |
| Taint Data flow | test.py:49 | arg | test.py:70 |
| Taint Data flow | test.py:51 | arg | test.py:63 |
| Taint Data flow | test.py:51 | arg | test.py:70 |
| Taint Data flow | test.py:54 | source2() | |
| Taint Data flow | test.py:55 | t | |
| Taint Data flow | test.py:62 | SOURCE | |
| Taint Data flow | test.py:63 | t | |
| Taint Data flow | test.py:67 | SOURCE | |
| Taint Data flow | test.py:70 | t | |
| Taint Data flow | test.py:72 | arg | test.py:77 |
| Taint Data flow | test.py:73 | arg | test.py:77 |
| Taint Data flow | test.py:76 | SOURCE | |
| Taint Data flow | test.py:77 | hub() | |
| Taint Data flow | test.py:77 | t | |
| Taint Data flow | test.py:78 | t | |
| Taint Data flow | test.py:108 | SOURCE | |
| Taint Data flow | test.py:112 | t | |
| Taint Data flow | test.py:118 | SOURCE | |
| Taint Data flow | test.py:120 | t | |
| Taint Data flow | test.py:128 | SOURCE | |
| Taint Data flow | test.py:129 | t | |
| Taint Data flow | test.py:139 | SOURCE | |
| Taint Data flow | test.py:140 | t | |
| Taint Data flow | test.py:143 | SOURCE | |
| Taint Data flow | test.py:144 | s | |
| Taint Data flow | test.py:145 | s | |
| Taint Data flow | test.py:148 | SOURCE | |
| Taint Data flow | test.py:149 | SOURCE | |
| Taint Data flow | test.py:152 | Subscript | |
| Taint Data flow | test.py:153 | Subscript | |
| Taint Data flow | test.py:158 | SOURCE | |
| Taint Data flow | test.py:159 | t | |
| Taint Data flow | test.py:160 | t | |
| Taint Data flow | test.py:163 | t | |
| Taint Data flow | test.py:166 | t | |
| Taint [Data flow] | test.py:148 | List | |
| Taint [Data flow] | test.py:150 | l | |
| Taint [Data flow] | test.py:152 | x | |
| Taint [Data flow] | test.py:154 | l | |
| Taint [Data flow] | test.py:154 | list() | |
| Taint {Data flow} | test.py:149 | Dict | |
| Taint {Data flow} | test.py:151 | d | |
| Taint {Data flow} | test.py:153 | y | |
| Taint {Data flow} | test.py:155 | d | |
| Taint {Data flow} | test.py:155 | dict() | |

View File

@@ -0,0 +1,5 @@
import python
import Config
from TaintedNode n
select n.getTrackedValue(), n.getLocation().toString(), n.getNode().getNode().toString(), n.getContext()

View File

@@ -0,0 +1,167 @@
def test1():
SINK(SOURCE)
def test2():
s = SOURCE
SINK(s)
def source():
return SOURCE
def sink(arg):
SINK(arg)
def test3():
t = source()
SINK(t)
def test4():
t = SOURCE
sink(t)
def test5():
t = source()
sink(t)
def test6(cond):
if cond:
t = "Safe"
else:
t = SOURCE
if cond:
SINK(t)
def test7(cond):
if cond:
t = SOURCE
else:
t = "Safe"
if cond:
SINK(t)
def source2(arg):
return source(arg)
def sink2(arg):
sink(arg)
def sink3(cond, arg):
if cond:
sink(arg)
def test8(cond):
t = source2()
sink2(t)
#False positive
def test9(cond):
if cond:
t = "Safe"
else:
t = SOURCE
sink3(cond, t)
def test10(cond):
if cond:
t = SOURCE
else:
t = "Safe"
sink3(cond, t)
def hub(arg):
return arg
def test11():
t = SOURCE
t = hub(t)
SINK(t)
def test12():
t = "safe"
t = hub(t)
SINK(t)
import module
def test13():
t = module.dangerous
SINK(t)
def test14():
t = module.safe
SINK(t)
def test15():
t = module.safe2
SINK(t)
def test16():
t = module.dangerous_func()
SINK(t)
def test20(cond):
if cond:
t = CUSTOM_SOURCE
else:
t = SOURCE
if cond:
CUSTOM_SINK(t)
else:
SINK(t)
def test21(cond):
if cond:
t = CUSTOM_SOURCE
else:
t = SOURCE
if not cond:
CUSTOM_SINK(t)
else:
SINK(t)
def test22(cond):
if cond:
t = CUSTOM_SOURCE
else:
t = SOURCE
t = TAINT_FROM_ARG(t)
if cond:
CUSTOM_SINK(t)
else:
SINK(t)
from module import dangerous as unsafe
SINK(unsafe)
def test23():
with SOURCE as t:
SINK(t)
def test24():
s = SOURCE
SANITIZE(s)
SINK(s)
def test_update_extend(x, y):
l = [SOURCE]
d = {"key" : SOURCE}
x.extend(l)
y.update(d)
SINK(x[0])
SINK(y["key"])
l2 = list(l)
d2 = dict(d)
def test_truth():
t = SOURCE
if t:
SINK(t)
else:
SINK(t)
if not t:
SINK(t)
else:
SINK(t)