Skip to content

Commit 955e54b

Browse files
committed
Python: Update unitialized local to use new taint-tracking config.
1 parent 24b4a41 commit 955e54b

File tree

2 files changed

+81
-82
lines changed

2 files changed

+81
-82
lines changed

python/ql/src/Variables/Undefined.qll

Lines changed: 66 additions & 81 deletions
Original file line numberDiff line numberDiff line change
@@ -9,44 +9,6 @@ class Uninitialized extends TaintKind {
99

1010
}
1111

12-
/** A source of an uninitialized variable.
13-
* Either the start of the scope or a deletion.
14-
*/
15-
class UninitializedSource extends TaintedDefinition {
16-
17-
UninitializedSource() {
18-
exists(FastLocalVariable var |
19-
this.getSourceVariable() = var and
20-
not var.escapes() |
21-
this instanceof ScopeEntryDefinition
22-
or
23-
this instanceof DeletionDefinition
24-
)
25-
}
26-
27-
override predicate isSourceOf(TaintKind kind) {
28-
kind instanceof Uninitialized
29-
}
30-
31-
}
32-
33-
/** A loop where we are guaranteed (or is at least likely) to execute the body at least once.
34-
*/
35-
class AtLeastOnceLoop extends DataFlowExtension::DataFlowVariable {
36-
37-
AtLeastOnceLoop() {
38-
loop_entry_variables(this, _)
39-
}
40-
41-
/* If we are guaranteed to iterate over a loop at least once, then we can prune any edges that
42-
* don't pass through the body.
43-
*/
44-
override predicate prunedSuccessor(EssaVariable succ) {
45-
loop_entry_variables(this, succ)
46-
}
47-
48-
}
49-
5012
private predicate loop_entry_variables(EssaVariable pred, EssaVariable succ) {
5113
exists(PhiFunction phi, BasicBlock pb |
5214
loop_entry_edge(pb, phi.getBasicBlock()) and
@@ -64,43 +26,6 @@ private predicate loop_entry_edge(BasicBlock pred, BasicBlock loop) {
6426
)
6527
}
6628

67-
class UnitializedSanitizer extends Sanitizer {
68-
69-
UnitializedSanitizer() { this = "use of variable" }
70-
71-
override
72-
predicate sanitizingDefinition(TaintKind taint, EssaDefinition def) {
73-
// An assignment cannot leave a variable uninitialized
74-
taint instanceof Uninitialized and
75-
(
76-
def instanceof AssignmentDefinition
77-
or
78-
def instanceof ExceptionCapture
79-
or
80-
def instanceof ParameterDefinition
81-
or
82-
/* A use is a "sanitizer" of "uninitialized", as any use of an undefined
83-
* variable will raise, making the subsequent code unreacahable.
84-
*/
85-
exists(def.(EssaNodeRefinement).getInput().getASourceUse())
86-
or
87-
exists(def.(PhiFunction).getAnInput().getASourceUse())
88-
or
89-
exists(def.(EssaEdgeRefinement).getInput().getASourceUse())
90-
)
91-
}
92-
93-
override
94-
predicate sanitizingNode(TaintKind taint, ControlFlowNode node) {
95-
taint instanceof Uninitialized and
96-
exists(EssaVariable v |
97-
v.getASourceUse() = node and
98-
not first_use(node, v)
99-
)
100-
}
101-
102-
}
103-
10429
/** Since any use of a local will raise if it is uninitialized, then
10530
* any use dominated by another use of the same variable must be defined, or is unreachable.
10631
*/
@@ -124,15 +49,75 @@ private predicate maybe_call_to_exiting_function(CallNode call) {
12449
)
12550
}
12651

127-
/** Prune edges where the predecessor block looks like it might contain a call to an exit function. */
128-
class ExitFunctionGuardedEdge extends DataFlowExtension::DataFlowVariable {
12952

130-
override predicate prunedSuccessor(EssaVariable succ) {
131-
exists(CallNode exit_call |
132-
succ.(PhiFunction).getInput(exit_call.getBasicBlock()) = this and
133-
maybe_call_to_exiting_function(exit_call)
53+
predicate exitFunctionGuardedEdge(EssaVariable pred, EssaVariable succ) {
54+
exists(CallNode exit_call |
55+
succ.(PhiFunction).getInput(exit_call.getBasicBlock()) = pred and
56+
maybe_call_to_exiting_function(exit_call)
57+
)
58+
}
59+
60+
class UninitializedConfig extends TaintTracking::Configuration {
61+
62+
UninitializedConfig() {
63+
this = "Unitialized local config"
64+
}
65+
66+
override predicate isSource(DataFlow::Node source, TaintKind kind) {
67+
kind instanceof Uninitialized and
68+
exists(EssaVariable var |
69+
source.asVariable() = var and
70+
var.getSourceVariable() instanceof FastLocalVariable and
71+
not var.getSourceVariable().(Variable).escapes() |
72+
var instanceof ScopeEntryDefinition
73+
or
74+
var instanceof DeletionDefinition
13475
)
13576
}
13677

78+
override predicate isBarrier(DataFlow::Node node, TaintKind kind) {
79+
kind instanceof Uninitialized and
80+
(
81+
definition(node.asVariable())
82+
or
83+
use(node.asVariable())
84+
or
85+
sanitizingNode(node.asCfgNode())
86+
)
87+
}
88+
89+
private predicate definition(EssaDefinition def) {
90+
def instanceof AssignmentDefinition
91+
or
92+
def instanceof ExceptionCapture
93+
or
94+
def instanceof ParameterDefinition
95+
}
96+
97+
private predicate use(EssaDefinition def) {
98+
exists(def.(EssaNodeRefinement).getInput().getASourceUse())
99+
or
100+
exists(def.(PhiFunction).getAnInput().getASourceUse())
101+
or
102+
exists(def.(EssaEdgeRefinement).getInput().getASourceUse())
103+
}
104+
105+
private predicate sanitizingNode(ControlFlowNode node) {
106+
exists(EssaVariable v |
107+
v.getASourceUse() = node and
108+
not first_use(node, v)
109+
)
110+
}
111+
112+
override predicate isBarrierEdge(DataFlow::Node src, DataFlow::Node dest) {
113+
/* If we are guaranteed to iterate over a loop at least once, then we can prune any edges that
114+
* don't pass through the body.
115+
*/
116+
loop_entry_variables(src.asVariable(), dest.asVariable())
117+
or
118+
exitFunctionGuardedEdge(src.asVariable(), dest.asVariable())
119+
}
120+
137121
}
138122

123+

python/ql/src/semmle/python/dataflow/Implementation.qll

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -328,7 +328,21 @@ class TaintTrackingImplementation extends string {
328328
this.unprunedStep(src, node, context, path, kind, edgeLabel) and
329329
node.getBasicBlock().likelyReachable() and
330330
not this.(TaintTracking::Configuration).isBarrier(node) and
331-
not this.flowBarrier(node, kind) and path = TNoAttribute()
331+
(
332+
not path = TNoAttribute()
333+
or
334+
not this.flowBarrier(node, kind) and
335+
exists(DataFlow::Node srcnode, TaintKind srckind |
336+
src = TTaintTrackingNode_(srcnode, _, _, srckind, this) and
337+
not this.prunedEdge(srcnode, node, srckind, kind)
338+
)
339+
)
340+
}
341+
342+
predicate prunedEdge(DataFlow::Node srcnode, DataFlow::Node destnode, TaintKind srckind, TaintKind destkind) {
343+
this.(TaintTracking::Configuration).isBarrierEdge(srcnode, destnode, srckind, destkind)
344+
or
345+
srckind = destkind and this.(TaintTracking::Configuration).isBarrierEdge(srcnode, destnode)
332346
}
333347

334348
predicate unprunedStep(TaintTrackingNode src, DataFlow::Node node, TaintTrackingContext context, AttributePath path, TaintKind kind, string edgeLabel) {

0 commit comments

Comments
 (0)