Python: Autoformat dataflow files

This commit is contained in:
Rasmus Wriedt Larsen
2020-01-23 13:20:22 +01:00
parent 816a8d1f9e
commit 9502756874
9 changed files with 512 additions and 536 deletions

View File

@@ -4,7 +4,6 @@ private import semmle.python.objects.ObjectInternal
private import semmle.python.dataflow.Implementation
module TaintTracking {
class Source = TaintSource;
class Sink = TaintSink;
@@ -16,13 +15,11 @@ module TaintTracking {
class PathSink = TaintTrackingNode;
abstract class Configuration extends string {
/* Required to prevent compiler warning */
bindingset[this]
Configuration() { this = this }
/* Old implementation API */
predicate isSource(Source src) { none() }
predicate isSink(Sink sink) { none() }
@@ -32,7 +29,6 @@ module TaintTracking {
predicate isExtension(Extension extension) { none() }
/* New implementation API */
/**
* Holds if `src` is a source of taint of `kind` that is relevant
* for this configuration.
@@ -66,7 +62,9 @@ module TaintTracking {
/**
* Holds if `src -> dest` is a flow edge converting taint from `srckind` to `destkind`.
*/
predicate isAdditionalFlowStep(DataFlow::Node src, DataFlow::Node dest, TaintKind srckind, TaintKind destkind) {
predicate isAdditionalFlowStep(
DataFlow::Node src, DataFlow::Node dest, TaintKind srckind, TaintKind destkind
) {
none()
}
@@ -79,9 +77,7 @@ module TaintTracking {
* Holds if `node` should be considered as a barrier to flow of `kind`.
*/
predicate isBarrier(DataFlow::Node node, TaintKind kind) {
exists(Sanitizer sanitizer |
this.isSanitizer(sanitizer)
|
exists(Sanitizer sanitizer | this.isSanitizer(sanitizer) |
sanitizer.sanitizingNode(kind, node.asCfgNode())
or
sanitizer.sanitizingEdge(kind, node.asVariable())
@@ -112,16 +108,18 @@ module TaintTracking {
* Holds if flow from `src` to `dest` is prohibited when the incoming taint is `srckind` and the outgoing taint is `destkind`.
* Note that `srckind` and `destkind` can be the same.
*/
predicate isBarrierEdge(DataFlow::Node src, DataFlow::Node dest, TaintKind srckind, TaintKind destkind) { none() }
predicate isBarrierEdge(
DataFlow::Node src, DataFlow::Node dest, TaintKind srckind, TaintKind destkind
) {
none()
}
/* Common query API */
predicate hasFlowPath(PathSource src, PathSink sink) {
this.(TaintTrackingImplementation).hasFlowPath(src, sink)
}
/* Old query API */
/* deprecated */
deprecated predicate hasFlow(Source src, Sink sink) {
exists(PathSource psrc, PathSink psink |
@@ -132,7 +130,6 @@ module TaintTracking {
}
/* New query API */
predicate hasSimpleFlow(DataFlow::Node src, DataFlow::Node sink) {
exists(PathSource psrc, PathSink psink |
this.hasFlowPath(psrc, psink) and
@@ -140,7 +137,5 @@ module TaintTracking {
sink = psink.getNode()
)
}
}
}

View File

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

View File

@@ -2,25 +2,18 @@ import python
import semmle.python.security.TaintTracking
class OpenFile extends TaintKind {
OpenFile() { this = "file.open" }
override string repr() { result = "an open file" }
}
class OpenFileConfiguration extends TaintTracking::Configuration {
OpenFileConfiguration() { this = "Open file configuration" }
OpenFileConfiguration() { this = "Open file configuration" }
override predicate isSource(DataFlow::Node src, TaintKind kind) {
theOpenFunction().(FunctionObject).getACall() = src.asCfgNode() and
kind instanceof OpenFile
}
override predicate isSink(DataFlow::Node sink, TaintKind kind) {
none()
}
override predicate isSink(DataFlow::Node sink, TaintKind kind) { none() }
}

View File

@@ -4,28 +4,27 @@ private import semmle.python.objects.ObjectInternal
private import semmle.python.pointsto.Filters as Filters
import semmle.python.dataflow.Legacy
/* See tests/library-tests/taint/examples
/*
* See tests/library-tests/taint/examples
* For examples of taint sources, sinks and flow,
* including attribute paths, contexts and edges.
*/
newtype TTaintTrackingContext =
TNoParam()
or
TNoParam() or
TParamContext(TaintKind param, AttributePath path, int n) {
any(TaintTrackingImplementation impl).callWithTaintedArgument(_, _, _, _, n, path, param)
}
/** The context for taint-tracking.
/**
* The context for taint-tracking.
* There are two types of contexts:
* * No context; the context at a source.
* * Tainted parameter; tracks the taint and attribute-path for a parameter
* Used to track taint through calls accurately and reasonably efficiently.
*/
class TaintTrackingContext extends TTaintTrackingContext {
string toString() {
string toString() {
this = TNoParam() and result = ""
or
exists(TaintKind param, AttributePath path, int n |
@@ -34,17 +33,11 @@ class TaintTrackingContext extends TTaintTrackingContext {
)
}
TaintKind getParameterTaint(int n) {
this = TParamContext(result, _, n)
}
TaintKind getParameterTaint(int n) { this = TParamContext(result, _, n) }
AttributePath getAttributePath() {
this = TParamContext(_, result, _)
}
AttributePath getAttributePath() { this = TParamContext(_, result, _) }
TaintTrackingContext getCaller() {
result = this.getCaller(_)
}
TaintTrackingContext getCaller() { result = this.getCaller(_) }
TaintTrackingContext getCaller(CallNode call) {
exists(TaintKind param, AttributePath path, int n |
@@ -55,60 +48,46 @@ class TaintTrackingContext extends TTaintTrackingContext {
)
}
predicate isTop() {
this = TNoParam()
}
predicate isTop() { this = TNoParam() }
}
private newtype TAttributePath =
TNoAttribute()
or
TAttribute(string name) {
exists(Attribute a | a.getName() = name)
}
/* It might make sense to add another level, attribute of attribute.
TNoAttribute() or
/*
* It might make sense to add another level, attribute of attribute.
* But some experimentation would be needed.
*/
TAttribute(string name) { exists(Attribute a | a.getName() = name) }
/** The attribute of the tracked value holding the taint.
/**
* The attribute of the tracked value holding the taint.
* This is usually "no attribute".
* Used for tracking tainted attributes of objects.
*/
abstract class AttributePath extends TAttributePath {
abstract string toString();
abstract string extension();
abstract AttributePath fromAttribute(string name);
AttributePath getAttribute(string name) {
this = result.fromAttribute(name)
}
predicate noAttribute() {
this = TNoAttribute()
}
AttributePath getAttribute(string name) { this = result.fromAttribute(name) }
predicate noAttribute() { this = TNoAttribute() }
}
/** AttributePath for no attribute. */
class NoAttribute extends TNoAttribute, AttributePath {
override string toString() { result = "no attribute" }
override string extension() { result = "" }
override AttributePath fromAttribute(string name) {
none()
}
override AttributePath fromAttribute(string name) { none() }
}
/** AttributePath for an attribute. */
class NamedAttributePath extends TAttribute, AttributePath {
override string toString() {
exists(string attr |
this = TAttribute(attr) and
@@ -126,76 +105,57 @@ class NamedAttributePath extends TAttribute, AttributePath {
override AttributePath fromAttribute(string name) {
this = TAttribute(name) and result = TNoAttribute()
}
}
/** Type representing the (node, context, path, kind) tuple.
* Construction of this type is mutually recursive with `TaintTrackingImplementation.flowStep(...)`
/**
* Type representing the (node, context, path, kind) tuple.
* Construction of this type is mutually recursive with `TaintTrackingImplementation.flowStep(...)`
*/
newtype TTaintTrackingNode =
TTaintTrackingNode_(DataFlow::Node node, TaintTrackingContext context, AttributePath path, TaintKind kind, TaintTracking::Configuration config) {
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, _)
}
/** Class representing the (node, context, path, kind) tuple.
/**
* Class representing the (node, context, path, kind) tuple.
* Used for context-sensitive path-aware taint-tracking.
*/
class TaintTrackingNode extends TTaintTrackingNode {
string toString() {
if this.getPath() instanceof NoAttribute then (
result = this.getTaintKind().repr()
) else (
result = this.getPath().extension() + " = " + this.getTaintKind().repr()
)
if this.getPath() instanceof NoAttribute
then result = this.getTaintKind().repr()
else result = this.getPath().extension() + " = " + this.getTaintKind().repr()
}
/** Gets the data flow node for this taint-tracking node */
DataFlow::Node getNode() {
this = TTaintTrackingNode_(result, _, _, _, _)
}
DataFlow::Node getNode() { this = TTaintTrackingNode_(result, _, _, _, _) }
/** Gets the taint kind for this taint-tracking node */
TaintKind getTaintKind() {
this = TTaintTrackingNode_(_, _, _, result, _)
}
TaintKind getTaintKind() { this = TTaintTrackingNode_(_, _, _, result, _) }
/** Gets the taint-tracking context for this taint-tracking node */
TaintTrackingContext getContext() {
this = TTaintTrackingNode_(_, result, _, _, _)
}
TaintTrackingContext getContext() { this = TTaintTrackingNode_(_, result, _, _, _) }
/** Gets the attribute path context for this taint-tracking node */
AttributePath getPath() {
this = TTaintTrackingNode_(_, _, result, _, _)
}
AttributePath getPath() { this = TTaintTrackingNode_(_, _, result, _, _) }
TaintTracking::Configuration getConfiguration() {
this = TTaintTrackingNode_(_, _, _, _, result)
}
TaintTracking::Configuration getConfiguration() { this = TTaintTrackingNode_(_, _, _, _, result) }
Location getLocation() {
result = this.getNode().getLocation()
}
Location getLocation() { result = this.getNode().getLocation() }
predicate isSource() {
this.getConfiguration().(TaintTrackingImplementation).isPathSource(this)
}
predicate isSource() { this.getConfiguration().(TaintTrackingImplementation).isPathSource(this) }
predicate isSink() {
this.getConfiguration().(TaintTrackingImplementation).isPathSink(this)
}
predicate isSink() { this.getConfiguration().(TaintTrackingImplementation).isPathSink(this) }
ControlFlowNode getCfgNode() {
result = this.getNode().asCfgNode()
}
ControlFlowNode getCfgNode() { result = this.getNode().asCfgNode() }
/** Get the AST node for this node. */
AstNode getAstNode() {
result = this.getCfgNode().getNode()
}
AstNode getAstNode() { result = this.getCfgNode().getNode() }
TaintTrackingNode getASuccessor(string edgeLabel) {
this.isVisible() and
@@ -225,24 +185,20 @@ class TaintTrackingNode extends TTaintTrackingNode {
this.isSource()
}
predicate flowsTo(TaintTrackingNode other) {
this.getASuccessor*() = other
}
predicate flowsTo(TaintTrackingNode other) { this.getASuccessor*() = other }
}
/** The implementation of taint-tracking
/**
* The implementation of taint-tracking
* Each `TaintTrackingImplementation` is also a `TaintTracking::Configuration`
* It is implemented as a separate class for clarity and to keep the code
* in `TaintTracking::Configuration` simpler.
*/
class TaintTrackingImplementation extends string {
TaintTrackingImplementation() { this instanceof TaintTracking::Configuration }
TaintTrackingImplementation() {
this instanceof TaintTracking::Configuration
}
/** Hold if there is a flow from `source`, which is a taint source, to
/**
* Hold if there is a flow from `source`, which is a taint source, to
* `sink`, which is a taint sink, with this configuration.
*/
predicate hasFlowPath(TaintTrackingNode source, TaintTrackingNode sink) {
@@ -251,10 +207,14 @@ class TaintTrackingImplementation extends string {
source.flowsTo(sink)
}
/** Hold if `node` is a source of taint `kind` with context `context` and attribute path `path`.
/**
* Hold if `node` is a source of taint `kind` with context `context` and attribute path `path`.
*/
predicate flowSource(DataFlow::Node node, TaintTrackingContext context, AttributePath path, TaintKind kind) {
context = TNoParam() and path = TNoAttribute() and
predicate flowSource(
DataFlow::Node node, TaintTrackingContext context, AttributePath path, TaintKind kind
) {
context = TNoParam() and
path = TNoAttribute() and
this.(TaintTracking::Configuration).isSource(node, kind)
}
@@ -275,7 +235,8 @@ class TaintTrackingImplementation extends string {
)
}
/** Hold if taint flows to `src` to `dest` in a single step, labeled with `edgeLabel`
/**
* Hold if taint flows to `src` to `dest` in a single step, labeled with `edgeLabel`
* `edgeLabel` is purely informative.
*/
predicate flowStep(TaintTrackingNode src, TaintTrackingNode dest, string edgeLabel) {
@@ -285,10 +246,14 @@ class TaintTrackingImplementation extends string {
)
}
/** Hold if taint flows to `src` to `(node, context, path, kind)` in a single step, labelled with `egdeLabel` with this configuration.
/**
* Hold if taint flows to `src` to `(node, context, path, kind)` in a single step, labelled with `egdeLabel` with this configuration.
* `edgeLabel` is purely informative.
*/
predicate flowStep(TaintTrackingNode src, DataFlow::Node node, TaintTrackingContext context, AttributePath path, TaintKind kind, string edgeLabel) {
predicate flowStep(
TaintTrackingNode src, DataFlow::Node node, TaintTrackingContext context, AttributePath path,
TaintKind kind, string edgeLabel
) {
this.unprunedStep(src, node, context, path, kind, edgeLabel) and
node.getBasicBlock().likelyReachable() and
not this.(TaintTracking::Configuration).isBarrier(node) and
@@ -303,13 +268,18 @@ class TaintTrackingImplementation extends string {
)
}
private predicate prunedEdge(DataFlow::Node srcnode, DataFlow::Node destnode, TaintKind srckind, TaintKind destkind) {
private predicate prunedEdge(
DataFlow::Node srcnode, DataFlow::Node destnode, TaintKind srckind, TaintKind destkind
) {
this.(TaintTracking::Configuration).isBarrierEdge(srcnode, destnode, srckind, destkind)
or
srckind = destkind and this.(TaintTracking::Configuration).isBarrierEdge(srcnode, destnode)
}
private predicate unprunedStep(TaintTrackingNode src, DataFlow::Node node, TaintTrackingContext context, AttributePath path, TaintKind kind, string edgeLabel) {
private predicate unprunedStep(
TaintTrackingNode src, DataFlow::Node node, TaintTrackingContext context, AttributePath path,
TaintKind kind, string edgeLabel
) {
this.importStep(src, node, context, path, kind, edgeLabel)
or
this.fromImportStep(src, node, context, path, kind, edgeLabel)
@@ -343,19 +313,21 @@ class TaintTrackingImplementation extends string {
exists(DataFlow::Node srcnode, TaintKind srckind |
this.(TaintTracking::Configuration).isAdditionalFlowStep(srcnode, node, srckind, kind) and
src = TTaintTrackingNode_(srcnode, context, path, srckind, this) and
path.noAttribute() and edgeLabel = "additional with kind"
path.noAttribute() and
edgeLabel = "additional with kind"
)
or
exists(DataFlow::Node srcnode |
this.(TaintTracking::Configuration).isAdditionalFlowStep(srcnode, node) and
src = TTaintTrackingNode_(srcnode, context, path, kind, this) and
path.noAttribute() and edgeLabel = "additional"
path.noAttribute() and
edgeLabel = "additional"
)
or
exists(DataFlow::Node srcnode, TaintKind srckind |
src = TTaintTrackingNode_(srcnode, context, path, srckind, this) and
path.noAttribute()
|
|
kind = srckind.getTaintForFlowStep(srcnode.asCfgNode(), node.asCfgNode(), edgeLabel)
or
kind = srckind.(CollectionKind).getMember() and
@@ -368,14 +340,21 @@ class TaintTrackingImplementation extends string {
or
kind = srckind and srckind.flowStep(srcnode, node, edgeLabel)
or
kind = srckind and srckind instanceof DictKind and DictKind::flowStep(srcnode.asCfgNode(), node.asCfgNode(), edgeLabel)
kind = srckind and
srckind instanceof DictKind and
DictKind::flowStep(srcnode.asCfgNode(), node.asCfgNode(), edgeLabel)
or
kind = srckind and srckind instanceof SequenceKind and SequenceKind::flowStep(srcnode.asCfgNode(), node.asCfgNode(), edgeLabel)
kind = srckind and
srckind instanceof SequenceKind and
SequenceKind::flowStep(srcnode.asCfgNode(), node.asCfgNode(), edgeLabel)
)
}
pragma [noinline]
predicate importStep(TaintTrackingNode src, DataFlow::Node node, TaintTrackingContext context, AttributePath path, TaintKind kind, string edgeLabel) {
pragma[noinline]
predicate importStep(
TaintTrackingNode src, DataFlow::Node node, TaintTrackingContext context, AttributePath path,
TaintKind kind, string edgeLabel
) {
edgeLabel = "import" and
exists(ModuleValue m, string name, AttributePath srcpath |
src = TTaintTrackingNode_(_, context, srcpath, kind, this) and
@@ -385,8 +364,11 @@ class TaintTrackingImplementation extends string {
)
}
pragma [noinline]
predicate fromImportStep(TaintTrackingNode src, DataFlow::Node node, TaintTrackingContext context, AttributePath path, TaintKind kind, string edgeLabel) {
pragma[noinline]
predicate fromImportStep(
TaintTrackingNode src, DataFlow::Node node, TaintTrackingContext context, AttributePath path,
TaintKind kind, string edgeLabel
) {
edgeLabel = "from import" and
exists(ModuleValue m, string name |
src = TTaintTrackingNode_(_, context, path, kind, this) and
@@ -395,24 +377,32 @@ class TaintTrackingImplementation extends string {
)
}
pragma [noinline]
predicate attributeLoadStep(TaintTrackingNode src, DataFlow::Node node, TaintTrackingContext context, AttributePath path, TaintKind kind, string edgeLabel) {
pragma[noinline]
predicate attributeLoadStep(
TaintTrackingNode src, DataFlow::Node node, TaintTrackingContext context, AttributePath path,
TaintKind kind, string edgeLabel
) {
exists(DataFlow::Node srcnode, AttributePath srcpath, string attrname |
src = TTaintTrackingNode_(srcnode, context, srcpath, kind, this) and
srcnode.asCfgNode() = node.asCfgNode().(AttrNode).getObject(attrname) and
path = srcpath.fromAttribute(attrname) and edgeLabel = "from path attribute"
path = srcpath.fromAttribute(attrname) and
edgeLabel = "from path attribute"
)
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) and edgeLabel = "from taint attribute" and
kind = srckind.getTaintOfAttribute(attrname) and
edgeLabel = "from taint attribute" and
path instanceof NoAttribute
)
}
pragma [noinline]
predicate getattrStep(TaintTrackingNode src, DataFlow::Node node, TaintTrackingContext context, AttributePath path, TaintKind kind, string edgeLabel) {
pragma[noinline]
predicate getattrStep(
TaintTrackingNode src, DataFlow::Node node, TaintTrackingContext context, AttributePath path,
TaintKind kind, string edgeLabel
) {
exists(DataFlow::Node srcnode, AttributePath srcpath, TaintKind srckind, string attrname |
src = TTaintTrackingNode_(srcnode, context, srcpath, srckind, this) and
exists(CallNode call, ControlFlowNode arg |
@@ -421,67 +411,96 @@ class TaintTrackingImplementation extends string {
arg = call.getArg(0) and
attrname = call.getArg(1).getNode().(StrConst).getText() and
arg = srcnode.asCfgNode()
|
|
path = srcpath.fromAttribute(attrname) and
kind = srckind
or
path = srcpath and
kind = srckind.getTaintOfAttribute(attrname)
)
) and edgeLabel = "getattr"
) and
edgeLabel = "getattr"
}
pragma [noinline]
predicate useStep(TaintTrackingNode src, DataFlow::Node node, TaintTrackingContext context, AttributePath path, TaintKind kind, string edgeLabel) {
pragma[noinline]
predicate useStep(
TaintTrackingNode src, DataFlow::Node node, TaintTrackingContext context, AttributePath path,
TaintKind kind, string edgeLabel
) {
exists(DataFlow::Node srcnode |
src = TTaintTrackingNode_(srcnode, context, path, kind, this) and
node.asCfgNode() = srcnode.asVariable().getASourceUse()
) and edgeLabel = "use"
) and
edgeLabel = "use"
}
/* If the return value is tainted without context, then it always flows back to the caller */
pragma [noinline]
predicate returnFlowStep(TaintTrackingNode src, DataFlow::Node node, TaintTrackingContext context, AttributePath path, TaintKind kind, string edgeLabel) {
pragma[noinline]
predicate returnFlowStep(
TaintTrackingNode src, DataFlow::Node node, TaintTrackingContext context, AttributePath path,
TaintKind kind, string edgeLabel
) {
exists(CallNode call, PythonFunctionObjectInternal pyfunc, DataFlow::Node retval |
pyfunc.getACall() = call and
context = TNoParam() and
src = TTaintTrackingNode_(retval, TNoParam(), path, kind, this) and
node.asCfgNode() = call and
retval.asCfgNode() = any(Return ret | ret.getScope() = pyfunc.getScope()).getValue().getAFlowNode()
retval.asCfgNode() = any(Return ret | ret.getScope() = pyfunc.getScope())
.getValue()
.getAFlowNode()
) and
edgeLabel = "return"
}
/* Avoid taint flow from return value to caller as it can produce imprecise flow graphs
/*
* Avoid taint flow from return value to caller as it can produce imprecise flow graphs
* Step directly from tainted argument to call result.
*/
pragma [noinline]
predicate callFlowStep(TaintTrackingNode src, DataFlow::Node node, TaintTrackingContext context, AttributePath path, TaintKind kind, string edgeLabel) {
exists(CallNode call, PythonFunctionObjectInternal pyfunc, TaintTrackingContext callee, DataFlow::Node retval, TaintTrackingNode retnode |
pragma[noinline]
predicate callFlowStep(
TaintTrackingNode src, DataFlow::Node node, TaintTrackingContext context, AttributePath path,
TaintKind kind, string edgeLabel
) {
exists(
CallNode call, PythonFunctionObjectInternal pyfunc, TaintTrackingContext callee,
DataFlow::Node retval, TaintTrackingNode retnode
|
this.callContexts(call, src, pyfunc, context, callee) and
retnode = TTaintTrackingNode_(retval, callee, path, kind, this) and
node.asCfgNode() = call and
retval.asCfgNode() = any(Return ret | ret.getScope() = pyfunc.getScope()).getValue().getAFlowNode()
retval.asCfgNode() = any(Return ret | ret.getScope() = pyfunc.getScope())
.getValue()
.getAFlowNode()
) and
edgeLabel = "call"
}
pragma [noinline]
predicate callContexts(CallNode call, TaintTrackingNode argnode, PythonFunctionObjectInternal pyfunc, TaintTrackingContext caller, TaintTrackingContext callee) {
pragma[noinline]
predicate callContexts(
CallNode call, TaintTrackingNode argnode, PythonFunctionObjectInternal pyfunc,
TaintTrackingContext caller, TaintTrackingContext callee
) {
exists(int arg, TaintKind callerKind, AttributePath callerPath |
this.callWithTaintedArgument(argnode, call, caller, pyfunc, arg, callerPath, callerKind) and
callee = TParamContext(callerKind, callerPath, arg)
)
}
predicate callWithTaintedArgument(TaintTrackingNode src, CallNode call, TaintTrackingContext caller, CallableValue pyfunc, int arg, AttributePath path, TaintKind kind) {
predicate callWithTaintedArgument(
TaintTrackingNode src, CallNode call, TaintTrackingContext caller, CallableValue pyfunc,
int arg, AttributePath path, TaintKind kind
) {
exists(DataFlow::Node srcnode |
src = TTaintTrackingNode_(srcnode, caller, path, kind, this) and
srcnode.asCfgNode() = pyfunc.getArgumentForCall(call, arg)
)
}
predicate instantiationStep(TaintTrackingNode src, DataFlow::Node node, TaintTrackingContext context, AttributePath path, TaintKind kind, string edgeLabel) {
predicate instantiationStep(
TaintTrackingNode src, DataFlow::Node node, TaintTrackingContext context, AttributePath path,
TaintKind kind, string edgeLabel
) {
exists(PythonFunctionValue init, EssaVariable self, TaintTrackingContext callee |
instantiationCall(node.asCfgNode(), src, init, context, callee) and
this.(EssaTaintTracking).taintedDefinition(_, self.getDefinition(), callee, path, kind) and
@@ -492,51 +511,69 @@ class TaintTrackingImplementation extends string {
edgeLabel = "instantiation"
}
predicate instantiationCall(CallNode call, TaintTrackingNode argnode, PythonFunctionObjectInternal init, TaintTrackingContext caller, TaintTrackingContext callee) {
predicate instantiationCall(
CallNode call, TaintTrackingNode argnode, PythonFunctionObjectInternal init,
TaintTrackingContext caller, TaintTrackingContext callee
) {
exists(ClassValue cls |
call.getFunction().pointsTo(cls) and
cls.lookup("__init__") = init
|
|
exists(int arg, TaintKind callerKind, AttributePath callerPath, DataFlow::Node argument |
argnode = TTaintTrackingNode_(argument, caller, callerPath, callerKind, this) and
call.getArg(arg-1) = argument.asCfgNode() and
call.getArg(arg - 1) = argument.asCfgNode() and
callee = TParamContext(callerKind, callerPath, arg)
)
)
}
pragma [noinline]
predicate callTaintStep(TaintTrackingNode src, DataFlow::Node node, TaintTrackingContext context, AttributePath path, TaintKind kind, string edgeLabel) {
pragma[noinline]
predicate callTaintStep(
TaintTrackingNode src, DataFlow::Node node, TaintTrackingContext context, AttributePath path,
TaintKind kind, string edgeLabel
) {
exists(DataFlow::Node srcnode, CallNode call, TaintKind srckind, string name |
src = TTaintTrackingNode_(srcnode, context, path, srckind, this) and
call.getFunction().(AttrNode).getObject(name) = src.getNode().asCfgNode() and
kind = srckind.getTaintOfMethodResult(name) and
node.asCfgNode() = call
) and edgeLabel = "call"
) and
edgeLabel = "call"
}
pragma [noinline]
predicate iterationStep(TaintTrackingNode src, DataFlow::Node node, TaintTrackingContext context, AttributePath path, TaintKind kind, string edgeLabel) {
pragma[noinline]
predicate iterationStep(
TaintTrackingNode src, DataFlow::Node node, TaintTrackingContext context, AttributePath path,
TaintKind kind, string edgeLabel
) {
exists(ForNode for, DataFlow::Node sequence, TaintKind seqkind |
src = TTaintTrackingNode_(sequence, context, path, seqkind, this) and
for.iterates(_, sequence.asCfgNode()) and
node.asCfgNode() = for and
path.noAttribute() and
kind = seqkind.getTaintForIteration()
) and edgeLabel = "iteration"
) and
edgeLabel = "iteration"
}
pragma [noinline]
predicate parameterStep(TaintTrackingNode src, DataFlow::Node node, TaintTrackingContext context, AttributePath path, TaintKind kind, string edgeLabel) {
pragma[noinline]
predicate parameterStep(
TaintTrackingNode src, DataFlow::Node node, TaintTrackingContext context, AttributePath path,
TaintKind kind, string edgeLabel
) {
exists(CallNode call, PythonFunctionObjectInternal pyfunc, int arg |
this.callWithTaintedArgument(src, call, _, pyfunc, arg, path, kind) and
node.asCfgNode() = pyfunc.getParameter(arg) and
context = TParamContext(kind, path, arg)
) and edgeLabel = "parameter"
) and
edgeLabel = "parameter"
}
pragma [noinline]
predicate yieldStep(TaintTrackingNode src, DataFlow::Node node, TaintTrackingContext context, AttributePath path, TaintKind kind, string edgeLabel) {
pragma[noinline]
predicate yieldStep(
TaintTrackingNode src, DataFlow::Node node, TaintTrackingContext context, AttributePath path,
TaintKind kind, string edgeLabel
) {
exists(DataFlow::Node srcnode, TaintKind itemkind |
src = TTaintTrackingNode_(srcnode, context, path, itemkind, this) and
itemkind = kind.getTaintForIteration() and
@@ -548,35 +585,50 @@ class TaintTrackingImplementation extends string {
yield.getValue() = srcnode.asCfgNode().getNode()
)
)
) and edgeLabel = "yield"
) and
edgeLabel = "yield"
}
pragma [noinline]
predicate ifExpStep(TaintTrackingNode src, DataFlow::Node node, TaintTrackingContext context, AttributePath path, TaintKind kind, string edgeLabel) {
pragma[noinline]
predicate ifExpStep(
TaintTrackingNode src, DataFlow::Node node, TaintTrackingContext context, AttributePath path,
TaintKind kind, string edgeLabel
) {
exists(DataFlow::Node srcnode |
src = TTaintTrackingNode_(srcnode, context, path, kind, this) and
srcnode.asCfgNode() = node.asCfgNode().(IfExprNode).getAnOperand()
) and edgeLabel = "if exp"
) and
edgeLabel = "if exp"
}
pragma [noinline]
predicate essaFlowStep(TaintTrackingNode src, DataFlow::Node node, TaintTrackingContext context, AttributePath path, TaintKind kind, string edgeLabel) {
this.(EssaTaintTracking).taintedDefinition(src, node.asVariable().getDefinition(), context, path, kind) and edgeLabel = ""
pragma[noinline]
predicate essaFlowStep(
TaintTrackingNode src, DataFlow::Node node, TaintTrackingContext context, AttributePath path,
TaintKind kind, string edgeLabel
) {
this
.(EssaTaintTracking)
.taintedDefinition(src, node.asVariable().getDefinition(), context, path, kind) and
edgeLabel = ""
}
pragma [noinline]
predicate legacyExtensionStep(TaintTrackingNode src, DataFlow::Node node, TaintTrackingContext context, AttributePath path, TaintKind kind, string edgeLabel) {
pragma[noinline]
predicate legacyExtensionStep(
TaintTrackingNode src, DataFlow::Node node, TaintTrackingContext context, AttributePath path,
TaintKind kind, string edgeLabel
) {
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
) and edgeLabel = "legacy extension"
) and
edgeLabel = "legacy extension"
}
predicate moduleAttributeTainted(ModuleValue m, string name, TaintTrackingNode taint) {
@@ -588,18 +640,20 @@ class TaintTrackingImplementation extends string {
var.getScope() = m.getScope()
)
}
}
/** Another taint-tracking class to help partition the code for clarity
* This class handle tracking of ESSA variables. */
/**
* Another taint-tracking class to help partition the code for clarity
* This class handle tracking of ESSA variables.
*/
private class EssaTaintTracking extends string {
EssaTaintTracking() { this instanceof TaintTracking::Configuration }
EssaTaintTracking() {
this instanceof TaintTracking::Configuration
}
pragma [noinline]
predicate taintedDefinition(TaintTrackingNode src, EssaDefinition defn, TaintTrackingContext context, AttributePath path, TaintKind kind) {
pragma[noinline]
predicate taintedDefinition(
TaintTrackingNode src, EssaDefinition defn, TaintTrackingContext context, AttributePath path,
TaintKind kind
) {
this.taintedPhi(src, defn, context, path, kind)
or
this.taintedAssignment(src, defn, context, path, kind)
@@ -625,8 +679,11 @@ private class EssaTaintTracking extends string {
this.taintedWith(src, defn, context, path, kind)
}
pragma [noinline]
private predicate taintedPhi(TaintTrackingNode src, PhiFunction defn, TaintTrackingContext context, AttributePath path, TaintKind kind) {
pragma[noinline]
private predicate taintedPhi(
TaintTrackingNode src, PhiFunction defn, TaintTrackingContext context, AttributePath path,
TaintKind kind
) {
exists(DataFlow::Node srcnode, BasicBlock pred, EssaVariable predvar, DataFlow::Node phi |
src = TTaintTrackingNode_(srcnode, context, path, kind, this) and
defn = phi.asVariable().getDefinition() and
@@ -637,16 +694,22 @@ private class EssaTaintTracking extends string {
)
}
pragma [noinline]
private predicate taintedAssignment(TaintTrackingNode src, AssignmentDefinition defn, TaintTrackingContext context, AttributePath path, TaintKind kind) {
pragma[noinline]
private predicate taintedAssignment(
TaintTrackingNode src, AssignmentDefinition defn, TaintTrackingContext context,
AttributePath path, TaintKind kind
) {
exists(DataFlow::Node srcnode |
src = TTaintTrackingNode_(srcnode, context, path, kind, this) and
defn.getValue() = srcnode.asCfgNode()
)
}
pragma [noinline]
private predicate taintedAttributeAssignment(TaintTrackingNode src, AttributeAssignment defn, TaintTrackingContext context, AttributePath path, TaintKind kind) {
pragma[noinline]
private predicate taintedAttributeAssignment(
TaintTrackingNode src, AttributeAssignment defn, TaintTrackingContext context,
AttributePath path, TaintKind kind
) {
exists(DataFlow::Node srcnode, AttributePath srcpath, string attrname |
src = TTaintTrackingNode_(srcnode, context, srcpath, kind, this) and
defn.getValue() = srcnode.asCfgNode() and
@@ -655,35 +718,49 @@ private class EssaTaintTracking extends string {
)
}
pragma [noinline]
private predicate taintedParameterDefinition(TaintTrackingNode src, ParameterDefinition defn, TaintTrackingContext context, AttributePath path, TaintKind kind) {
pragma[noinline]
private predicate taintedParameterDefinition(
TaintTrackingNode src, ParameterDefinition defn, TaintTrackingContext context,
AttributePath path, TaintKind kind
) {
exists(DataFlow::Node srcnode |
src = TTaintTrackingNode_(srcnode, context, path, kind, this) and
srcnode.asCfgNode() = defn.getDefiningNode()
)
}
pragma [noinline]
private predicate taintedCallsite(TaintTrackingNode src, CallsiteRefinement defn, TaintTrackingContext context, AttributePath path, TaintKind kind) {
/* In the interest of simplicity and performance we assume that tainted escaping variables remain tainted across calls.
pragma[noinline]
private predicate taintedCallsite(
TaintTrackingNode src, CallsiteRefinement defn, TaintTrackingContext context,
AttributePath path, TaintKind kind
) {
/*
* In the interest of simplicity and performance we assume that tainted escaping variables remain tainted across calls.
* In the cases were this assumption is false, it is easy enough to add an additional barrier.
*/
exists(DataFlow::Node srcnode |
src = TTaintTrackingNode_(srcnode, context, path, kind, this) and
srcnode.asVariable() = defn.getInput()
)
}
pragma [noinline]
private predicate taintedMethodCallsite(TaintTrackingNode src, MethodCallsiteRefinement defn, TaintTrackingContext context, AttributePath path, TaintKind kind) {
exists(DataFlow::Node srcnode |
src = TTaintTrackingNode_(srcnode, context, path, kind, this) and
srcnode.asVariable() = defn.getInput()
)
}
pragma [noinline]
private predicate taintedUniEdge(TaintTrackingNode src, SingleSuccessorGuard defn, TaintTrackingContext context, AttributePath path, TaintKind kind) {
pragma[noinline]
private predicate taintedMethodCallsite(
TaintTrackingNode src, MethodCallsiteRefinement defn, TaintTrackingContext context,
AttributePath path, TaintKind kind
) {
exists(DataFlow::Node srcnode |
src = TTaintTrackingNode_(srcnode, context, path, kind, this) and
srcnode.asVariable() = defn.getInput()
)
}
pragma[noinline]
private predicate taintedUniEdge(
TaintTrackingNode src, SingleSuccessorGuard defn, TaintTrackingContext context,
AttributePath path, TaintKind kind
) {
exists(DataFlow::Node srcnode |
src = TTaintTrackingNode_(srcnode, context, path, kind, this) and
srcnode.asVariable() = defn.getInput() and
@@ -691,14 +768,20 @@ private class EssaTaintTracking extends string {
)
}
private predicate taintedPiNode(TaintTrackingNode src, PyEdgeRefinement defn, TaintTrackingContext context, AttributePath path, TaintKind kind) {
private predicate taintedPiNode(
TaintTrackingNode src, PyEdgeRefinement defn, TaintTrackingContext context, AttributePath path,
TaintKind kind
) {
taintedPiNodeOneway(src, defn, context, path, kind)
or
taintedPiNodeBothways(src, defn, context, path, kind)
}
pragma [noinline]
private predicate taintedPiNodeOneway(TaintTrackingNode src, PyEdgeRefinement defn, TaintTrackingContext context, AttributePath path, TaintKind kind) {
pragma[noinline]
private predicate taintedPiNodeOneway(
TaintTrackingNode src, PyEdgeRefinement defn, TaintTrackingContext context, AttributePath path,
TaintKind kind
) {
exists(DataFlow::Node srcnode, ControlFlowNode use |
src = TTaintTrackingNode_(srcnode, context, path, kind, this) and
not this.(TaintTracking::Configuration).isBarrierTest(defn.getTest(), defn.getSense()) and
@@ -706,8 +789,11 @@ private class EssaTaintTracking extends string {
)
}
pragma [noinline]
private predicate taintedPiNodeBothways(TaintTrackingNode src, PyEdgeRefinement defn, TaintTrackingContext context, AttributePath path, TaintKind kind) {
pragma[noinline]
private predicate taintedPiNodeBothways(
TaintTrackingNode src, PyEdgeRefinement defn, TaintTrackingContext context, AttributePath path,
TaintKind kind
) {
exists(DataFlow::Node srcnode, ControlFlowNode test, ControlFlowNode use |
src = TTaintTrackingNode_(srcnode, context, path, kind, this) and
piNodeTestAndUse(defn, test, use) and
@@ -717,49 +803,63 @@ private class EssaTaintTracking extends string {
)
}
pragma [noinline]
private predicate taintedArgument(TaintTrackingNode src, ArgumentRefinement defn, TaintTrackingContext context, AttributePath path, TaintKind kind) {
pragma[noinline]
private predicate taintedArgument(
TaintTrackingNode src, ArgumentRefinement defn, TaintTrackingContext context,
AttributePath path, TaintKind kind
) {
exists(DataFlow::Node srcnode |
src = TTaintTrackingNode_(srcnode, context, path, kind, this) and
defn.getInput() = srcnode.asVariable()
)
}
pragma [noinline]
private predicate taintedExceptionCapture(TaintTrackingNode src, ExceptionCapture defn, TaintTrackingContext context, AttributePath path, TaintKind kind) {
pragma[noinline]
private predicate taintedExceptionCapture(
TaintTrackingNode src, ExceptionCapture defn, TaintTrackingContext context, AttributePath path,
TaintKind kind
) {
exists(DataFlow::Node srcnode |
src = TTaintTrackingNode_(srcnode, context, path, kind, this) and
srcnode.asCfgNode() = defn.getDefiningNode()
)
}
pragma [noinline]
private predicate taintedScopeEntryDefinition(TaintTrackingNode src, ScopeEntryDefinition defn, TaintTrackingContext context, AttributePath path, TaintKind kind) {
pragma[noinline]
private predicate taintedScopeEntryDefinition(
TaintTrackingNode src, ScopeEntryDefinition defn, TaintTrackingContext context,
AttributePath path, TaintKind kind
) {
exists(EssaVariable var |
BaseFlow::scope_entry_value_transfer_from_earlier(var, _, defn, _) and
this.taintedDefinition(src, var.getDefinition(), context, path, kind)
)
}
pragma [noinline]
private predicate taintedWith(TaintTrackingNode src, WithDefinition defn, TaintTrackingContext context, AttributePath path, TaintKind kind) {
pragma[noinline]
private predicate taintedWith(
TaintTrackingNode src, WithDefinition defn, TaintTrackingContext context, AttributePath path,
TaintKind kind
) {
exists(DataFlow::Node srcnode |
src = TTaintTrackingNode_(srcnode, context, path, kind, this) and
with_flow(_, srcnode.asCfgNode(), defn.getDefiningNode())
)
}
/** Gets the boolean value that `test` evaluates to when `use` is tainted with `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 testEvaluates(PyEdgeRefinement defn, ControlFlowNode test, ControlFlowNode use, TaintTrackingNode src) {
private boolean testEvaluates(
PyEdgeRefinement defn, ControlFlowNode test, ControlFlowNode use, TaintTrackingNode src
) {
defn.getTest().getAChild*() = use and
exists(DataFlow::Node srcnode, TaintKind kind |
srcnode.asVariable() = defn.getInput() and
srcnode.asVariable().getASourceUse() = use and
src = TTaintTrackingNode_(srcnode, _, TNoAttribute(), kind, this)
|
|
test = use and result = kind.booleanValue()
or
exists(ControlFlowNode const |
@@ -770,9 +870,8 @@ private class EssaTaintTracking extends string {
exists(ControlFlowNode c, ClassValue cls |
Filters::isinstance(test, c, use) and
c.pointsTo(cls)
|
exists(ClassValue scls |
scls = kind.getType() |
|
exists(ClassValue scls | scls = kind.getType() |
scls.getASuperType() = cls and result = true
or
not scls.getASuperType() = cls and result = false
@@ -785,7 +884,8 @@ private class EssaTaintTracking extends string {
result = testEvaluates(defn, not_operand(test), use, src).booleanNot()
}
/** Holds if `test` is the test in a branch and `use` is that test
/**
* 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) {
@@ -799,7 +899,6 @@ private class EssaTaintTracking extends string {
)
)
}
}
private predicate testEvaluatesMaybe(ControlFlowNode test, ControlFlowNode use) {
@@ -830,19 +929,17 @@ private predicate with_flow(With with, ControlFlowNode contextManager, ControlFl
}
/* Helper predicate for taintedPiNode */
pragma [noinline]
pragma[noinline]
private predicate piNodeTestAndUse(PyEdgeRefinement defn, ControlFlowNode test, ControlFlowNode use) {
test = defn.getTest() and use = defn.getInput().getASourceUse() and test.getAChild*() = use
}
module Implementation {
/* A call that returns a copy (or similar) of the argument */
predicate copyCall(ControlFlowNode fromnode, CallNode tonode) {
tonode.getFunction().(AttrNode).getObject("copy") = fromnode
or
exists(ModuleObject copy, string name |
name = "copy" or name = "deepcopy" |
exists(ModuleObject copy, string name | name = "copy" or name = "deepcopy" |
copy.attr(name).(FunctionObject).getACall() = tonode and
tonode.getArg(0) = fromnode
)
@@ -850,6 +947,4 @@ module Implementation {
tonode.getFunction().pointsTo(ObjectInternal::builtin("reversed")) and
tonode.getArg(0) = fromnode
}
}

View File

@@ -3,12 +3,8 @@ private import semmle.python.objects.ObjectInternal
import semmle.python.dataflow.Implementation
/* For backwards compatibility -- Use `TaintTrackingContext` instead. */
deprecated
class CallContext extends TaintTrackingContext {
TaintTrackingContext getCallee(CallNode call) {
result.getCaller(call) = this
}
deprecated class CallContext extends TaintTrackingContext {
TaintTrackingContext getCallee(CallNode call) { result.getCaller(call) = this }
predicate appliesToScope(Scope s) {
exists(PythonFunctionObjectInternal func, TaintKind param, AttributePath path, int n |
@@ -21,33 +17,23 @@ class CallContext extends TaintTrackingContext {
or
this.isTop()
}
}
/* Backwards compatibility with config-less taint-tracking */
private class LegacyConfiguration extends TaintTracking::Configuration {
LegacyConfiguration() {
/* A name that won't be accidentally chosen by users */
this = "Semmle: Internal legacy configuration"
}
override predicate isSource(TaintSource src) {
src = src
}
override predicate isSource(TaintSource src) { src = src }
override predicate isSink(TaintSink sink) {
sink = sink
}
override predicate isSink(TaintSink sink) { sink = sink }
override predicate isSanitizer(Sanitizer sanitizer) {
sanitizer = sanitizer
}
override predicate isSanitizer(Sanitizer sanitizer) { sanitizer = sanitizer }
override predicate isAdditionalFlowStep(DataFlow::Node src, DataFlow::Node dest) {
exists(DataFlowExtension::DataFlowNode legacyExtension |
src.asCfgNode() = legacyExtension
|
exists(DataFlowExtension::DataFlowNode legacyExtension | src.asCfgNode() = legacyExtension |
dest.asCfgNode() = legacyExtension.getASuccessorNode()
or
dest.asVariable() = legacyExtension.getASuccessorVariable()
@@ -58,10 +44,10 @@ private class LegacyConfiguration extends TaintTracking::Configuration {
)
}
override predicate isAdditionalFlowStep(DataFlow::Node src, DataFlow::Node dest, TaintKind srckind, TaintKind destkind) {
exists(DataFlowExtension::DataFlowNode legacyExtension |
src.asCfgNode() = legacyExtension
|
override predicate isAdditionalFlowStep(
DataFlow::Node src, DataFlow::Node dest, TaintKind srckind, TaintKind destkind
) {
exists(DataFlowExtension::DataFlowNode legacyExtension | src.asCfgNode() = legacyExtension |
dest.asCfgNode() = legacyExtension.getASuccessorNode(srckind, destkind)
)
}
@@ -79,5 +65,4 @@ private class LegacyConfiguration extends TaintTracking::Configuration {
)
)
}
}

View File

@@ -1,5 +1,6 @@
/** Provides classes and predicates for tracking global state across the control flow and call graphs.
*
/**
* Provides classes and predicates for tracking global state across the control flow and call graphs.
*
* NOTE: State tracking tracks both whether a state may apply to a given node in a given context *and*
* whether it may not apply.
* That `state.appliesTo(f, ctx)` holds implies nothing about whether `state.mayNotApplyTo(f, ctx)` holds.
@@ -15,14 +16,11 @@ private import semmle.python.objects.ObjectInternal
/** A state that should be tracked. */
abstract class TrackableState extends string {
bindingset[this]
TrackableState() { this = this }
/** Holds if this state may apply to the control flow node `f`, regardless of the context. */
final predicate appliesTo(ControlFlowNode f) {
this.appliesTo(f, _)
}
final predicate appliesTo(ControlFlowNode f) { this.appliesTo(f, _) }
/** Holds if this state may not apply to the control flow node `f`, given the context `ctx`. */
final predicate appliesTo(ControlFlowNode f, Context ctx) {
@@ -35,60 +33,56 @@ abstract class TrackableState extends string {
}
/** Holds if this state may apply to the control flow node `f`, regardless of the context. */
final predicate mayNotApplyTo(ControlFlowNode f) {
this.mayNotApplyTo(f, _)
}
final predicate mayNotApplyTo(ControlFlowNode f) { this.mayNotApplyTo(f, _) }
/** Holds if `test` shows value to be untainted with `taint`, given the context `ctx`. */
predicate testsFor(PyEdgeRefinement test, Context ctx, boolean sense) {
predicate testsFor(PyEdgeRefinement test, Context ctx, boolean sense) {
ctx.appliesToScope(test.getScope()) and this.testsFor(test, sense)
}
/** Holds if `test` shows value to be untainted with `taint` */
predicate testsFor(PyEdgeRefinement test, boolean sense) { none() }
/** Holds if state starts at `f`.
/**
* Holds if state starts at `f`.
* Either this predicate or `startsAt(ControlFlowNode f, Context ctx)`
* should be overriden by sub-classes.
*/
predicate startsAt(ControlFlowNode f) { none() }
/** Holds if state starts at `f` given context `ctx`.
/**
* Holds if state starts at `f` given context `ctx`.
* Either this predicate or `startsAt(ControlFlowNode f)`
* should be overriden by sub-classes.
*/
pragma [noinline]
predicate startsAt(ControlFlowNode f, Context ctx) {
ctx.appliesTo(f) and this.startsAt(f)
}
pragma[noinline]
predicate startsAt(ControlFlowNode f, Context ctx) { ctx.appliesTo(f) and this.startsAt(f) }
/** Holds if state ends at `f`.
/**
* Holds if state ends at `f`.
* Either this predicate or `endsAt(ControlFlowNode f, Context ctx)`
* may be overriden by sub-classes.
*/
predicate endsAt(ControlFlowNode f) { none() }
/** Holds if state ends at `f` given context `ctx`.
/**
* Holds if state ends at `f` given context `ctx`.
* Either this predicate or `endsAt(ControlFlowNode f)`
* may be overriden by sub-classes.
*/
pragma [noinline]
predicate endsAt(ControlFlowNode f, Context ctx) {
ctx.appliesTo(f) and this.endsAt(f)
}
pragma[noinline]
predicate endsAt(ControlFlowNode f, Context ctx) { ctx.appliesTo(f) and this.endsAt(f) }
}
module StateTracking {
private predicate not_allowed(TrackableState state, ControlFlowNode f, Context ctx, boolean sense) {
state.endsAt(f, ctx) and sense = true
or
state.startsAt(f, ctx) and sense = false
}
/** Holds if `state` may apply (with `sense` = true) or may not apply (with `sense` = false) to
/**
* Holds if `state` may apply (with `sense` = true) or may not apply (with `sense` = false) to
* control flow node `f` given the context `ctx`.
*/
predicate appliesToNode(TrackableState state, ControlFlowNode f, Context ctx, boolean sense) {
@@ -96,8 +90,7 @@ module StateTracking {
or
state.startsAt(f, ctx) and sense = true
or
not not_allowed(state, f, ctx, sense)
and
not not_allowed(state, f, ctx, sense) and
(
exists(BasicBlock b |
/* First node in a block */
@@ -106,7 +99,7 @@ module StateTracking {
/* Other nodes in block, except trackable calls */
exists(int n |
f = b.getNode(n) and
appliesToNode(state, b.getNode(n-1), ctx, sense) and
appliesToNode(state, b.getNode(n - 1), ctx, sense) and
not exists(PythonFunctionObjectInternal func, Context callee |
callee.fromCall(f, func, ctx)
)
@@ -127,27 +120,32 @@ module StateTracking {
)
or
/* Other scope entries */
exists(Scope s |
exists(Scope s |
s.getEntryNode() = f and
ctx.appliesToScope(s)
|
|
not exists(Scope pred | pred.precedes(s)) and
(ctx.isImport() or ctx.isRuntime()) and sense = false
(ctx.isImport() or ctx.isRuntime()) and
sense = false
or
exists(Scope pred, Context pred_ctx |
appliesToNode(state, pred.getANormalExit(), pred_ctx, sense) and
pred.precedes(s) and
ctx.isRuntime() |
ctx.isRuntime()
|
pred_ctx.isRuntime() or pred_ctx.isImport()
)
)
)
}
/** Holds if `state` may apply (with `sense` = true) or may not apply (with `sense` = false) at the
/**
* Holds if `state` may apply (with `sense` = true) or may not apply (with `sense` = false) at the
* start of basic block `block` given the context `ctx`.
*/
private predicate appliesAtBlockStart(TrackableState state, BasicBlock block, Context ctx, boolean sense) {
private predicate appliesAtBlockStart(
TrackableState state, BasicBlock block, Context ctx, boolean sense
) {
exists(PyEdgeRefinement test |
test.getSuccessor() = block and
state.testsFor(test, ctx, sense)
@@ -164,12 +162,13 @@ module StateTracking {
)
}
/** Holds if `state` may apply (with `sense` = true) or may not apply (with `sense` = false) at the
/**
* Holds if `state` may apply (with `sense` = true) or may not apply (with `sense` = false) at the
* end of basic block `block` given the context `ctx`.
*/
private predicate appliesAtBlockEnd(TrackableState state, BasicBlock block, Context ctx, boolean sense) {
private predicate appliesAtBlockEnd(
TrackableState state, BasicBlock block, Context ctx, boolean sense
) {
appliesToNode(state, block.getLastNode(), ctx, sense)
}
}

View File

@@ -92,7 +92,8 @@ private import semmle.python.objects.ObjectInternal
private import semmle.python.dataflow.Implementation
import semmle.python.dataflow.Configuration
/** A 'kind' of taint. This may be almost anything,
/**
* A 'kind' of taint. This may be almost anything,
* but it is typically something like a "user-defined string".
* Examples include, data from a http request object,
* data from an SMS or other mobile data source,
@@ -100,33 +101,38 @@ import semmle.python.dataflow.Configuration
* the local file system.
*/
abstract class TaintKind extends string {
bindingset[this]
TaintKind() { any() }
/** Gets the kind of taint that the named attribute will have if an object is tainted with this taint.
/**
* Gets the kind of taint that the named attribute will have if an object is tainted with this taint.
* In other words, if `x` has this kind of taint then it implies that `x.name`
* has `result` kind of taint.
*/
TaintKind getTaintOfAttribute(string name) { none() }
/** Gets the kind of taint results from calling the named method if an object is tainted with this taint.
/**
* Gets the kind of taint results from calling the named method if an object is tainted with this taint.
* In other words, if `x` has this kind of taint then it implies that `x.name()`
* has `result` kind of taint.
*/
TaintKind getTaintOfMethodResult(string name) { none() }
/** Gets the taint resulting from the flow step `fromnode` -> `tonode`.
/**
* Gets the taint resulting from the flow step `fromnode` -> `tonode`.
*/
TaintKind getTaintForFlowStep(ControlFlowNode fromnode, ControlFlowNode tonode) { none() }
/** Gets the taint resulting from the flow step `fromnode` -> `tonode`, with `edgeLabel`
/**
* Gets the taint resulting from the flow step `fromnode` -> `tonode`, with `edgeLabel`
*/
TaintKind getTaintForFlowStep(ControlFlowNode fromnode, ControlFlowNode tonode, string edgeLabel) {
result = this.getTaintForFlowStep(fromnode, tonode) and edgeLabel = "custom taint flow step for " + this
result = this.getTaintForFlowStep(fromnode, tonode) and
edgeLabel = "custom taint flow step for " + this
}
/** DEPRECATED -- Use `TaintFlow.additionalFlowStepVar(EssaVariable fromvar, EssaVariable tovar, TaintKind kind)` instead.
/**
* DEPRECATED -- Use `TaintFlow.additionalFlowStepVar(EssaVariable fromvar, EssaVariable tovar, TaintKind kind)` instead.
*
* Holds if this kind of taint passes from variable `fromvar` to variable `tovar`
* This predicate is present for completeness. It is unlikely that any `TaintKind`
@@ -134,40 +140,40 @@ abstract class TaintKind extends string {
*/
deprecated predicate additionalFlowStepVar(EssaVariable fromvar, EssaVariable tovar) { none() }
/** Holds if this kind of taint "taints" `expr`.
/**
* Holds if this kind of taint "taints" `expr`.
*/
final predicate taints(ControlFlowNode expr) {
exists(TaintedNode n |
n.getTaintKind() = this and n.getCfgNode() = expr
)
exists(TaintedNode n | n.getTaintKind() = this and n.getCfgNode() = expr)
}
/** DEPRECATED -- Use getType() instead */
deprecated ClassObject getClass() {
none()
}
deprecated ClassObject getClass() { none() }
/** Gets the class of this kind of taint.
/**
* Gets the class of this kind of taint.
* For example, if this were a kind of string taint
* the `result` would be `theStrType()`.
*/
ClassValue getType() {
result.(ClassObjectInternal).getSource() = this.getClass()
}
ClassValue getType() { result.(ClassObjectInternal).getSource() = this.getClass() }
/** Gets the boolean values (may be one, neither, or both) that
/**
* Gets the boolean values (may be one, neither, or both) that
* may result from the Python expression `bool(this)`
*/
boolean booleanValue() {
/* Default to true as the vast majority of taint is strings and
/*
* Default to true as the vast majority of taint is strings and
* the empty string is almost always benign.
*/
result = true
}
string repr() { result = this }
/** Gets the taint resulting from iterating over this kind of taint.
/**
* Gets the taint resulting from iterating over this kind of taint.
* For example iterating over a text file produces lines. So iterating
* over a tainted file would result in tainted strings
*/
@@ -184,20 +190,21 @@ abstract class TaintKind extends string {
*/
class FlowLabel = TaintKind;
/** Taint kinds representing collections of other taint kind.
/**
* Taint kinds representing collections of other taint kind.
* We use `{kind}` to represent a mapping of string to `kind` and
* `[kind]` to represent a flat collection of `kind`.
* The use of `{` and `[` is chosen to reflect dict and list literals
* `[kind]` to represent a flat collection of `kind`.
* The use of `{` and `[` is chosen to reflect dict and list literals
* in Python. We choose a single character prefix and suffix for simplicity
* and ease of preventing infinite recursion.
*/
abstract class CollectionKind extends TaintKind {
bindingset[this]
CollectionKind() {
(this.charAt(0) = "[" or this.charAt(0) = "{") and
/* Prevent any collection kinds more than 2 deep */
not this.charAt(2) = "[" and not this.charAt(2) = "{"
not this.charAt(2) = "[" and
not this.charAt(2) = "{"
}
abstract TaintKind getMember();
@@ -207,20 +214,16 @@ abstract class CollectionKind extends TaintKind {
abstract predicate flowToMember(DataFlow::Node fromnode, DataFlow::Node tonode);
}
/** A taint kind representing a flat collections of kinds.
/**
* A taint kind representing a flat collections of kinds.
* Typically a sequence, but can include sets.
*/
class SequenceKind extends CollectionKind {
TaintKind itemKind;
SequenceKind() {
this = "[" + itemKind + "]"
}
SequenceKind() { this = "[" + itemKind + "]" }
TaintKind getItem() {
result = itemKind
}
TaintKind getItem() { result = itemKind }
override TaintKind getTaintForFlowStep(ControlFlowNode fromnode, ControlFlowNode tonode) {
exists(BinaryExprNode mod |
@@ -236,17 +239,11 @@ class SequenceKind extends CollectionKind {
name = "pop" and result = this.getItem()
}
override string repr() {
result = "sequence of " + itemKind
}
override string repr() { result = "sequence of " + itemKind }
override TaintKind getTaintForIteration() {
result = itemKind
}
override TaintKind getTaintForIteration() { result = itemKind }
override TaintKind getMember() {
result = itemKind
}
override TaintKind getMember() { result = itemKind }
override predicate flowFromMember(DataFlow::Node fromnode, DataFlow::Node tonode) {
sequence_construct(fromnode.asCfgNode(), tonode.asCfgNode())
@@ -255,12 +252,9 @@ class SequenceKind extends CollectionKind {
override predicate flowToMember(DataFlow::Node fromnode, DataFlow::Node tonode) {
SequenceKind::itemFlowStep(fromnode.asCfgNode(), tonode.asCfgNode())
}
}
module SequenceKind {
predicate flowStep(ControlFlowNode fromnode, ControlFlowNode tonode, string edgeLabel) {
tonode.(BinaryExprNode).getAnOperand() = fromnode and edgeLabel = "binary operation"
or
@@ -275,11 +269,10 @@ module SequenceKind {
predicate itemFlowStep(ControlFlowNode fromnode, ControlFlowNode tonode) {
subscript_index(fromnode, tonode)
}
}
module DictKind {
predicate flowStep(ControlFlowNode fromnode, ControlFlowNode tonode, string edgeLabel) {
predicate flowStep(ControlFlowNode fromnode, ControlFlowNode tonode, string edgeLabel) {
Implementation::copyCall(fromnode, tonode) and
edgeLabel = "dict copy"
or
@@ -289,37 +282,31 @@ module DictKind {
}
}
/* Helper for sequence flow steps */
pragma [noinline]
pragma[noinline]
private predicate subscript_index(ControlFlowNode obj, SubscriptNode sub) {
sub.isLoad() and
sub.getValue() = obj and
not sub.getNode().getIndex() instanceof Slice
}
pragma [noinline]
pragma[noinline]
private predicate subscript_slice(ControlFlowNode obj, SubscriptNode sub) {
sub.isLoad() and
sub.getValue() = obj and
sub.getNode().getIndex() instanceof Slice
}
/** A taint kind representing a mapping of objects to kinds.
/**
* A taint kind representing a mapping of objects to kinds.
* Typically a dict, but can include other mappings.
*/
class DictKind extends CollectionKind {
TaintKind valueKind;
DictKind() {
this = "{" + valueKind + "}"
}
DictKind() { this = "{" + valueKind + "}" }
TaintKind getValue() {
result = valueKind
}
TaintKind getValue() { result = valueKind }
override TaintKind getTaintOfMethodResult(string name) {
name = "get" and result = valueKind
@@ -329,13 +316,9 @@ class DictKind extends CollectionKind {
name = "itervalues" and result.(SequenceKind).getItem() = valueKind
}
override string repr() {
result = "dict of " + valueKind
}
override string repr() { result = "dict of " + valueKind }
override TaintKind getMember() {
result = valueKind
}
override TaintKind getMember() { result = valueKind }
override predicate flowFromMember(DataFlow::Node fromnode, DataFlow::Node tonode) {
dict_construct(fromnode.asCfgNode(), tonode.asCfgNode())
@@ -344,17 +327,15 @@ class DictKind extends CollectionKind {
override predicate flowToMember(DataFlow::Node fromnode, DataFlow::Node tonode) {
subscript_index(fromnode.asCfgNode(), tonode.asCfgNode())
}
}
/** A type of sanitizer of untrusted data.
/**
* A type of sanitizer of untrusted data.
* Examples include sanitizers for http responses, for DB access or for shell commands.
* Usually a sanitizer can only sanitize data for one particular use.
* For example, a sanitizer for DB commands would not be safe to use for http responses.
*/
abstract class Sanitizer extends string {
bindingset[this]
Sanitizer() { any() }
@@ -372,42 +353,49 @@ abstract class Sanitizer extends string {
/** Holds if `def` shows value to be untainted with `taint` */
predicate sanitizingDefinition(TaintKind taint, EssaDefinition def) { none() }
}
/** DEPRECATED -- Use DataFlowExtension instead.
/**
* 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
* from a socket to data from that socket.
*/
deprecated abstract class TaintFlow extends string {
abstract deprecated class TaintFlow extends string {
bindingset[this]
TaintFlow() { any() }
/** Holds if `fromnode` being tainted with `fromkind` will result in `tonode` being tainted with `tokind`.
/**
* Holds if `fromnode` being tainted with `fromkind` will result in `tonode` being tainted with `tokind`.
* Extensions to `TaintFlow` should override this to provide additional taint steps.
*/
predicate additionalFlowStep(ControlFlowNode fromnode, TaintKind fromkind, ControlFlowNode tonode, TaintKind tokind) { none() }
predicate additionalFlowStep(
ControlFlowNode fromnode, TaintKind fromkind, ControlFlowNode tonode, TaintKind tokind
) {
none()
}
/** Holds if the given `kind` of taint passes from variable `fromvar` to variable `tovar`.
/**
* Holds if the given `kind` of taint passes from variable `fromvar` to variable `tovar`.
* This predicate is present for completeness. Most `TaintFlow` implementations will not need to override it.
*/
predicate additionalFlowStepVar(EssaVariable fromvar, EssaVariable tovar, TaintKind kind) { none() }
predicate additionalFlowStepVar(EssaVariable fromvar, EssaVariable tovar, TaintKind kind) {
none()
}
/** Holds if the given `kind` of taint cannot pass from variable `fromvar` to variable `tovar`.
/**
* Holds if the given `kind` of taint cannot pass from variable `fromvar` to variable `tovar`.
* This predicate is present for completeness. Most `TaintFlow` implementations will not need to override it.
*/
predicate prunedFlowStepVar(EssaVariable fromvar, EssaVariable tovar, TaintKind kind) { none() }
predicate prunedFlowStepVar(EssaVariable fromvar, EssaVariable tovar, TaintKind kind) { none() }
}
/** A source of taintedness.
/**
* A source of taintedness.
* Users of the taint tracking library should override this
* class to provide their own sources.
*/
abstract class TaintSource extends @py_flow_node {
string toString() { result = "Taint source" }
/**
@@ -429,9 +417,7 @@ abstract class TaintSource extends @py_flow_node {
context.isTop() and this.isSourceOf(kind)
}
Location getLocation() {
result = this.(ControlFlowNode).getLocation()
}
Location getLocation() { result = this.(ControlFlowNode).getLocation() }
predicate hasLocationInfo(string fp, int bl, int bc, int el, int ec) {
this.getLocation().hasLocationInfo(fp, bl, bc, el, ec)
@@ -459,19 +445,16 @@ abstract class TaintSource extends @py_flow_node {
}
/** Holds if taint can flow from this source to taint sink `sink` */
final predicate flowsToSink(TaintSink sink) {
this.flowsToSink(_, sink)
}
final predicate flowsToSink(TaintSink sink) { this.flowsToSink(_, sink) }
}
/** Warning: Advanced feature. Users are strongly recommended to use `TaintSource` instead.
/**
* Warning: Advanced feature. Users are strongly recommended to use `TaintSource` instead.
* A source of taintedness on the ESSA data-flow graph.
* Users of the taint tracking library can override this
* class to provide their own sources on the ESSA graph.
*/
abstract class TaintedDefinition extends EssaNodeDefinition {
/**
* Holds if `this` is a source of taint kind `kind`
*
@@ -490,48 +473,36 @@ abstract class TaintedDefinition extends EssaNodeDefinition {
predicate isSourceOf(TaintKind kind, TaintTrackingContext context) {
context.isTop() and this.isSourceOf(kind)
}
}
private class DictUpdate extends DataFlowExtension::DataFlowNode {
MethodCallsiteRefinement call;
DictUpdate() {
exists(CallNode c |
c = call.getCall()
|
exists(CallNode c | c = call.getCall() |
c.getFunction().(AttrNode).getName() = "update" and
c.getArg(0) = this
)
}
override EssaVariable getASuccessorVariable() {
call.getVariable() = result
}
override EssaVariable getASuccessorVariable() { call.getVariable() = result }
}
private class SequenceExtends extends DataFlowExtension::DataFlowNode {
MethodCallsiteRefinement call;
SequenceExtends() {
exists(CallNode c |
c = call.getCall()
|
exists(CallNode c | c = call.getCall() |
c.getFunction().(AttrNode).getName() = "extend" and
c.getArg(0) = this
)
}
override EssaVariable getASuccessorVariable() {
call.getVariable() = result
}
override EssaVariable getASuccessorVariable() { call.getVariable() = result }
}
/** A node that is vulnerable to one or more types of taint.
/**
* A node that is vulnerable to one or more types of taint.
* These nodes provide the sinks when computing the taint flow graph.
* An example would be an argument to a write to a http response object,
* such an argument would be vulnerable to unsanitized user-input (XSS).
@@ -539,8 +510,7 @@ private class SequenceExtends extends DataFlowExtension::DataFlowNode {
* Users of the taint tracking library should extend this
* class to provide their own sink nodes.
*/
abstract class TaintSink extends @py_flow_node {
abstract class TaintSink extends @py_flow_node {
string toString() { result = "Taint sink" }
/**
@@ -551,134 +521,119 @@ abstract class TaintSink extends @py_flow_node {
*/
abstract predicate sinks(TaintKind taint);
Location getLocation() {
result = this.(ControlFlowNode).getLocation()
}
Location getLocation() { result = this.(ControlFlowNode).getLocation() }
predicate hasLocationInfo(string fp, int bl, int bc, int el, int ec) {
this.getLocation().hasLocationInfo(fp, bl, bc, el, ec)
}
}
/** Extension for data-flow, to help express data-flow paths that are
/**
* Extension for data-flow, to help express data-flow paths that are
* library or framework specific and cannot be inferred by the general
* data-flow machinery.
*/
module DataFlowExtension {
/** A control flow node that modifies the basic data-flow. */
abstract class DataFlowNode extends @py_flow_node {
string toString() { result = "Dataflow extension node" }
string toString() {
result = "Dataflow extension node"
}
/** Gets a successor node for data-flow.
/**
* Gets a successor node for data-flow.
* Data (all forms) is assumed to flow from `this` to `result`
*/
ControlFlowNode getASuccessorNode() { none() }
/** Gets a successor variable for data-flow.
/**
* Gets a successor variable for data-flow.
* Data (all forms) is assumed to flow from `this` to `result`.
* Note: This is an unlikely form of flow. See `DataFlowVariable.getASuccessorVariable()`
*/
EssaVariable getASuccessorVariable() { none() }
/** Holds if data cannot flow from `this` to `succ`,
/**
* Holds if data cannot flow from `this` to `succ`,
* even though it would normally do so.
*/
predicate prunedSuccessor(ControlFlowNode succ) { none() }
/** Gets a successor node, where the successor node will be tainted with `tokind`
/**
* Gets a successor node, where the successor node will be tainted with `tokind`
* when `this` is tainted with `fromkind`.
* Extensions to `DataFlowNode` should override this to provide additional taint steps.
*/
ControlFlowNode getASuccessorNode(TaintKind fromkind, TaintKind tokind) { none() }
/** Gets a successor node for data-flow with a change of context from callee to caller
/**
* Gets a successor node for data-flow with a change of context from callee to caller
* (going *up* the call-stack) across call-site `call`.
* Data (all forms) is assumed to flow from `this` to `result`
* Extensions to `DataFlowNode` should override this to provide additional taint steps.
*/
ControlFlowNode getAReturnSuccessorNode(CallNode call) { none() }
/** Gets a successor node for data-flow with a change of context from caller to callee
/**
* Gets a successor node for data-flow with a change of context from caller to callee
* (going *down* the call-stack) across call-site `call`.
* Data (all forms) is assumed to flow from `this` to `result`
* Extensions to `DataFlowNode` should override this to provide additional taint steps.
*/
ControlFlowNode getACalleeSuccessorNode(CallNode call) { none() }
}
/** Data flow variable that modifies the basic data-flow. */
class DataFlowVariable extends EssaVariable {
/** Gets a successor node for data-flow.
/**
* Gets a successor node for data-flow.
* Data (all forms) is assumed to flow from `this` to `result`
* Note: This is an unlikely form of flow. See `DataFlowNode.getASuccessorNode()`
*/
ControlFlowNode getASuccessorNode() { none() }
/** Gets a successor variable for data-flow.
/**
* Gets a successor variable for data-flow.
* Data (all forms) is assumed to flow from `this` to `result`.
*/
EssaVariable getASuccessorVariable() { none() }
/** Holds if data cannot flow from `this` to `succ`,
/**
* Holds if data cannot flow from `this` to `succ`,
* even though it would normally do so.
*/
predicate prunedSuccessor(EssaVariable succ) { none() }
}
}
class TaintedPathSource extends TaintTrackingNode {
TaintedPathSource() { this.isSource() }
TaintedPathSource() {
this.isSource()
}
DataFlow::Node getSource() {
result = this.getNode()
}
DataFlow::Node getSource() { result = this.getNode() }
}
class TaintedPathSink extends TaintTrackingNode {
TaintedPathSink() { this.isSink() }
TaintedPathSink() {
this.isSink()
}
DataFlow::Node getSink() {
result = this.getNode()
}
DataFlow::Node getSink() { result = this.getNode() }
}
/* Backwards compatible name */
class TaintedNode = TaintTrackingNode;
/* Helpers for Validating classes */
private import semmle.python.pointsto.PointsTo
/** Data flow module providing an interface compatible with
/**
* Data flow module providing an interface compatible with
* the other language implementations.
*/
module DataFlow {
/** Generic taint kind, source and sink classes for convenience and
/**
* Generic taint kind, source and sink classes for convenience and
* compatibility with other language libraries
*/
class Extension = DataFlowExtension::DataFlowNode;
deprecated abstract class Configuration extends string {
abstract deprecated class Configuration extends string {
bindingset[this]
Configuration() { this = this }
@@ -702,14 +657,10 @@ module DataFlow {
this.hasFlowPath(psource, psink)
)
}
}
private class ConfigurationAdapter extends TaintTracking::Configuration {
ConfigurationAdapter() {
this instanceof Configuration
}
ConfigurationAdapter() { this instanceof Configuration }
override predicate isSource(DataFlow::Node node, TaintKind kind) {
this.(Configuration).isSource(node.asCfgNode()) and
@@ -720,16 +671,13 @@ module DataFlow {
this.(Configuration).isSink(node.asCfgNode()) and
kind instanceof DataFlowType
}
}
private newtype TDataFlowNode =
TEssaNode(EssaVariable var)
or
TEssaNode(EssaVariable var) or
TCfgNode(ControlFlowNode node)
abstract class Node extends TDataFlowNode {
abstract ControlFlowNode asCfgNode();
abstract EssaVariable asVariable();
@@ -742,86 +690,51 @@ module DataFlow {
abstract Location getLocation();
AstNode asAstNode() {
result = this.asCfgNode().getNode()
}
AstNode asAstNode() { result = this.asCfgNode().getNode() }
/** For backwards compatibility -- Use asAstNode() instead */
deprecated AstNode getNode() {
result = this.asAstNode()
}
deprecated AstNode getNode() { result = this.asAstNode() }
}
class CfgNode extends Node, TCfgNode {
override ControlFlowNode asCfgNode() { this = TCfgNode(result) }
override ControlFlowNode asCfgNode() {
this = TCfgNode(result)
}
override EssaVariable asVariable() { none() }
override EssaVariable asVariable() {
none()
}
override string toString() { result = this.asAstNode().toString() }
override string toString() {
result = this.asAstNode().toString()
}
override Scope getScope() { result = this.asCfgNode().getScope() }
override Scope getScope() {
result = this.asCfgNode().getScope()
}
override BasicBlock getBasicBlock() {
result = this.asCfgNode().getBasicBlock()
}
override Location getLocation() {
result = this.asCfgNode().getLocation()
}
override BasicBlock getBasicBlock() { result = this.asCfgNode().getBasicBlock() }
override Location getLocation() { result = this.asCfgNode().getLocation() }
}
class EssaNode extends Node, TEssaNode {
override ControlFlowNode asCfgNode() { none() }
override ControlFlowNode asCfgNode() {
none()
}
override EssaVariable asVariable() { this = TEssaNode(result) }
override EssaVariable asVariable() {
this = TEssaNode(result)
}
override string toString() { result = this.asVariable().toString() }
override string toString() {
result = this.asVariable().toString()
}
override Scope getScope() {
result = this.asVariable().getScope()
}
override Scope getScope() { result = this.asVariable().getScope() }
override BasicBlock getBasicBlock() {
result = this.asVariable().getDefinition().getBasicBlock()
}
override Location getLocation() {
result = this.asVariable().getDefinition().getLocation()
}
override Location getLocation() { result = this.asVariable().getDefinition().getLocation() }
}
}
private class DataFlowType extends TaintKind {
DataFlowType() {
this = "Data flow" and
this = "Data flow" and
exists(DataFlow::Configuration c)
}
}
pragma [noinline]
pragma[noinline]
private predicate dict_construct(ControlFlowNode itemnode, ControlFlowNode dictnode) {
dictnode.(DictNode).getAValue() = itemnode
or
@@ -829,7 +742,7 @@ private predicate dict_construct(ControlFlowNode itemnode, ControlFlowNode dictn
dictnode.(CallNode).getArgByName(_) = itemnode
}
pragma [noinline]
pragma[noinline]
private predicate sequence_construct(ControlFlowNode itemnode, ControlFlowNode seqnode) {
seqnode.isLoad() and
(
@@ -841,13 +754,11 @@ private predicate sequence_construct(ControlFlowNode itemnode, ControlFlowNode s
)
}
/* A call to construct a sequence from a sequence or iterator*/
pragma [noinline]
pragma[noinline]
private predicate sequence_call(ControlFlowNode fromnode, CallNode tonode) {
tonode.getArg(0) = fromnode and
exists(ControlFlowNode cls |
cls = tonode.getFunction() |
exists(ControlFlowNode cls | cls = tonode.getFunction() |
cls.pointsTo(ObjectInternal::builtin("list"))
or
cls.pointsTo(ObjectInternal::builtin("tuple"))
@@ -855,4 +766,3 @@ private predicate sequence_call(ControlFlowNode fromnode, CallNode tonode) {
cls.pointsTo(ObjectInternal::builtin("set"))
)
}

View File

@@ -37,7 +37,7 @@ class EssaVariable extends TEssaDefinition {
result = "SSA variable " + this.getName()
}
/** Gets a string representation of this variable.
/** Gets a string representation of this variable.
* WARNING: The format of this may change and it may be very inefficient to compute.
* To used for debugging and testing only.
*/
@@ -69,7 +69,7 @@ class EssaVariable extends TEssaDefinition {
}
/* Helper for location_string
/* Helper for location_string
* NOTE: This is Python specific, to make `getRepresentation()` portable will require further work.
*/
private int exception_handling(BasicBlock b) {
@@ -153,10 +153,10 @@ abstract class EssaDefinition extends TEssaDefinition {
abstract predicate reachesEndOfBlock(BasicBlock b);
/** Gets the location of a control flow node that is indicative of this definition.
* Since definitions may occur on edges of the control flow graph, the given location may
* Since definitions may occur on edges of the control flow graph, the given location may
* be imprecise.
* Distinct `EssaDefinitions` may return the same ControlFlowNode even for
* the same variable.
* the same variable.
*/
abstract Location getLocation();
@@ -174,9 +174,9 @@ abstract class EssaDefinition extends TEssaDefinition {
}
/** An ESSA definition corresponding to an edge refinement of the underlying variable.
/** An ESSA definition corresponding to an edge refinement of the underlying variable.
* For example, the edges leaving a test on a variable both represent refinements of that
* variable. On one edge the test is true, on the other it is false.
* variable. On one edge the test is true, on the other it is false.
*/
class EssaEdgeRefinement extends EssaDefinition, TEssaEdgeDefinition {
@@ -348,7 +348,7 @@ class PhiFunction extends EssaDefinition, TPhiFunction {
}
private EssaEdgeRefinement piInputDefinition(EssaVariable input) {
input = this.getAnInput() and
input = this.getAnInput() and
result = input.getDefinition()
or
input = this.getAnInput() and result = input.getDefinition().(PhiFunction).piInputDefinition(_)
@@ -851,4 +851,3 @@ class PyEdgeRefinement extends EssaEdgeRefinement {
}
}

View File

@@ -1,4 +1,4 @@
/** Provides classes and predicates for determining the uses and definitions of
/** Provides classes and predicates for determining the uses and definitions of
* variables for ESSA form.
*/
@@ -30,7 +30,7 @@ cached module SsaSource {
/** Holds if `v` is defined by a with statement. */
cached predicate with_definition(Variable v, ControlFlowNode defn) {
exists(With with, Name var |
exists(With with, Name var |
with.getOptionalVars() = var and
var.getAFlowNode() = defn |
var = v.getAStore()
@@ -39,7 +39,7 @@ cached module SsaSource {
/** Holds if `v` is defined by multiple assignment at `defn`. */
cached predicate multi_assignment_definition(Variable v, ControlFlowNode defn, int n, SequenceNode lhs) {
defn.(NameNode).defines(v) and
defn.(NameNode).defines(v) and
not exists(defn.(DefinitionNode).getValue()) and
lhs.getElement(n) = defn and
lhs.getBasicBlock().dominates(defn.getBasicBlock())