Skip to content

Python: Speed up taint-tracking #1169

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Mar 26, 2019
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
102 changes: 63 additions & 39 deletions python/ql/src/semmle/python/security/TaintTracking.qll
Original file line number Diff line number Diff line change
Expand Up @@ -189,25 +189,13 @@ class SequenceKind extends CollectionKind {
}

override TaintKind getTaintForFlowStep(ControlFlowNode fromnode, ControlFlowNode tonode) {
sequence_subscript_taint(tonode, fromnode, this, result)
or
result = this and
(
slice(fromnode, tonode) or
tonode.(BinaryExprNode).getAnOperand() = fromnode
)
or
result = this and TaintFlowImplementation::copyCall(fromnode, tonode)
or
exists(BinaryExprNode mod |
mod = tonode and
mod.getOp() instanceof Mod and
mod.getAnOperand() = fromnode and
result = this.getItem() and
result.getClass() = theStrType()
)
or
result = this and sequence_call(fromnode, tonode)
}

override TaintKind getTaintOfMethodResult(string name) {
Expand All @@ -220,26 +208,42 @@ class SequenceKind extends CollectionKind {

}

/* Helper for getTaintForStep() */

module SequenceKind {

predicate flowStep(ControlFlowNode fromnode, ControlFlowNode tonode) {
tonode.(BinaryExprNode).getAnOperand() = fromnode
or
TaintFlowImplementation::copyCall(fromnode, tonode)
or
sequence_call(fromnode, tonode)
or
sequence_subscript_slice(fromnode, tonode)
}

predicate itemFlowStep(ControlFlowNode fromnode, ControlFlowNode tonode) {
sequence_subscript_index(fromnode, tonode)
}

}


/* Helper for sequence flow steps */
pragma [noinline]
private predicate sequence_subscript_taint(SubscriptNode sub, ControlFlowNode obj, SequenceKind seq, TaintKind key) {
private predicate sequence_subscript_index(ControlFlowNode obj, SubscriptNode sub) {
sub.isLoad() and
sub.getValue() = obj and
if sub.getNode().getIndex() instanceof Slice then
seq = key
else
key = seq.getItem()
not sub.getNode().getIndex() instanceof Slice
}

/* tonode = fromnode[:] */
private predicate slice(ControlFlowNode fromnode, SubscriptNode tonode) {
exists(Slice all |
all = tonode.getIndex().getNode() and
not exists(all.getStart()) and not exists(all.getStop()) and
tonode.getValue() = fromnode
)
pragma [noinline]
private predicate sequence_subscript_slice(ControlFlowNode obj, SubscriptNode sub) {
sub.isLoad() and
sub.getValue() = obj and
sub.getNode().getIndex() instanceof Slice
}


/** A taint kind representing a mapping of objects to kinds.
* Typically a dict, but can include other mappings.
*/
Expand All @@ -255,20 +259,6 @@ class DictKind extends CollectionKind {
result = valueKind
}

override TaintKind getTaintForFlowStep(ControlFlowNode fromnode, ControlFlowNode tonode) {
result = valueKind and
tonode.(SubscriptNode).getValue() = fromnode and tonode.isLoad()
or
result = valueKind and
tonode.(CallNode).getFunction().(AttrNode).getObject("get") = fromnode
or
result = this and TaintFlowImplementation::copyCall(fromnode, tonode)
or
result = this and
tonode.(CallNode).getFunction().refersTo(theDictType()) and
tonode.(CallNode).getArg(0) = fromnode
}

override TaintKind getTaintOfMethodResult(string name) {
name = "get" and result = valueKind
or
Expand All @@ -284,6 +274,24 @@ class DictKind extends CollectionKind {
}


module DictKind {

predicate flowStep(ControlFlowNode fromnode, ControlFlowNode tonode) {
TaintFlowImplementation::copyCall(fromnode, tonode)
or
tonode.(CallNode).getFunction().refersTo(theDictType()) and
tonode.(CallNode).getArg(0) = fromnode
}

predicate valueFlowStep(ControlFlowNode fromnode, ControlFlowNode tonode) {
tonode.(SubscriptNode).getValue() = fromnode and tonode.isLoad()
or
tonode.(CallNode).getFunction().(AttrNode).getObject("get") = fromnode
}

}


/** A type of sanitizer of untrusted data.
* Examples include sanitizers for http responses, for DB access or for shell commands.
* Usually a sanitizer can only sanitize data for one particular use.
Expand Down Expand Up @@ -890,6 +898,22 @@ library module TaintFlowImplementation {
tocontext = fromnode.getContext()
)
or
exists(SequenceKind fromkind |
fromkind = fromnode.getTaintKind() and
tocontext = fromnode.getContext() |
totaint = fromnode.getTrackedValue() and SequenceKind::flowStep(fromnode.getNode(), tonode)
or
totaint = fromnode.getTrackedValue().toKind(fromkind.getItem()) and SequenceKind::itemFlowStep(fromnode.getNode(), tonode)
)
or
exists(DictKind fromkind |
fromkind = fromnode.getTaintKind() and
tocontext = fromnode.getContext() |
totaint = fromnode.getTrackedValue() and DictKind::flowStep(fromnode.getNode(), tonode)
or
totaint = fromnode.getTrackedValue().toKind(fromkind.getValue()) and DictKind::valueFlowStep(fromnode.getNode(), tonode)
)
or
exists(TaintFlow flow, TaintKind tokind |
flow.additionalFlowStep(fromnode.getNode(), fromnode.getTaintKind(), tonode, tokind) and
totaint = fromnode.getTrackedValue().toKind(tokind) and
Expand Down