@@ -712,32 +712,16 @@ private class EssaTaintTracking extends string {
712712 TaintTrackingNode src , MultiAssignmentDefinition defn , TaintTrackingContext context ,
713713 AttributePath path , TaintKind kind
714714 ) {
715- exists ( DataFlow:: Node srcnode , TaintKind srckind , Assign assign |
715+ exists ( DataFlow:: Node srcnode , TaintKind srckind , Assign assign , int depth |
716716 src = TTaintTrackingNode_ ( srcnode , context , path , srckind , this ) and
717717 path .noAttribute ( )
718718 |
719719 assign .getValue ( ) .getAFlowNode ( ) = srcnode .asCfgNode ( ) and
720- kind = iterable_unpacking_descent ( assign .getATarget ( ) .getAFlowNode ( ) , defn .getDefiningNode ( ) ,
721- srckind )
720+ depth = iterable_unpacking_descent ( assign .getATarget ( ) .getAFlowNode ( ) , defn .getDefiningNode ( ) ) and
721+ kind = taint_at_depth ( srckind , depth )
722722 )
723723 }
724724
725- /** `((x,y), ...) = value` with any nesting on LHS */
726- private TaintKind iterable_unpacking_descent (
727- SequenceNode left_parent , ControlFlowNode left_defn , CollectionKind parent_kind
728- ) {
729- //TODO: Fix the cartesian product in this predicate
730- none ( ) and
731- left_parent .getAnElement ( ) = left_defn and
732- // Handle `a, *b = some_iterable`
733- if left_defn instanceof StarredNode
734- then result = parent_kind
735- else result = parent_kind .getMember ( )
736- or
737- result = iterable_unpacking_descent ( left_parent .getAnElement ( ) , left_defn ,
738- parent_kind .getMember ( ) )
739- }
740-
741725 pragma [ noinline]
742726 private predicate taintedAttributeAssignment (
743727 TaintTrackingNode src , AttributeAssignment defn , TaintTrackingContext context ,
@@ -967,6 +951,46 @@ private predicate piNodeTestAndUse(PyEdgeRefinement defn, ControlFlowNode test,
967951 test = defn .getTest ( ) and use = defn .getInput ( ) .getASourceUse ( ) and test .getAChild * ( ) = use
968952}
969953
954+ /** Helper predicate for taintedMultiAssignment */
955+ private TaintKind taint_at_depth ( SequenceKind parent_kind , int depth ) {
956+ depth >= 0 and
957+ (
958+ // base-case #0
959+ depth = 0 and
960+ result = parent_kind
961+ or
962+ // base-case #1
963+ depth = 1 and
964+ result = parent_kind .getMember ( )
965+ or
966+ // recursive case
967+ depth > 1 and
968+ result = taint_at_depth ( parent_kind .getMember ( ) , depth - 1 )
969+ )
970+ }
971+
972+ /** Helper predicate for taintedMultiAssignment
973+ *
974+ * Returns the `depth` the elements that are assigned to `left_defn` with iterable unpacking has,
975+ * compared to `left_parent`. Special care is taken for `StarredNode` that is assigned a sequence of items.
976+ *
977+ * For example, `((x, *y), ...) = value` with any nesting on LHS
978+ * - with `left_defn` = `x`, `left_parent` = `(x, *y)`, result = 1
979+ * - with `left_defn` = `x`, `left_parent` = `((x, *y), ...)`, result = 2
980+ * - with `left_defn` = `*y`, `left_parent` = `(x, *y)`, result = 0
981+ * - with `left_defn` = `*y`, `left_parent` = `((x, *y), ...)`, result = 1
982+ */
983+ int iterable_unpacking_descent ( SequenceNode left_parent , ControlFlowNode left_defn ) {
984+ exists ( Assign a | a .getATarget ( ) .getASubExpression * ( ) .getAFlowNode ( ) = left_parent ) and
985+ left_parent .getAnElement ( ) = left_defn and
986+ // Handle `a, *b = some_iterable`
987+ if left_defn instanceof StarredNode
988+ then result = 0
989+ else result = 1
990+ or
991+ result = 1 + iterable_unpacking_descent ( left_parent .getAnElement ( ) , left_defn )
992+ }
993+
970994module Implementation {
971995 /* A call that returns a copy (or similar) of the argument */
972996 predicate copyCall ( ControlFlowNode fromnode , CallNode tonode ) {
0 commit comments