Merge pull request #1052 from markshannon/python-taint-tracking-configuration

Python: Add taint-tracking configuration.
This commit is contained in:
Taus
2019-03-15 11:34:59 +01:00
committed by GitHub
2 changed files with 171 additions and 28 deletions

View File

@@ -0,0 +1,3 @@
/* For compatibility with other language implementations */
import semmle.python.security.TaintTracking

View File

@@ -125,13 +125,6 @@ abstract class TaintKind extends string {
*/
predicate additionalFlowStepVar(EssaVariable fromvar, EssaVariable tovar) { none() }
/** Holds if this kind of taint can start from `expr`.
* In other words, is `expr` a source of this kind of taint.
*/
final predicate startsFrom(ControlFlowNode expr) {
expr.(TaintSource).isSourceOf(this, _)
}
/** Holds if this kind of taint "taints" `expr`.
*/
final predicate taints(ControlFlowNode expr) {
@@ -318,6 +311,18 @@ abstract class Sanitizer extends string {
}
/** Hold if `sanitizer` is valid. A sanitizer is valid if there is
* a `TaintTracking::Configuration` that declares `sanitizer` or
* there are no `TaintTracking::Configuration`s.
*/
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))
}
/** DEPRECATED -- Use DataFlowExtension instead.
* An extension to taint-flow. For adding library or framework specific flows.
* Examples include flow from a request to untrusted part of that request or
@@ -584,12 +589,19 @@ private newtype TTaintedNode =
n.(TaintSource).isSourceOf(kind, context)
)
or
exists(DataFlow::Configuration config, TaintKind kind |
taint = TaintFlowImplementation::TTrackedTaint(kind) and
config.isSource(n) and context.getDepth() = 0 and
kind instanceof GenericFlowType
)
or
TaintFlowImplementation::step(_, taint, context, n) and
exists(TaintKind kind |
kind = taint.(TaintFlowImplementation::TrackedTaint).getKind()
or
kind = taint.(TaintFlowImplementation::TrackedAttribute).getKind(_) |
not exists(Sanitizer sanitizer |
valid_sanitizer(sanitizer) and
sanitizer.sanitizingNode(kind, n)
)
)
@@ -839,26 +851,37 @@ library module TaintFlowImplementation {
or
call_taint_step(fromnode, totaint, tocontext, tonode)
or
fromnode.getNode().(DataFlowNode).getASuccessorNode() = tonode and
fromnode.getContext() = tocontext and
totaint = fromnode.getTrackedValue()
or
exists(CallNode call |
fromnode.getNode().(DataFlowNode).getAReturnSuccessorNode(call) = tonode and
fromnode.getContext() = tocontext.getCallee(call) and
exists(DataFlowNode fromnodenode |
fromnodenode = fromnode.getNode() and
(
not exists(TaintTracking::Configuration c)
or
exists(DataFlow::Configuration c | c.isExtension(fromnodenode))
or
exists(TaintTracking::Configuration c | c.isExtension(fromnodenode))
)
|
fromnodenode.getASuccessorNode() = tonode and
fromnode.getContext() = tocontext and
totaint = fromnode.getTrackedValue()
)
or
exists(CallNode call |
fromnode.getNode().(DataFlowNode).getACalleeSuccessorNode(call) = tonode and
fromnode.getContext().getCallee(call) = tocontext and
totaint = fromnode.getTrackedValue()
)
or
exists(TaintKind tokind |
fromnode.getNode().(DataFlowNode).getASuccessorNode(fromnode.getTaintKind(), tokind) = tonode and
totaint = fromnode.getTrackedValue().toKind(tokind) and
tocontext = fromnode.getContext()
or
exists(CallNode call |
fromnodenode.getAReturnSuccessorNode(call) = tonode and
fromnode.getContext() = tocontext.getCallee(call) and
totaint = fromnode.getTrackedValue()
)
or
exists(CallNode call |
fromnodenode.getACalleeSuccessorNode(call) = tonode and
fromnode.getContext().getCallee(call) = tocontext and
totaint = fromnode.getTrackedValue()
)
or
exists(TaintKind tokind |
fromnodenode.getASuccessorNode(fromnode.getTaintKind(), tokind) = tonode and
totaint = fromnode.getTrackedValue().toKind(tokind) and
tocontext = fromnode.getContext()
)
)
or
exists(TaintKind tokind |
@@ -1038,8 +1061,18 @@ library module TaintFlowImplementation {
prev.(DataFlowVariable).getASuccessorVariable() = var
)
or
origin.getNode().(DataFlowNode).getASuccessorVariable() = var and
context = origin.getContext()
exists(DataFlowNode originnode |
originnode = origin.getNode() and
(
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
context = origin.getContext()
)
or
exists(TrackedTaint taint, EssaVariable prev |
tainted_var(prev, context, origin) and
@@ -1062,6 +1095,7 @@ library module TaintFlowImplementation {
exists(TaintKind kind |
kind = origin.getTaintKind() and
not exists(Sanitizer san |
valid_sanitizer(san) |
san.sanitizingDefinition(kind, def)
or
san.sanitizingNode(kind, def.(EssaNodeDefinition).getDefiningNode())
@@ -1184,6 +1218,7 @@ library module TaintFlowImplementation {
exists(TaintKind kind |
kind = origin.getTaintKind() |
not exists(FunctionObject callee, Sanitizer sanitizer |
valid_sanitizer(sanitizer) and
callee.getACall() = call.getCall() and
sanitizer.sanitizingCall(kind, callee)
)
@@ -1197,6 +1232,7 @@ library module TaintFlowImplementation {
var = test.getInput() and
tainted_var(var, context, origin) and
not exists(Sanitizer sanitizer |
valid_sanitizer(sanitizer) and
sanitizer.sanitizingEdge(kind, test)
)
|
@@ -1246,6 +1282,7 @@ library module TaintFlowImplementation {
var = uniphi.getInput() and
tainted_var(var, context, origin) and
not exists(Sanitizer sanitizer |
valid_sanitizer(sanitizer) and
sanitizer.sanitizingSingleEdge(kind, uniphi)
)
)
@@ -1438,6 +1475,109 @@ class CallContext extends TCallContext {
}
/** Data flow module providing an interface compatible with
* the other language implementations.
*/
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 {
bindingset[this]
Configuration() { this = this }
abstract predicate isSource(Node source);
abstract predicate isSink(Node sink);
predicate isSanitizer(Sanitizer sanitizer) { none() }
predicate isExtension(Extension extension) { none() }
predicate hasFlowPath(PathNode source, PathNode sink) {
this.isSource(source.getNode()) and
this.isSink(sink.getNode()) and
source.getTaintKind() instanceof GenericFlowType and
sink.getTaintKind() instanceof GenericFlowType
}
predicate hasFlow(Node source, Node sink) {
exists(PathNode psource, PathNode psink |
psource.getNode() = source and
psink.getNode() = sink and
this.isSource(source) and
this.isSink(sink) and
this.hasFlowPath(psource, psink)
)
}
}
}
private class GenericFlowType extends DataFlow::FlowType {
GenericFlowType() {
this = "Generic taint kind" and
exists(DataFlow::Configuration c)
}
}
module TaintTracking {
class Source = TaintSource;
class Sink = TaintSink;
class PathSource = TaintedPathSource;
class PathSink = TaintedPathSink;
class Extension = DataFlowExtension::DataFlowNode;
abstract class Configuration extends string {
bindingset[this]
Configuration() { this = this }
abstract predicate isSource(Source source);
abstract predicate isSink(Sink sink);
predicate isSanitizer(Sanitizer sanitizer) { none() }
predicate isExtension(Extension extension) { none() }
predicate hasFlowPath(PathSource source, PathSink sink) {
this.isSource(source.getNode()) and
this.isSink(sink.getNode()) and
source.flowsTo(sink)
}
predicate hasFlow(Source source, Sink sink) {
this.isSource(source) and
this.isSink(sink) and
source.flowsToSink(sink)
}
}
}
pragma [noinline]
private predicate dict_construct(ControlFlowNode itemnode, ControlFlowNode dictnode) {
dictnode.(DictNode).getAValue() = itemnode