mirror of
https://github.com/github/codeql.git
synced 2026-04-30 11:15:13 +02:00
Python: Autoformat dataflow files
This commit is contained in:
@@ -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()
|
||||
)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1 +1 @@
|
||||
import semmle.python.security.TaintTracking
|
||||
import semmle.python.security.TaintTracking
|
||||
|
||||
@@ -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() }
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -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 {
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -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"))
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -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 {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -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())
|
||||
|
||||
Reference in New Issue
Block a user