Skip to content

Commit 12c6997

Browse files
committed
Python: Reduce result set in custom taint sanitizer
1 parent 083dd43 commit 12c6997

1 file changed

Lines changed: 26 additions & 14 deletions

File tree

  • python/ql/test/library-tests/examples/custom-sanitizer

python/ql/test/library-tests/examples/custom-sanitizer/Taint.qll

Lines changed: 26 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -36,22 +36,34 @@ class MySanitizerHandlingNot extends Sanitizer {
3636
/** The test `if is_safe(arg):` sanitizes `arg` on its `true` edge. */
3737
override predicate sanitizingEdge(TaintKind taint, PyEdgeRefinement test) {
3838
taint instanceof ExternalStringKind and
39-
exists(CallNode call |
40-
clears_taint_on_true(call, test.getTest(), test.getSense())
41-
|
42-
call = Value::named("test.is_safe").getACall() and
43-
test.getInput().getAUse() = call.getAnArg()
44-
)
39+
clears_taint_on_true(_, test.getTest(), test.getSense(), test)
4540
}
4641

47-
private predicate clears_taint_on_true(ControlFlowNode final_test, ControlFlowNode test, boolean sense) {
48-
final_test = test and
49-
sense = true
50-
or
51-
test.(UnaryExprNode).getNode().getOp() instanceof Not and
52-
exists(ControlFlowNode nested_test |
53-
nested_test = test.(UnaryExprNode).getOperand() and
54-
clears_taint_on_true(final_test, nested_test, sense.booleanNot())
42+
/**
43+
* Helper predicate that recurses into any nesting of `not`
44+
*
45+
* To reduce the number of tuples this predicate holds for, we include the `PyEdgeRefinement` and
46+
* ensure that `test` is a part of this `PyEdgeRefinement`. Without including `PyEdgeRefinement` as an argument
47+
* *any* `CallNode c` to `test.is_safe` would be a result of this predicate, since (c, c, true) would hold.
48+
*/
49+
private predicate clears_taint_on_true(
50+
CallNode final_test, ControlFlowNode test, boolean sense, PyEdgeRefinement edge_refinement
51+
) {
52+
(
53+
edge_refinement.getTest().getNode().(Expr).getASubExpression*() = test.getNode() and
54+
test.getNode().(Expr).getASubExpression*() = final_test.getNode()
55+
) and
56+
(
57+
final_test = test and
58+
final_test = Value::named("test.is_safe").getACall() and
59+
edge_refinement.getInput().getAUse() = final_test.getAnArg() and
60+
sense = true
61+
or
62+
test.(UnaryExprNode).getNode().getOp() instanceof Not and
63+
exists(ControlFlowNode nested_test |
64+
nested_test = test.(UnaryExprNode).getOperand() and
65+
clears_taint_on_true(final_test, nested_test, sense.booleanNot(), edge_refinement)
66+
)
5567
)
5668
}
5769
}

0 commit comments

Comments
 (0)