mirror of
https://github.com/github/codeql.git
synced 2026-04-30 19:26:02 +02:00
Python: Update unitialized local to use new taint-tracking config.
This commit is contained in:
@@ -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())
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -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) {
|
||||
|
||||
Reference in New Issue
Block a user