Python taint-tracking: Improve layout and documentation.

This commit is contained in:
Mark Shannon
2019-08-16 12:55:03 +01:00
parent 91aefab7aa
commit 45abe09494
2 changed files with 238 additions and 199 deletions

View File

@@ -2,6 +2,7 @@ import python
import semmle.python.security.TaintTracking
private import semmle.python.objects.ObjectInternal
private import semmle.python.pointsto.Filters as Filters
import semmle.python.dataflow.Legacy
newtype TTaintTrackingContext =
TNoParam()
@@ -10,6 +11,12 @@ newtype TTaintTrackingContext =
any(TaintTrackingImplementation impl).callWithTaintedArgument(_, _, _, _, n, path, param)
}
/** 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() {
@@ -48,28 +55,6 @@ class TaintTrackingContext extends TTaintTrackingContext {
}
/* For backwards compatibility -- Use `TaintTrackingContext` instead. */
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 |
this = TParamContext(param, path, n) and
exists(TaintTrackingImplementation impl |
impl.callWithTaintedArgument(_, _, _, func, n, path, param) and
s = func.getScope()
)
)
or
this.isTop()
}
}
private newtype TAttributePath =
TNoAttribute()
or
@@ -81,6 +66,10 @@ private newtype TAttributePath =
none()
}
/** 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();
@@ -99,7 +88,7 @@ abstract class AttributePath extends TAttributePath {
}
/** AttributePath for no attribute. */
class NoAttribute extends TNoAttribute, AttributePath {
override string toString() { result = "no attribute" }
@@ -112,6 +101,7 @@ class NoAttribute extends TNoAttribute, AttributePath {
}
/** AttributePath for an attribute. */
class NamedAttributePath extends TAttribute, AttributePath {
override string toString() {
@@ -134,6 +124,9 @@ class NamedAttributePath extends TAttribute, AttributePath {
}
/** 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) {
config.(TaintTrackingImplementation).flowSource(node, context, path, kind)
@@ -141,6 +134,9 @@ newtype TTaintTrackingNode =
config.(TaintTrackingImplementation).flowStep(_, node, context, path, kind, _)
}
/** Class representing the (node, context, path, kind) tuple.
* Used for context-sensitive path-aware taint-tracking.
*/
class TaintTrackingNode extends TTaintTrackingNode {
string toString() {
@@ -151,18 +147,22 @@ class TaintTrackingNode extends TTaintTrackingNode {
)
}
/** Gets the data flow node for this taint-tracking node */
DataFlow::Node getNode() {
this = TTaintTrackingNode_(result, _, _, _, _)
}
/** Gets the taint kind for this taint-tracking node */
TaintKind getTaintKind() {
this = TTaintTrackingNode_(_, _, _, result, _)
}
/** Gets the taint-tracking context for this taint-tracking node */
TaintTrackingContext getContext() {
this = TTaintTrackingNode_(_, result, _, _, _)
}
/** Gets the attribute path context for this taint-tracking node */
AttributePath getPath() {
this = TTaintTrackingNode_(_, _, result, _, _)
}
@@ -222,6 +222,11 @@ class TaintTrackingNode extends TTaintTrackingNode {
}
/** 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 {
@@ -229,23 +234,23 @@ class TaintTrackingImplementation extends string {
this instanceof TaintTracking::Configuration
}
/** 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) {
this.isPathSource(source) and
this.isPathSink(sink) and
this.flowReaches(source, sink)
}
/** 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
this.(TaintTracking::Configuration).isSource(node, kind)
}
predicate flowSink(DataFlow::Node node, AttributePath path, TaintKind kind) {
path = TNoAttribute() and
this.(TaintTracking::Configuration).isSink(node, kind)
}
/** Hold if `source` is a source of taint. */
predicate isPathSource(TaintTrackingNode source) {
exists(DataFlow::Node node, TaintTrackingContext context, AttributePath path, TaintKind kind |
source = TTaintTrackingNode_(node, context, path, kind, this) and
@@ -253,13 +258,18 @@ class TaintTrackingImplementation extends string {
)
}
/** Hold if `sink` is a taint sink. */
predicate isPathSink(TaintTrackingNode sink) {
exists(DataFlow::Node node, AttributePath path, TaintKind kind |
sink = TTaintTrackingNode_(node, _, path, kind, this) and
this.flowSink(node, path, kind)
path = TNoAttribute() and
this.(TaintTracking::Configuration).isSink(node, kind)
)
}
/** Hold if taint flows to `src` to `dest` in a single step, labelled with `egdeLabel`
* `edgeLabel` is purely informative.
*/
predicate flowStep(TaintTrackingNode src, TaintTrackingNode dest, string edgeLabel) {
exists(DataFlow::Node node, TaintTrackingContext ctx, AttributePath path, TaintKind kind |
dest = TTaintTrackingNode_(node, ctx, path, kind, this) and
@@ -267,6 +277,8 @@ class TaintTrackingImplementation extends string {
)
}
/** Hold if taint reaches `dest` from `src` with this configuration.
*/
predicate flowReaches(TaintTrackingNode src, TaintTrackingNode dest) {
this = src.getConfiguration() and dest = src
or
@@ -276,68 +288,9 @@ class TaintTrackingImplementation extends string {
)
}
/** 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.
/** 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.
*/
boolean testEvaluates(ControlFlowNode test, ControlFlowNode use, TaintKind kind) {
boolean_filter(_, use) and
kind.taints(use) and
test = use and result = kind.booleanValue()
or
result = testEvaluates(not_operand(test), use, kind).booleanNot()
or
exists(ControlFlowNode const |
Filters::equality_test(test, use, result.booleanNot(), const) and
const.getNode() instanceof ImmutableLiteral
)
or
exists(ControlFlowNode c, ClassValue cls |
Filters::isinstance(test, c, use) and
c.pointsTo(cls)
|
exists(ClassValue scls |
scls = kind.getType() |
scls.getASuperType() = cls and result = true
or
not scls.getASuperType() = cls and result = false
)
or
not exists(kind.getType()) and result = maybe()
)
}
predicate testEvaluatesMaybe(ControlFlowNode test, ControlFlowNode use) {
any(PyEdgeRefinement ref).getTest().getAChild*() = test and
test.getAChild*() = use and
not test.(UnaryExprNode).getNode().getOp() instanceof Not and
not Filters::equality_test(test, use, _, _) and
not Filters::isinstance(test, _, use) and
not test = use
or
testEvaluatesMaybe(not_operand(test), use)
}
/** Gets the operand of a unary `not` expression. */
private ControlFlowNode not_operand(ControlFlowNode expr) {
expr.(UnaryExprNode).getNode().getOp() instanceof Not and
result = expr.(UnaryExprNode).getOperand()
}
/** Holds if `test` is the test in a branch and `use` is that test
* with all the `not` prefixes removed.
*/
private predicate boolean_filter(ControlFlowNode test, ControlFlowNode use) {
any(PyEdgeRefinement ref).getTest() = test and
(
use = test
or
exists(ControlFlowNode notuse |
boolean_filter(test, notuse) and
use = not_operand(notuse)
)
)
}
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
@@ -353,13 +306,13 @@ class TaintTrackingImplementation extends string {
)
}
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)
}
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)
@@ -384,9 +337,9 @@ class TaintTrackingImplementation extends string {
or
this.ifExpStep(src, node, context, path, kind, edgeLabel)
or
this.essaFlowStep(src, node, context, path, kind) and edgeLabel = ""
this.essaFlowStep(src, node, context, path, kind, edgeLabel)
or
this.instantionStep(src, node, context, path, kind, edgeLabel)
this.instantiationStep(src, node, context, path, kind, edgeLabel)
or
this.legacyExtensionStep(src, node, context, path, kind, edgeLabel)
or
@@ -477,16 +430,6 @@ class TaintTrackingImplementation extends string {
) and edgeLabel = "use"
}
//pragma [noinline]
//predicate argumentFlowStep(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, arg)
// )
// // TO DO... named parameters
//}
/* 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) {
@@ -529,10 +472,10 @@ class TaintTrackingImplementation extends string {
)
}
predicate instantionStep(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 |
instantionCall(node.asCfgNode(), src, init, context, callee) and
this.taintedDefinition(_, self.getDefinition(), callee, path, kind) and
instantiationCall(node.asCfgNode(), src, init, context, callee) and
this.(EssaTaintTracking).taintedDefinition(_, self.getDefinition(), callee, path, kind) and
self.getSourceVariable().(Variable).isSelf() and
BaseFlow::reaches_exit(self) and
self.getScope() = init.getScope()
@@ -540,7 +483,7 @@ class TaintTrackingImplementation extends string {
edgeLabel = "instantiation"
}
predicate instantionCall(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
@@ -555,7 +498,6 @@ class TaintTrackingImplementation extends string {
)
}
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 |
@@ -611,8 +553,8 @@ class TaintTrackingImplementation extends string {
}
pragma [noinline]
predicate essaFlowStep(TaintTrackingNode src, DataFlow::Node node, TaintTrackingContext context, AttributePath path, TaintKind kind) {
this.taintedDefinition(src, node.asVariable().getDefinition(), context, path, kind)
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]
@@ -630,6 +572,25 @@ class TaintTrackingImplementation extends string {
) and edgeLabel = "legacy extension"
}
predicate moduleAttributeTainted(ModuleValue m, string name, TaintTrackingNode taint) {
exists(DataFlow::Node srcnode, EssaVariable var |
taint = TTaintTrackingNode_(srcnode, TNoParam(), _, _, this) and
var = srcnode.asVariable() and
var.getName() = name and
BaseFlow::reaches_exit(var) and
var.getScope() = m.getScope()
)
}
}
/** 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
}
pragma [noinline]
predicate taintedDefinition(TaintTrackingNode src, EssaDefinition defn, TaintTrackingContext context, AttributePath path, TaintKind kind) {
this.taintedPhi(src, defn, context, path, kind)
@@ -658,7 +619,7 @@ class TaintTrackingImplementation extends string {
}
pragma [noinline]
predicate taintedPhi(TaintTrackingNode src, PhiFunction defn, TaintTrackingContext context, AttributePath path, TaintKind kind) {
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
@@ -670,7 +631,7 @@ class TaintTrackingImplementation extends string {
}
pragma [noinline]
predicate taintedAssignment(TaintTrackingNode src, AssignmentDefinition defn, TaintTrackingContext context, AttributePath path, TaintKind kind) {
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()
@@ -678,7 +639,7 @@ class TaintTrackingImplementation extends string {
}
pragma [noinline]
predicate taintedAttributeAssignment(TaintTrackingNode src, AttributeAssignment defn, TaintTrackingContext context, AttributePath path, TaintKind kind) {
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
@@ -688,7 +649,7 @@ class TaintTrackingImplementation extends string {
}
pragma [noinline]
predicate taintedParameterDefinition(TaintTrackingNode src, ParameterDefinition defn, TaintTrackingContext context, AttributePath path, TaintKind kind) {
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()
@@ -696,7 +657,7 @@ class TaintTrackingImplementation extends string {
}
pragma [noinline]
predicate taintedCallsite(TaintTrackingNode src, CallsiteRefinement defn, TaintTrackingContext context, AttributePath path, TaintKind kind) {
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.
*/
@@ -707,7 +668,7 @@ class TaintTrackingImplementation extends string {
}
pragma [noinline]
predicate taintedMethodCallsite(TaintTrackingNode src, MethodCallsiteRefinement defn, TaintTrackingContext context, AttributePath path, TaintKind kind) {
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()
@@ -715,7 +676,7 @@ class TaintTrackingImplementation extends string {
}
pragma [noinline]
predicate taintedUniEdge(TaintTrackingNode src, SingleSuccessorGuard defn, TaintTrackingContext context, AttributePath path, TaintKind kind) {
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
@@ -724,7 +685,7 @@ class TaintTrackingImplementation extends string {
}
pragma [noinline]
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) {
exists(DataFlow::Node srcnode |
src = TTaintTrackingNode_(srcnode, context, path, kind, this) and
srcnode.asVariable() = defn.getInput() and
@@ -737,7 +698,7 @@ class TaintTrackingImplementation extends string {
}
pragma [noinline]
predicate taintedArgument(TaintTrackingNode src, ArgumentRefinement defn, TaintTrackingContext context, AttributePath path, TaintKind kind) {
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()
@@ -745,7 +706,7 @@ class TaintTrackingImplementation extends string {
}
pragma [noinline]
predicate taintedExceptionCapture(TaintTrackingNode src, ExceptionCapture defn, TaintTrackingContext context, AttributePath path, TaintKind kind) {
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()
@@ -753,7 +714,7 @@ class TaintTrackingImplementation extends string {
}
pragma [noinline]
predicate taintedScopeEntryDefinition(TaintTrackingNode src, ScopeEntryDefinition defn, TaintTrackingContext context, AttributePath path, TaintKind kind) {
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)
@@ -761,20 +722,72 @@ class TaintTrackingImplementation extends string {
}
pragma [noinline]
predicate taintedWith(TaintTrackingNode src, WithDefinition defn, TaintTrackingContext context, AttributePath path, TaintKind kind) {
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())
)
}
predicate moduleAttributeTainted(ModuleValue m, string name, TaintTrackingNode taint) {
exists(DataFlow::Node srcnode, EssaVariable var |
taint = TTaintTrackingNode_(srcnode, TNoParam(), _, _, this) and
var = srcnode.asVariable() and
var.getName() = name and
BaseFlow::reaches_exit(var) and
var.getScope() = m.getScope()
/** 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(ControlFlowNode test, ControlFlowNode use, TaintKind kind) {
boolean_filter(_, use) and
kind.taints(use) and
test = use and result = kind.booleanValue()
or
result = testEvaluates(not_operand(test), use, kind).booleanNot()
or
exists(ControlFlowNode const |
Filters::equality_test(test, use, result.booleanNot(), const) and
const.getNode() instanceof ImmutableLiteral
)
or
exists(ControlFlowNode c, ClassValue cls |
Filters::isinstance(test, c, use) and
c.pointsTo(cls)
|
exists(ClassValue scls |
scls = kind.getType() |
scls.getASuperType() = cls and result = true
or
not scls.getASuperType() = cls and result = false
)
or
not exists(kind.getType()) and result = maybe()
)
}
private predicate testEvaluatesMaybe(ControlFlowNode test, ControlFlowNode use) {
any(PyEdgeRefinement ref).getTest().getAChild*() = test and
test.getAChild*() = use and
not test.(UnaryExprNode).getNode().getOp() instanceof Not and
not Filters::equality_test(test, use, _, _) and
not Filters::isinstance(test, _, use) and
not test = use
or
testEvaluatesMaybe(not_operand(test), use)
}
/** Gets the operand of a unary `not` expression. */
private ControlFlowNode not_operand(ControlFlowNode expr) {
expr.(UnaryExprNode).getNode().getOp() instanceof Not and
result = expr.(UnaryExprNode).getOperand()
}
/** Holds if `test` is the test in a branch and `use` is that test
* with all the `not` prefixes removed.
*/
private predicate boolean_filter(ControlFlowNode test, ControlFlowNode use) {
any(PyEdgeRefinement ref).getTest() = test and
(
use = test
or
exists(ControlFlowNode notuse |
boolean_filter(test, notuse) and
use = not_operand(notuse)
)
)
}
@@ -787,74 +800,6 @@ private predicate with_flow(With with, ControlFlowNode contextManager, ControlFl
contextManager.strictlyDominates(var)
}
/* 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) {
isValid() and
src = src
}
override predicate isSink(TaintSink sink) {
isValid() and
sink = sink
}
override predicate isSanitizer(Sanitizer sanitizer) {
isValid() and
sanitizer = sanitizer
}
private predicate isValid() {
not exists(TaintTracking::Configuration config | config != this)
}
override predicate isAdditionalFlowStep(DataFlow::Node src, DataFlow::Node dest) {
isValid() and
exists(DataFlowExtension::DataFlowNode legacyExtension |
src.asCfgNode() = legacyExtension
|
dest.asCfgNode() = legacyExtension.getASuccessorNode()
or
dest.asVariable() = legacyExtension.getASuccessorVariable()
or
dest.asCfgNode() = legacyExtension.getAReturnSuccessorNode(_)
or
dest.asCfgNode() = legacyExtension.getACalleeSuccessorNode(_)
)
}
override predicate isAdditionalFlowStep(DataFlow::Node src, DataFlow::Node dest, TaintKind srckind, TaintKind destkind) {
isValid() and
exists(DataFlowExtension::DataFlowNode legacyExtension |
src.asCfgNode() = legacyExtension
|
dest.asCfgNode() = legacyExtension.getASuccessorNode(srckind, destkind)
)
}
override predicate isBarrierEdge(DataFlow::Node src, DataFlow::Node dest) {
isValid() and
(
exists(DataFlowExtension::DataFlowVariable legacyExtension |
src.asVariable() = legacyExtension and
legacyExtension.prunedSuccessor(dest.asVariable())
)
or
exists(DataFlowExtension::DataFlowNode legacyExtension |
src.asCfgNode() = legacyExtension and
legacyExtension.prunedSuccessor(dest.asCfgNode())
)
)
}
}
module Implementation {
/* A call that returns a copy (or similar) of the argument */

View File

@@ -0,0 +1,94 @@
import semmle.python.security.TaintTracking
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
}
predicate appliesToScope(Scope s) {
exists(PythonFunctionObjectInternal func, TaintKind param, AttributePath path, int n |
this = TParamContext(param, path, n) and
exists(TaintTrackingImplementation impl |
impl.callWithTaintedArgument(_, _, _, func, n, path, param) and
s = func.getScope()
)
)
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) {
isValid() and
src = src
}
override predicate isSink(TaintSink sink) {
isValid() and
sink = sink
}
override predicate isSanitizer(Sanitizer sanitizer) {
isValid() and
sanitizer = sanitizer
}
private predicate isValid() {
not exists(TaintTracking::Configuration config | config != this)
}
override predicate isAdditionalFlowStep(DataFlow::Node src, DataFlow::Node dest) {
isValid() and
exists(DataFlowExtension::DataFlowNode legacyExtension |
src.asCfgNode() = legacyExtension
|
dest.asCfgNode() = legacyExtension.getASuccessorNode()
or
dest.asVariable() = legacyExtension.getASuccessorVariable()
or
dest.asCfgNode() = legacyExtension.getAReturnSuccessorNode(_)
or
dest.asCfgNode() = legacyExtension.getACalleeSuccessorNode(_)
)
}
override predicate isAdditionalFlowStep(DataFlow::Node src, DataFlow::Node dest, TaintKind srckind, TaintKind destkind) {
isValid() and
exists(DataFlowExtension::DataFlowNode legacyExtension |
src.asCfgNode() = legacyExtension
|
dest.asCfgNode() = legacyExtension.getASuccessorNode(srckind, destkind)
)
}
override predicate isBarrierEdge(DataFlow::Node src, DataFlow::Node dest) {
isValid() and
(
exists(DataFlowExtension::DataFlowVariable legacyExtension |
src.asVariable() = legacyExtension and
legacyExtension.prunedSuccessor(dest.asVariable())
)
or
exists(DataFlowExtension::DataFlowNode legacyExtension |
src.asCfgNode() = legacyExtension and
legacyExtension.prunedSuccessor(dest.asCfgNode())
)
)
}
}