Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions python/ql/src/semmle/python/dataflow/TaintTracking.qll
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
/* For compatibility with other language implementations */

import semmle.python.security.TaintTracking
196 changes: 168 additions & 28 deletions python/ql/src/semmle/python/security/TaintTracking.qll
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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)
)
)
Expand Down Expand Up @@ -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
totaint = fromnode.getTrackedValue()
)
or
exists(CallNode call |
fromnode.getNode().(DataFlowNode).getACalleeSuccessorNode(call) = tonode and
fromnode.getContext().getCallee(call) = tocontext 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(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 |
Expand Down Expand Up @@ -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
Expand All @@ -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())
Expand Down Expand Up @@ -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)
)
Expand All @@ -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)
)
|
Expand Down Expand Up @@ -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)
)
)
Expand Down Expand Up @@ -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
Expand Down