diff --git a/python/ql/test/library-tests/dataflow/global-or-captured-vars/test.expected b/python/ql/test/library-tests/dataflow/global-or-captured-vars/test.expected new file mode 100644 index 000000000000..366de37b8677 --- /dev/null +++ b/python/ql/test/library-tests/dataflow/global-or-captured-vars/test.expected @@ -0,0 +1,4 @@ +argumentToEnsureNotTaintedNotMarkedAsSpurious +untaintedArgumentToEnsureTaintedNotMarkedAsMissing +testFailures +failures diff --git a/python/ql/test/library-tests/dataflow/global-or-captured-vars/test.py b/python/ql/test/library-tests/dataflow/global-or-captured-vars/test.py new file mode 100644 index 000000000000..7719021890f8 --- /dev/null +++ b/python/ql/test/library-tests/dataflow/global-or-captured-vars/test.py @@ -0,0 +1,118 @@ +import threading +import time + +# Test 1 +# TP - Flow is tracked through a global variable +foo1 = None + +def bar1(): + time.sleep(1) + ensure_tainted(foo1) # $tainted + +# The intent of these tests is to test how dataflow is handled through shared state accessed by different threads; +# but the presense or absense of the actual call to start a thread does not affect the results (there is no special modelling for Thread) +# threading.Thread(target=bar).start() + +foo1 = TAINTED_STRING + +# Test 2 +# FN - Flow is *not* tracked through an access path on a global variable +foo2 = [] + +def bar2(): + time.sleep(1) + ensure_tainted(foo2[0]) # $MISSING:tainted + +threading.Thread(target=bar2).start() + +foo2.append(TAINTED_STRING) + +# Test 3 +# FN - Flow is not found even when there is a direct call +foo3 = [] + +def bar3(): + time.sleep(1) + ensure_tainted(foo2[0]) # $MISSING:tainted + +foo3.append(TAINTED_STRING) +bar3() + +# Tast 4 +# TP - Sanity check: Flow is found through a ListElement directly without a call +foo4 = [] +foo4.append(TAINTED_STRING) +ensure_tainted(foo4[0]) # $tainted + +# Test 5 +# FN - Flow is *not* tracked through a shared captured but non-global variable +def test5(): + foo5 = None + + def bar5(): + time.sleep(1) + ensure_tainted(foo5) # $MISSING:tainted + + threading.Thread(target=bar5).start() # Only the presense of this thread call makes this an FN rather than a TN + + foo5 = TAINTED_STRING + + # Test 6 + # TP - Flow is tracked through a shared captured but non-global variable with a direct call +def test6(): + foo6 = [] + + def bar6(): + time.sleep(1) + ensure_tainted(foo6[0]) # $tainted + + foo6.append(TAINTED_STRING) + bar6() + + +# Test 7 +# FN - Flow is *not* found through an access path on a global variable that's also used as a parameter +# We'd like to cover this case in order to be able to cover this CVE: https://github.com/github/codeql-python-CVE-coverage/issues/3176 + +foo7 = [] + +def bar7(): + time.sleep(1) + ensure_tainted(foo7[0]) # $MISSING: tainted + +def baz7(loc_foo): + loc_foo.append(TAINTED_STRING) + +threading.Thread(target=bar7).start() + +baz7(foo7) + +# Test 8 +# FN - Flow is also *not* found in the above case through a direct call + +foo8 = [] + +def bar8(): + time.sleep(1) + ensure_tainted(foo8[0]) # $MISSING: tainted + +def baz8(loc_foo): + loc_foo.append(TAINTED_STRING) + +baz8(foo8) +bar8() + +# Test 9 +# TP - Flow is found in the above case when the variable is captured rather than global + +def test9(): + foo9 = [] + def bar9(): + time.sleep(1) + ensure_tainted(foo9[0]) # $tainted + + def baz9(loc_foo): + loc_foo.append(TAINTED_STRING) + + baz9(foo9) + bar9() \ No newline at end of file diff --git a/python/ql/test/library-tests/dataflow/global-or-captured-vars/test.ql b/python/ql/test/library-tests/dataflow/global-or-captured-vars/test.ql new file mode 100644 index 000000000000..dd01b5d3e341 --- /dev/null +++ b/python/ql/test/library-tests/dataflow/global-or-captured-vars/test.ql @@ -0,0 +1,3 @@ +import python +import experimental.meta.InlineTaintTest +import MakeInlineTaintTest