Python taint-tracking. Further improvements to new taint-tracking.

This commit is contained in:
Mark Shannon
2019-07-31 17:19:55 +01:00
parent 74f1dd3ec0
commit da6a66975c
3 changed files with 182 additions and 30 deletions

View File

@@ -86,7 +86,8 @@ module TaintTracking {
/* Old query API */
deprecated predicate hasFlow(Source source, Sink sink) {
/* deprecated */
predicate hasFlow(Source source, Sink sink) {
exists(PathSource psource, PathSink psink |
this.hasFlowPath(psource, psink) and
source = psource.getNode().asCfgNode() and

View File

@@ -1,6 +1,7 @@
import python
import semmle.python.security.TaintTracking
private import semmle.python.objects.ObjectInternal
private import semmle.python.pointsto.Filters as Filters
newtype TTaintTrackingContext =
TNoParam()
@@ -85,21 +86,14 @@ class NoAttribute extends TNoAttribute, AttributePath {
newtype TTaintTrackingNode =
TTaintTrackingNode_(DataFlow::Node node, TaintTrackingContext context, AttributePath path, TaintKind kind, TaintTracking::Configuration config) {
config.(TaintTrackingImplementation).flowSource(node, context, path, kind)
or
config.(TaintTrackingImplementation).flowStep(_, node, context, path, kind)
or
config.isSource(node, kind) and context = TNoParam() and path = TNoAttribute()
or
exists(TaintSource source |
config.isSource(source) and
node.asCfgNode() = source and
source.isSourceOf(kind)
) and
context = TNoParam() and path = TNoAttribute()
}
class TaintTrackingNode extends TTaintTrackingNode {
string toString() { result = this.getTaintKind() + " at " + this.getNode().getLocation() }
string toString() { result = this.getTaintKind().repr() }
DataFlow::Node getNode() {
this = TTaintTrackingNode_(result, _, _, _, _)
@@ -151,17 +145,39 @@ class TaintTrackingImplementation extends string {
sink = source.getASuccessor*()
}
predicate flowSource(DataFlow::Node node, TaintTrackingContext context, AttributePath path, TaintKind kind) {
this.(TaintTracking::Configuration).isSource(node, kind) and context = TNoParam() and path = TNoAttribute()
or
exists(TaintSource source |
this.(TaintTracking::Configuration).isSource(source) and
node.asCfgNode() = source and
source.isSourceOf(kind)
) and
context = TNoParam() and path = TNoAttribute()
}
predicate flowSink(DataFlow::Node node, AttributePath path, TaintKind kind) {
this.(TaintTracking::Configuration).isSink(node, kind) and path = TNoAttribute()
or
exists(TaintSink sink |
this.(TaintTracking::Configuration).isSink(sink) and
node.asCfgNode() = sink and
sink.sinks(kind)
) and path = TNoAttribute()
}
predicate isPathSource(TaintTrackingNode source) {
exists(DataFlow::Node srcnode, TaintKind kind |
source = TTaintTrackingNode_(srcnode, TNoParam(), TNoAttribute(), kind, this) and
this.(TaintTracking::Configuration).isSource(srcnode, kind)
exists(DataFlow::Node node, TaintTrackingContext context, AttributePath path, TaintKind kind |
source = TTaintTrackingNode_(node, context, path, kind, this) and
this.flowSource(node, context, path, kind)
)
}
predicate isPathSink(TaintTrackingNode sink) {
exists(DataFlow::Node sinknode, TaintKind kind |
sink = TTaintTrackingNode_(sinknode, _, TNoAttribute(), kind, this) and
this.(TaintTracking::Configuration).isSink(sinknode, kind)
exists(DataFlow::Node node, AttributePath path, TaintKind kind |
sink = TTaintTrackingNode_(node, _, path, kind, this) and
this.flowSink(node, path, kind)
)
}
@@ -172,19 +188,92 @@ class TaintTrackingImplementation extends string {
)
}
predicate flowBarrier(DataFlow::Node node, TaintKind kind) {
this.(TaintTracking::Configuration).isBarrier(node, kind)
or
exists(Sanitizer sanitizer |
this.(TaintTracking::Configuration).isSanitizer(sanitizer)
|
sanitizer.sanitizingNode(kind, node.asCfgNode())
or
sanitizer.sanitizingDefinition(kind, node.asVariable().getDefinition())
or
exists(MethodCallsiteRefinement call, FunctionObject callee |
call = node.asVariable().getDefinition() and
callee.getACall() = call.getCall() and
sanitizer.sanitizingCall(kind, callee)
)
or
sanitizer.sanitizingEdge(kind, node.asVariable().getDefinition())
or
sanitizer.sanitizingSingleEdge(kind, node.asVariable().getDefinition())
or
exists(PyEdgeRefinement test |
test = node.asVariable().getDefinition()
|
exists(ControlFlowNode c, ClassValue cls |
Filters::isinstance(test.getTest(), c, test.getInput().getSourceVariable().getAUse()) and
c.pointsTo(cls)
|
test.getSense() = true and not exists(kind.getClass())
or
test.getSense() = true and kind.getType().getASuperType() = cls
or
test.getSense() = false and not kind.getType().getASuperType() = cls
)
or
test.getSense() = test_evaluates(test.getTest(), test.getInput().getSourceVariable().getAUse(), kind)
)
)
}
/** Gets the boolean value that `test` evaluates to when `use` is tainted with `kind`
* and `test` and `use` are part of a test in a branch.
*/
private boolean test_evaluates(ControlFlowNode test, ControlFlowNode use, TaintKind kind) {
boolean_filter(_, use) and
kind.taints(use) and
test = use and result = kind.booleanValue()
or
result = test_evaluates(not_operand(test), use, kind).booleanNot()
}
/** Gets the operand of a unary `not` expression. */
private ControlFlowNode not_operand(ControlFlowNode expr) {
expr.(UnaryExprNode).getNode().getOp() instanceof Not and
result = expr.(UnaryExprNode).getOperand()
}
/** Holds if `test` is the test in a branch and `use` is that test
* with all the `not` prefixes removed.
*/
private predicate boolean_filter(ControlFlowNode test, ControlFlowNode use) {
any(PyEdgeRefinement ref).getTest() = test and
(
use = test
or
exists(ControlFlowNode notuse |
boolean_filter(test, notuse) and
use = not_operand(notuse)
)
)
}
TaintTrackingImplementation() { this instanceof TaintTracking::Configuration }
predicate flowStep(TaintTrackingNode src, DataFlow::Node node, TaintTrackingContext context, AttributePath path, TaintKind kind) {
this.unprunedStep(src, node, context, path, kind) and
node.getBasicBlock().likelyReachable()
node.getBasicBlock().likelyReachable() and
not this.(TaintTracking::Configuration).isBarrier(node) and
not this.flowBarrier(node, kind) and path = TNoAttribute()
}
predicate unprunedStep(TaintTrackingNode src, DataFlow::Node node, TaintTrackingContext context, AttributePath path, TaintKind kind) {
this.importStep(src, node, context, path, kind)
or
this.fromImportStep(src, node, context, path, kind)
//or
//this.attributeLoadStep(src, node, context, path, kind)
or
this.attributeLoadStep(src, node, context, path, kind)
//or
//this.getattrStep(src, node, context, path, kind)
or
@@ -193,17 +282,19 @@ class TaintTrackingImplementation extends string {
this.callTaintStep(src, node, context, path, kind)
or
this.returnFlowStep(src, node, context, path, kind)
//or
//this.iterationStep(src, node, context, path, kind)
or
this.iterationStep(src, node, context, path, kind)
//or
//this.yieldStep(src, node, context, path, kind)
//or
//this.subscriptStep(src, node, context, path, kind)
//or
//this.ifExprStep(src, node, context, path, kind)
or
this.ifExpStep(src, node, context, path, kind)
or
this.essaFlowStep(src, node, context, path, kind)
or
this.legacyExtensionStep(src, node, context, path, kind)
or
exists(DataFlow::Node srcnode, TaintKind srckind |
this.(TaintTracking::Configuration).isAdditionalFlowStep(srcnode, node, srckind, kind) and
src = TTaintTrackingNode_(srcnode, context, path, srckind, this) and
@@ -217,9 +308,12 @@ class TaintTrackingImplementation extends string {
)
or
exists(DataFlow::Node srcnode, TaintKind srckind |
kind = srckind.getTaintForFlowStep(srcnode.asCfgNode(), node.asCfgNode()) and
src = TTaintTrackingNode_(srcnode, context, path, kind, this) and
src = TTaintTrackingNode_(srcnode, context, path, srckind, this) and
path.noAttribute()
|
kind = srckind.getTaintForFlowStep(srcnode.asCfgNode(), node.asCfgNode())
or
kind.isResultOfStep(srckind, srcnode.asCfgNode(), node.asCfgNode())
)
}
@@ -239,9 +333,15 @@ class TaintTrackingImplementation extends string {
predicate attributeLoadStep(TaintTrackingNode src, DataFlow::Node node, TaintTrackingContext context, AttributePath path, TaintKind kind) {
exists(DataFlow::Node srcnode, AttributePath srcpath, string attrname |
src = TTaintTrackingNode_(srcnode, context, srcpath, kind, this) and
node.asCfgNode() = srcnode.asCfgNode().(AttrNode).getObject(attrname) and
srcnode.asCfgNode() = node.asCfgNode().(AttrNode).getObject(attrname) and
path = srcpath.fromAttribute(attrname)
)
or
exists(DataFlow::Node srcnode, TaintKind srckind, string attrname |
src = TTaintTrackingNode_(srcnode, context, path, srckind, this) and
srcnode.asCfgNode() = node.asCfgNode().(AttrNode).getObject(attrname) and
kind = srckind.getTaintOfAttribute(attrname)
)
}
pragma [noinline]
@@ -342,7 +442,7 @@ class TaintTrackingImplementation extends string {
}
pragma [noinline]
predicate ifExprStep(TaintTrackingNode src, DataFlow::Node node, TaintTrackingContext context, AttributePath path, TaintKind kind) {
predicate ifExpStep(TaintTrackingNode src, DataFlow::Node node, TaintTrackingContext context, AttributePath path, TaintKind kind) {
exists(DataFlow::Node srcnode |
src = TTaintTrackingNode_(srcnode, context, path, kind, this) and
srcnode.asCfgNode() = node.asCfgNode().(IfExprNode).getAnOperand()
@@ -354,6 +454,21 @@ class TaintTrackingImplementation extends string {
this.taintedDefinition(src, node.asVariable().getDefinition(), context, path, kind)
}
pragma [noinline]
predicate legacyExtensionStep(TaintTrackingNode src, DataFlow::Node node, TaintTrackingContext context, AttributePath path, TaintKind kind) {
exists(TaintTracking::Extension extension, DataFlow::Node srcnode, TaintKind srckind |
this.(TaintTracking::Configuration).isExtension(extension) and
src = TTaintTrackingNode_(srcnode, context, path, srckind, this) and
srcnode.asCfgNode() = extension
|
extension.getASuccessorNode() = node.asCfgNode() and kind = srckind
or
extension.getASuccessorNode(srckind, kind) = node.asCfgNode()
or
extension.getASuccessorVariable() = node.asVariable() and kind = srckind
)
}
pragma [noinline]
predicate taintedDefinition(TaintTrackingNode src, EssaDefinition defn, TaintTrackingContext context, AttributePath path, TaintKind kind) {
this.taintedPhi(src, defn, context, path, kind)
@@ -409,6 +524,12 @@ class TaintTrackingImplementation extends string {
defn.getDefiningNode() = pyfunc.getParameter(arg) and
context = TParamContext(kind, path, arg)
)
or
/* Tainted parameter (usually user-defined) */
exists(DataFlow::Node srcnode |
src = TTaintTrackingNode_(srcnode, context, path, kind, this) and
srcnode.asCfgNode() = defn.getDefiningNode()
)
}
pragma [noinline]
@@ -440,7 +561,7 @@ class TaintTrackingImplementation extends string {
}
pragma [noinline]
predicate taintedPiNode(TaintTrackingNode src, SingleSuccessorGuard defn, TaintTrackingContext context, AttributePath path, TaintKind kind) {
predicate taintedPiNode(TaintTrackingNode src, PyEdgeRefinement defn, TaintTrackingContext context, AttributePath path, TaintKind kind) {
exists(DataFlow::Node srcnode |
src = TTaintTrackingNode_(srcnode, context, path, kind, this) and
srcnode.asVariable() = defn.getInput() and

View File

@@ -120,6 +120,8 @@ abstract class TaintKind extends string {
*/
TaintKind getTaintForFlowStep(ControlFlowNode fromnode, ControlFlowNode tonode) { none() }
predicate isResultOfStep(TaintKind fromkind, ControlFlowNode fromnode, ControlFlowNode tonode) { none() }
/** DEPRECATED -- Use `TaintFlow.additionalFlowStepVar(EssaVariable fromvar, EssaVariable tovar, TaintKind kind)` instead.
*
* Holds if this kind of taint passes from variable `fromvar` to variable `tovar`
@@ -215,6 +217,8 @@ class SequenceKind extends CollectionKind {
result = this.getItem() and
result.getType() = ObjectInternal::builtin("str")
)
or
result = this.getItem() and SequenceKind::itemFlowStep(fromnode, tonode)
}
override TaintKind getTaintOfMethodResult(string name) {
@@ -229,6 +233,12 @@ class SequenceKind extends CollectionKind {
result = itemKind
}
override predicate isResultOfStep(TaintKind fromkind, ControlFlowNode fromnode, ControlFlowNode tonode) {
SequenceKind::flowStep(fromnode, tonode) and this = fromkind
or
sequence_construct(fromnode, tonode) and this.getItem() = fromkind
}
}
@@ -294,6 +304,12 @@ class DictKind extends CollectionKind {
result = "dict of " + valueKind
}
override predicate isResultOfStep(TaintKind fromkind, ControlFlowNode fromnode, ControlFlowNode tonode) {
DictKind::flowStep(fromnode, tonode) and this = fromkind
or
dict_construct(fromnode, tonode) and this.getValue() = fromkind
}
}
@@ -762,6 +778,9 @@ class TaintedPathSource extends TaintTrackingNode {
this.getASuccessor*() = sink
}
DataFlow::Node getSource() {
result = this.getNode()
}
}
@@ -774,6 +793,7 @@ class TaintedPathSink extends TaintTrackingNode {
DataFlow::Node getSink() {
result = this.getNode()
}
}
/** This module contains the implementation of taint-flow.
@@ -1680,7 +1700,17 @@ module DataFlow {
}
override string toString() {
result = this.asCfgNode().toString()
exists(ControlFlowNode n |
n = this.asCfgNode()
|
result = n.(TaintSource).toString()
or
result = n.(TaintSink).toString()
or
not n instanceof TaintSource and
not n instanceof TaintSink and
result = n.toString()
)
}
override Scope getScope() {