Python: Update unitialized local to use new taint-tracking config.

This commit is contained in:
Mark Shannon
2019-08-08 14:25:27 +01:00
parent 24b4a4102c
commit 955e54b360
2 changed files with 81 additions and 82 deletions

View File

@@ -9,44 +9,6 @@ class Uninitialized extends TaintKind {
}
/** A source of an uninitialized variable.
* Either the start of the scope or a deletion.
*/
class UninitializedSource extends TaintedDefinition {
UninitializedSource() {
exists(FastLocalVariable var |
this.getSourceVariable() = var and
not var.escapes() |
this instanceof ScopeEntryDefinition
or
this instanceof DeletionDefinition
)
}
override predicate isSourceOf(TaintKind kind) {
kind instanceof Uninitialized
}
}
/** A loop where we are guaranteed (or is at least likely) to execute the body at least once.
*/
class AtLeastOnceLoop extends DataFlowExtension::DataFlowVariable {
AtLeastOnceLoop() {
loop_entry_variables(this, _)
}
/* If we are guaranteed to iterate over a loop at least once, then we can prune any edges that
* don't pass through the body.
*/
override predicate prunedSuccessor(EssaVariable succ) {
loop_entry_variables(this, succ)
}
}
private predicate loop_entry_variables(EssaVariable pred, EssaVariable succ) {
exists(PhiFunction phi, BasicBlock pb |
loop_entry_edge(pb, phi.getBasicBlock()) and
@@ -64,43 +26,6 @@ private predicate loop_entry_edge(BasicBlock pred, BasicBlock loop) {
)
}
class UnitializedSanitizer extends Sanitizer {
UnitializedSanitizer() { this = "use of variable" }
override
predicate sanitizingDefinition(TaintKind taint, EssaDefinition def) {
// An assignment cannot leave a variable uninitialized
taint instanceof Uninitialized and
(
def instanceof AssignmentDefinition
or
def instanceof ExceptionCapture
or
def instanceof ParameterDefinition
or
/* A use is a "sanitizer" of "uninitialized", as any use of an undefined
* variable will raise, making the subsequent code unreacahable.
*/
exists(def.(EssaNodeRefinement).getInput().getASourceUse())
or
exists(def.(PhiFunction).getAnInput().getASourceUse())
or
exists(def.(EssaEdgeRefinement).getInput().getASourceUse())
)
}
override
predicate sanitizingNode(TaintKind taint, ControlFlowNode node) {
taint instanceof Uninitialized and
exists(EssaVariable v |
v.getASourceUse() = node and
not first_use(node, v)
)
}
}
/** Since any use of a local will raise if it is uninitialized, then
* any use dominated by another use of the same variable must be defined, or is unreachable.
*/
@@ -124,15 +49,75 @@ private predicate maybe_call_to_exiting_function(CallNode call) {
)
}
/** Prune edges where the predecessor block looks like it might contain a call to an exit function. */
class ExitFunctionGuardedEdge extends DataFlowExtension::DataFlowVariable {
override predicate prunedSuccessor(EssaVariable succ) {
exists(CallNode exit_call |
succ.(PhiFunction).getInput(exit_call.getBasicBlock()) = this and
maybe_call_to_exiting_function(exit_call)
predicate exitFunctionGuardedEdge(EssaVariable pred, EssaVariable succ) {
exists(CallNode exit_call |
succ.(PhiFunction).getInput(exit_call.getBasicBlock()) = pred and
maybe_call_to_exiting_function(exit_call)
)
}
class UninitializedConfig extends TaintTracking::Configuration {
UninitializedConfig() {
this = "Unitialized local config"
}
override predicate isSource(DataFlow::Node source, TaintKind kind) {
kind instanceof Uninitialized and
exists(EssaVariable var |
source.asVariable() = var and
var.getSourceVariable() instanceof FastLocalVariable and
not var.getSourceVariable().(Variable).escapes() |
var instanceof ScopeEntryDefinition
or
var instanceof DeletionDefinition
)
}
override predicate isBarrier(DataFlow::Node node, TaintKind kind) {
kind instanceof Uninitialized and
(
definition(node.asVariable())
or
use(node.asVariable())
or
sanitizingNode(node.asCfgNode())
)
}
private predicate definition(EssaDefinition def) {
def instanceof AssignmentDefinition
or
def instanceof ExceptionCapture
or
def instanceof ParameterDefinition
}
private predicate use(EssaDefinition def) {
exists(def.(EssaNodeRefinement).getInput().getASourceUse())
or
exists(def.(PhiFunction).getAnInput().getASourceUse())
or
exists(def.(EssaEdgeRefinement).getInput().getASourceUse())
}
private predicate sanitizingNode(ControlFlowNode node) {
exists(EssaVariable v |
v.getASourceUse() = node and
not first_use(node, v)
)
}
override predicate isBarrierEdge(DataFlow::Node src, DataFlow::Node dest) {
/* If we are guaranteed to iterate over a loop at least once, then we can prune any edges that
* don't pass through the body.
*/
loop_entry_variables(src.asVariable(), dest.asVariable())
or
exitFunctionGuardedEdge(src.asVariable(), dest.asVariable())
}
}

View File

@@ -328,7 +328,21 @@ class TaintTrackingImplementation extends string {
this.unprunedStep(src, node, context, path, kind, edgeLabel) and
node.getBasicBlock().likelyReachable() and
not this.(TaintTracking::Configuration).isBarrier(node) and
not this.flowBarrier(node, kind) and path = TNoAttribute()
(
not path = TNoAttribute()
or
not this.flowBarrier(node, kind) and
exists(DataFlow::Node srcnode, TaintKind srckind |
src = TTaintTrackingNode_(srcnode, _, _, srckind, this) and
not this.prunedEdge(srcnode, node, srckind, kind)
)
)
}
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) {