diff --git a/python/ql/test/experimental/dataflow/model-summaries/TestSummaries.qll b/python/ql/test/experimental/dataflow/model-summaries/TestSummaries.qll deleted file mode 100644 index 5069c406a60..00000000000 --- a/python/ql/test/experimental/dataflow/model-summaries/TestSummaries.qll +++ /dev/null @@ -1,8 +0,0 @@ -private import python -private import semmle.python.dataflow.new.FlowSummary -private import semmle.python.frameworks.data.ModelsAsData -private import semmle.python.ApiGraphs - -private class StepsFromModel extends ModelInput::SummaryModelCsv { - override predicate row(string row) { none() } -} diff --git a/python/ql/test/experimental/dataflow/model-summaries/NormalTaintTrackingTest.expected b/python/ql/test/experimental/dataflow/model-summaries/dataflow/NormalDataflowTest.expected similarity index 100% rename from python/ql/test/experimental/dataflow/model-summaries/NormalTaintTrackingTest.expected rename to python/ql/test/experimental/dataflow/model-summaries/dataflow/NormalDataflowTest.expected diff --git a/python/ql/test/experimental/dataflow/model-summaries/dataflow/NormalDataflowTest.ql b/python/ql/test/experimental/dataflow/model-summaries/dataflow/NormalDataflowTest.ql new file mode 100644 index 00000000000..3e311335e14 --- /dev/null +++ b/python/ql/test/experimental/dataflow/model-summaries/dataflow/NormalDataflowTest.ql @@ -0,0 +1,3 @@ +import python +private import TestSummaries +import experimental.dataflow.TestUtil.NormalDataflowTest diff --git a/python/ql/test/experimental/dataflow/model-summaries/dataflow/TestSummaries.qll b/python/ql/test/experimental/dataflow/model-summaries/dataflow/TestSummaries.qll new file mode 100644 index 00000000000..d97702eec41 --- /dev/null +++ b/python/ql/test/experimental/dataflow/model-summaries/dataflow/TestSummaries.qll @@ -0,0 +1,20 @@ +private import python +private import semmle.python.dataflow.new.FlowSummary +private import semmle.python.frameworks.data.ModelsAsData +private import semmle.python.ApiGraphs + +private class StepsFromModel extends ModelInput::SummaryModelCsv { + override predicate row(string row) { + row = + [ + "Foo;Member[MS_identity];Argument[0];ReturnValue;value", + "Foo;Member[MS_apply_lambda];Argument[1];Argument[0].Parameter[0];value", + "Foo;Member[MS_apply_lambda];Argument[0].ReturnValue;ReturnValue;value", + "Foo;Member[MS_reversed];Argument[0].ListElement;ReturnValue.ListElement;value", + "Foo;Member[MS_list_map];Argument[1].ListElement;Argument[0].Parameter[0];value", + "Foo;Member[MS_list_map];Argument[0].ReturnValue;ReturnValue.ListElement;value", + "Foo;Member[MS_append_to_list];Argument[0].ListElement;ReturnValue.ListElement;value", + "Foo;Member[MS_append_to_list];Argument[1];ReturnValue.ListElement;value" + ] + } +} diff --git a/python/ql/test/experimental/dataflow/model-summaries/dataflow/model_summaries.py b/python/ql/test/experimental/dataflow/model-summaries/dataflow/model_summaries.py new file mode 100644 index 00000000000..c81fddf44ec --- /dev/null +++ b/python/ql/test/experimental/dataflow/model-summaries/dataflow/model_summaries.py @@ -0,0 +1,69 @@ + +import sys +import os + +sys.path.append(os.path.dirname(os.path.dirname((__file__)))) +from testlib import expects + +# These are defined so that we can evaluate the test code. +NONSOURCE = "not a source" +SOURCE = "source" + + +def is_source(x): + return x == "source" or x == b"source" or x == 42 or x == 42.0 or x == 42j + + +def SINK(x): + if is_source(x): + print("OK") + else: + print("Unexpected flow", x) + + +def SINK_F(x): + if is_source(x): + print("Unexpected flow", x) + else: + print("OK") + + +from Foo import MS_identity, MS_apply_lambda, MS_reversed, MS_list_map, MS_append_to_list + +# Simple summary +tainted = MS_identity(SOURCE) +SINK(tainted) # $ flow="SOURCE, l:-1 -> tainted" + +# Lambda summary +tainted_lambda = MS_apply_lambda(lambda x: [x], SOURCE) +SINK(tainted_lambda[0]) # $ flow="SOURCE, l:-1 -> tainted_lambda[0]" + +# A lambda that breaks the flow +untainted_lambda = MS_apply_lambda(lambda x: 1, SOURCE) +SINK_F(untainted_lambda) + +# Collection summaries +tainted_list = MS_reversed([SOURCE]) +SINK(tainted_list[0]) # $ flow="SOURCE, l:-1 -> tainted_list[0]" + +# Complex summaries +def box(x): + return [x] + +tainted_mapped = MS_list_map(box, [SOURCE]) +SINK(tainted_mapped[0][0]) # $ flow="SOURCE, l:-1 -> tainted_mapped[0][0]" + +def explicit_identity(x): + return x + +tainted_mapped_explicit = MS_list_map(explicit_identity, [SOURCE]) +SINK(tainted_mapped_explicit[0]) # $ flow="SOURCE, l:-1 -> tainted_mapped_explicit[0]" + +tainted_mapped_summary = MS_list_map(MS_identity, [SOURCE]) +SINK(tainted_mapped_summary[0]) # $ flow="SOURCE, l:-1 -> tainted_mapped_summary[0]" + +tainted_list = MS_append_to_list([], SOURCE) +SINK(tainted_list[0]) # $ flow="SOURCE, l:-1 -> tainted_list[0]" + +tainted_list = MS_append_to_list([SOURCE], NONSOURCE) +SINK(tainted_list[0]) # $ flow="SOURCE, l:-1 -> tainted_list[0]" diff --git a/python/ql/test/experimental/dataflow/model-summaries/taint/NormalTaintTrackingTest.expected b/python/ql/test/experimental/dataflow/model-summaries/taint/NormalTaintTrackingTest.expected new file mode 100644 index 00000000000..3875da4e143 --- /dev/null +++ b/python/ql/test/experimental/dataflow/model-summaries/taint/NormalTaintTrackingTest.expected @@ -0,0 +1,2 @@ +missingAnnotationOnSink +failures diff --git a/python/ql/test/experimental/dataflow/model-summaries/NormalTaintTrackingTest.ql b/python/ql/test/experimental/dataflow/model-summaries/taint/NormalTaintTrackingTest.ql similarity index 100% rename from python/ql/test/experimental/dataflow/model-summaries/NormalTaintTrackingTest.ql rename to python/ql/test/experimental/dataflow/model-summaries/taint/NormalTaintTrackingTest.ql diff --git a/python/ql/test/experimental/dataflow/model-summaries/taint/TestSummaries.qll b/python/ql/test/experimental/dataflow/model-summaries/taint/TestSummaries.qll new file mode 100644 index 00000000000..57861d3c022 --- /dev/null +++ b/python/ql/test/experimental/dataflow/model-summaries/taint/TestSummaries.qll @@ -0,0 +1,19 @@ +private import python +private import semmle.python.dataflow.new.FlowSummary +private import semmle.python.frameworks.data.ModelsAsData +private import semmle.python.ApiGraphs + +private class StepsFromModel extends ModelInput::SummaryModelCsv { + override predicate row(string row) { + row = + [ + "Foo;Member[MS_identity];Argument[0];ReturnValue;value", + "Foo;Member[MS_apply_lambda];Argument[1];Argument[0].Parameter[0];value", + "Foo;Member[MS_apply_lambda];Argument[0].ReturnValue;ReturnValue;value", + "Foo;Member[MS_reversed];Argument[0];ReturnValue;taint", + "Foo;Member[MS_list_map];Argument[1];ReturnValue;taint", + "Foo;Member[MS_append_to_list];Argument[0];ReturnValue;taint", + "json;Member[MS_loads];Argument[0];ReturnValue;taint" + ] + } +} diff --git a/python/ql/test/experimental/dataflow/model-summaries/model_summaries.py b/python/ql/test/experimental/dataflow/model-summaries/taint/model_summaries_taint.py similarity index 62% rename from python/ql/test/experimental/dataflow/model-summaries/model_summaries.py rename to python/ql/test/experimental/dataflow/model-summaries/taint/model_summaries_taint.py index 23cc4990aba..44ca79c116e 100644 --- a/python/ql/test/experimental/dataflow/model-summaries/model_summaries.py +++ b/python/ql/test/experimental/dataflow/model-summaries/taint/model_summaries_taint.py @@ -28,15 +28,15 @@ def SINK_F(x): print("OK") -from Foo import MS_identity +from Foo import MS_identity, MS_apply_lambda, MS_reversed, MS_list_map, MS_append_to_list # Simple summary tainted = MS_identity(SOURCE) -SINK(tainted) # $ MISSING: flow="SOURCE, l:-1 -> tainted" +SINK(tainted) # $ flow="SOURCE, l:-1 -> tainted" # Lambda summary tainted_lambda = MS_apply_lambda(lambda x: x + 1, SOURCE) -SINK(tainted_lambda) # $ MISSING: flow="SOURCE, l:-1 -> tainted_lambda" +SINK(tainted_lambda) # $ flow="SOURCE, l:-1 -> tainted_lambda" # A lambda that breaks the flow untainted_lambda = MS_apply_lambda(lambda x: 1, SOURCE) @@ -44,27 +44,27 @@ SINK_F(untainted_lambda) # Collection summaries tainted_list = MS_reversed([SOURCE]) -SINK(tainted_list[0]) # $ MISSING: flow="SOURCE, l:-1 -> tainted_list[0]" +SINK(tainted_list[0]) # $ flow="SOURCE, l:-1 -> tainted_list[0]" # Complex summaries def add_colon(x): return x + ":" tainted_mapped = MS_list_map(add_colon, [SOURCE]) -SINK(tainted_mapped[0]) # $ MISSING: flow="SOURCE, l:-1 -> tainted_mapped[0]" +SINK(tainted_mapped[0]) # $ flow="SOURCE, l:-1 -> tainted_mapped[0]" def explicit_identity(x): return x tainted_mapped_explicit = MS_list_map(explicit_identity, [SOURCE]) -SINK(tainted_mapped_explicit[0]) # $ MISSING: flow="SOURCE, l:-1 -> tainted_mapped_explicit[0]" +SINK(tainted_mapped_explicit[0]) # $ flow="SOURCE, l:-1 -> tainted_mapped_explicit[0]" tainted_mapped_summary = MS_list_map(MS_identity, [SOURCE]) -SINK(tainted_mapped_summary[0]) # $ MISSING: flow="SOURCE, l:-1 -> tainted_mapped_summary[0]" +SINK(tainted_mapped_summary[0]) # $ flow="SOURCE, l:-1 -> tainted_mapped_summary[0]" -tainted_list = MS_append_to_list([], SOURCE) -SINK(tainted_list[0]) # $ MISSING: flow="SOURCE, l:-1 -> tainted_list[0]" +tainted_list = MS_append_to_list([SOURCE], NONSOURCE) +SINK(tainted_list[0]) # $ flow="SOURCE, l:-1 -> tainted_list[0]" from json import MS_loads as json_loads tainted_resultlist = json_loads(SOURCE) -SINK(tainted_resultlist[0]) # $ MISSING: flow="SOURCE, l:-1 -> tainted_resultlist[0]" +SINK(tainted_resultlist[0]) # $ flow="SOURCE, l:-1 -> tainted_resultlist[0]"