mirror of
https://github.com/github/codeql.git
synced 2025-12-20 10:46:30 +01:00
Python: Fix iterable-unpacking taint CP
When running ql/python/ql/src/Security/CWE-079/ReflectedXss.ql against the database for flask. Iitially there were 10 million result-tuples for iterable_unpacking_descent. With this change, we're down to roughly 2100,
This commit is contained in:
@@ -712,32 +712,16 @@ private class EssaTaintTracking extends string {
|
||||
TaintTrackingNode src, MultiAssignmentDefinition defn, TaintTrackingContext context,
|
||||
AttributePath path, TaintKind kind
|
||||
) {
|
||||
exists(DataFlow::Node srcnode, TaintKind srckind, Assign assign |
|
||||
exists(DataFlow::Node srcnode, TaintKind srckind, Assign assign, int depth |
|
||||
src = TTaintTrackingNode_(srcnode, context, path, srckind, this) and
|
||||
path.noAttribute()
|
||||
|
|
||||
assign.getValue().getAFlowNode() = srcnode.asCfgNode() and
|
||||
kind = iterable_unpacking_descent(assign.getATarget().getAFlowNode(), defn.getDefiningNode(),
|
||||
srckind)
|
||||
depth = iterable_unpacking_descent(assign.getATarget().getAFlowNode(), defn.getDefiningNode()) and
|
||||
kind = taint_at_depth(srckind, depth)
|
||||
)
|
||||
}
|
||||
|
||||
/** `((x,y), ...) = value` with any nesting on LHS */
|
||||
private TaintKind iterable_unpacking_descent(
|
||||
SequenceNode left_parent, ControlFlowNode left_defn, CollectionKind parent_kind
|
||||
) {
|
||||
//TODO: Fix the cartesian product in this predicate
|
||||
none() and
|
||||
left_parent.getAnElement() = left_defn and
|
||||
// Handle `a, *b = some_iterable`
|
||||
if left_defn instanceof StarredNode
|
||||
then result = parent_kind
|
||||
else result = parent_kind.getMember()
|
||||
or
|
||||
result = iterable_unpacking_descent(left_parent.getAnElement(), left_defn,
|
||||
parent_kind.getMember())
|
||||
}
|
||||
|
||||
pragma[noinline]
|
||||
private predicate taintedAttributeAssignment(
|
||||
TaintTrackingNode src, AttributeAssignment defn, TaintTrackingContext context,
|
||||
@@ -967,6 +951,45 @@ private predicate piNodeTestAndUse(PyEdgeRefinement defn, ControlFlowNode test,
|
||||
test = defn.getTest() and use = defn.getInput().getASourceUse() and test.getAChild*() = use
|
||||
}
|
||||
|
||||
/** Helper predicate for taintedMultiAssignment */
|
||||
private TaintKind taint_at_depth(SequenceKind parent_kind, int depth) {
|
||||
depth >= 0 and
|
||||
(
|
||||
// base-case #0
|
||||
depth = 0 and
|
||||
result = parent_kind
|
||||
or
|
||||
// base-case #1
|
||||
depth = 1 and
|
||||
result = parent_kind.getMember()
|
||||
or
|
||||
// recursive case
|
||||
result = taint_at_depth(parent_kind.getMember(), depth-1)
|
||||
)
|
||||
}
|
||||
|
||||
/** Helper predicate for taintedMultiAssignment
|
||||
*
|
||||
* Returns the `depth` the elements that are assigned to `left_defn` with iterable unpacking has,
|
||||
* compared to `left_parent`. Special care is taken for `StarredNode` that is assigned a sequence of items.
|
||||
*
|
||||
* For example, `((x, *y), ...) = value` with any nesting on LHS
|
||||
* - with `left_defn` = `x`, `left_parent` = `(x, *y)`, result = 1
|
||||
* - with `left_defn` = `x`, `left_parent` = `((x, *y), ...)`, result = 2
|
||||
* - with `left_defn` = `*y`, `left_parent` = `(x, *y)`, result = 0
|
||||
* - with `left_defn` = `*y`, `left_parent` = `((x, *y), ...)`, result = 1
|
||||
*/
|
||||
int iterable_unpacking_descent(SequenceNode left_parent, ControlFlowNode left_defn) {
|
||||
exists(Assign a | a.getATarget().getASubExpression*().getAFlowNode() = left_parent) and
|
||||
left_parent.getAnElement() = left_defn and
|
||||
// Handle `a, *b = some_iterable`
|
||||
if left_defn instanceof StarredNode
|
||||
then result = 0
|
||||
else result = 1
|
||||
or
|
||||
result = 1 + iterable_unpacking_descent(left_parent.getAnElement(), left_defn)
|
||||
}
|
||||
|
||||
module Implementation {
|
||||
/* A call that returns a copy (or similar) of the argument */
|
||||
predicate copyCall(ControlFlowNode fromnode, CallNode tonode) {
|
||||
|
||||
Reference in New Issue
Block a user