Skip to content

Commit 7aef32e

Browse files
committed
Python: Add basic taint-tracking configuration. Should help avoid cross-talk between flows and brings the interface closer to that of the other languages.
1 parent b3d9350 commit 7aef32e

File tree

1 file changed

+86
-21
lines changed

1 file changed

+86
-21
lines changed

python/ql/src/semmle/python/security/TaintTracking.qll

Lines changed: 86 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -318,6 +318,14 @@ abstract class Sanitizer extends string {
318318

319319
}
320320

321+
/** Hold if `sanitizer` is valid. A sanitizer is valid if there is
322+
* a `TaintTracking::Configuration` that declares `sanitizer` or
323+
* there are no `TaintTracking::Configuration`s.
324+
*/
325+
private predicate valid_sanitizer(Sanitizer sanitizer) {
326+
forall (TaintTracking::Configuration c | c.isSanitizer(sanitizer))
327+
}
328+
321329
/** DEPRECATED -- Use DataFlowExtension instead.
322330
* An extension to taint-flow. For adding library or framework specific flows.
323331
* Examples include flow from a request to untrusted part of that request or
@@ -590,6 +598,7 @@ private newtype TTaintedNode =
590598
or
591599
kind = taint.(TaintFlowImplementation::TrackedAttribute).getKind(_) |
592600
not exists(Sanitizer sanitizer |
601+
valid_sanitizer(sanitizer) and
593602
sanitizer.sanitizingNode(kind, n)
594603
)
595604
)
@@ -839,26 +848,31 @@ library module TaintFlowImplementation {
839848
or
840849
call_taint_step(fromnode, totaint, tocontext, tonode)
841850
or
842-
fromnode.getNode().(DataFlowNode).getASuccessorNode() = tonode and
843-
fromnode.getContext() = tocontext and
844-
totaint = fromnode.getTrackedValue()
845-
or
846-
exists(CallNode call |
847-
fromnode.getNode().(DataFlowNode).getAReturnSuccessorNode(call) = tonode and
848-
fromnode.getContext() = tocontext.getCallee(call) and
849-
totaint = fromnode.getTrackedValue()
850-
)
851-
or
852-
exists(CallNode call |
853-
fromnode.getNode().(DataFlowNode).getACalleeSuccessorNode(call) = tonode and
854-
fromnode.getContext().getCallee(call) = tocontext and
851+
exists(DataFlowNode fromnodenode |
852+
fromnodenode = fromnode.getNode() and
853+
forall(TaintTracking::Configuration c | c.isExtension(fromnodenode))
854+
|
855+
fromnodenode.getASuccessorNode() = tonode and
856+
fromnode.getContext() = tocontext and
855857
totaint = fromnode.getTrackedValue()
856-
)
857-
or
858-
exists(TaintKind tokind |
859-
fromnode.getNode().(DataFlowNode).getASuccessorNode(fromnode.getTaintKind(), tokind) = tonode and
860-
totaint = fromnode.getTrackedValue().toKind(tokind) and
861-
tocontext = fromnode.getContext()
858+
or
859+
exists(CallNode call |
860+
fromnodenode.getAReturnSuccessorNode(call) = tonode and
861+
fromnode.getContext() = tocontext.getCallee(call) and
862+
totaint = fromnode.getTrackedValue()
863+
)
864+
or
865+
exists(CallNode call |
866+
fromnodenode.getACalleeSuccessorNode(call) = tonode and
867+
fromnode.getContext().getCallee(call) = tocontext and
868+
totaint = fromnode.getTrackedValue()
869+
)
870+
or
871+
exists(TaintKind tokind |
872+
fromnodenode.getASuccessorNode(fromnode.getTaintKind(), tokind) = tonode and
873+
totaint = fromnode.getTrackedValue().toKind(tokind) and
874+
tocontext = fromnode.getContext()
875+
)
862876
)
863877
or
864878
exists(TaintKind tokind |
@@ -1038,8 +1052,12 @@ library module TaintFlowImplementation {
10381052
prev.(DataFlowVariable).getASuccessorVariable() = var
10391053
)
10401054
or
1041-
origin.getNode().(DataFlowNode).getASuccessorVariable() = var and
1042-
context = origin.getContext()
1055+
exists(DataFlowNode originnode |
1056+
originnode = origin.getNode() and
1057+
forall(TaintTracking::Configuration c | c.isExtension(originnode)) and
1058+
originnode.getASuccessorVariable() = var and
1059+
context = origin.getContext()
1060+
)
10431061
or
10441062
exists(TrackedTaint taint, EssaVariable prev |
10451063
tainted_var(prev, context, origin) and
@@ -1062,6 +1080,7 @@ library module TaintFlowImplementation {
10621080
exists(TaintKind kind |
10631081
kind = origin.getTaintKind() and
10641082
not exists(Sanitizer san |
1083+
valid_sanitizer(san) |
10651084
san.sanitizingDefinition(kind, def)
10661085
or
10671086
san.sanitizingNode(kind, def.(EssaNodeDefinition).getDefiningNode())
@@ -1184,6 +1203,7 @@ library module TaintFlowImplementation {
11841203
exists(TaintKind kind |
11851204
kind = origin.getTaintKind() |
11861205
not exists(FunctionObject callee, Sanitizer sanitizer |
1206+
valid_sanitizer(sanitizer) and
11871207
callee.getACall() = call.getCall() and
11881208
sanitizer.sanitizingCall(kind, callee)
11891209
)
@@ -1197,6 +1217,7 @@ library module TaintFlowImplementation {
11971217
var = test.getInput() and
11981218
tainted_var(var, context, origin) and
11991219
not exists(Sanitizer sanitizer |
1220+
valid_sanitizer(sanitizer) and
12001221
sanitizer.sanitizingEdge(kind, test)
12011222
)
12021223
|
@@ -1246,6 +1267,7 @@ library module TaintFlowImplementation {
12461267
var = uniphi.getInput() and
12471268
tainted_var(var, context, origin) and
12481269
not exists(Sanitizer sanitizer |
1270+
valid_sanitizer(sanitizer) and
12491271
sanitizer.sanitizingSingleEdge(kind, uniphi)
12501272
)
12511273
)
@@ -1438,6 +1460,49 @@ class CallContext extends TCallContext {
14381460

14391461
}
14401462

1463+
1464+
module TaintTracking {
1465+
1466+
class Source = TaintSource;
1467+
1468+
class Sink = TaintSink;
1469+
1470+
class PathSource = TaintedPathSource;
1471+
1472+
class PathSink = TaintedPathSink;
1473+
1474+
class Extension = DataFlowExtension::DataFlowNode;
1475+
1476+
abstract class Configuration extends string {
1477+
1478+
bindingset[this]
1479+
Configuration() { this = this }
1480+
1481+
abstract predicate isSource(Source source);
1482+
1483+
abstract predicate isSink(Sink sink);
1484+
1485+
predicate isSanitizer(Sanitizer sanitizer) { none() }
1486+
1487+
predicate isExtension(Extension extension) { none() }
1488+
1489+
predicate hasFlowPath(PathSource source, PathSink sink) {
1490+
this.isSource(source.getNode()) and
1491+
this.isSink(sink.getNode()) and
1492+
source.flowsTo(sink)
1493+
}
1494+
1495+
predicate hasFlow(Source source, Sink sink) {
1496+
this.isSource(source) and
1497+
this.isSink(sink) and
1498+
source.flowsToSink(sink)
1499+
}
1500+
1501+
}
1502+
1503+
}
1504+
1505+
14411506
pragma [noinline]
14421507
private predicate dict_construct(ControlFlowNode itemnode, ControlFlowNode dictnode) {
14431508
dictnode.(DictNode).getAValue() = itemnode

0 commit comments

Comments
 (0)