Skip to content

Commit 16f2cd1

Browse files
authored
Merge pull request diffblue#273 from diffblue/smowton/fix/end_to_end_tests
SEC-144: Add a variety of end-to-end security analyser tests, and fix several bugs exposed by them
2 parents 8e88c89 + 4ccc7bd commit 16f2cd1

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

54 files changed

+925
-323
lines changed

cbmc/src/util/irep_ids.def

+1
Original file line numberDiff line numberDiff line change
@@ -845,6 +845,7 @@ IREP_ID_ONE(havoc_object)
845845
IREP_ID_TWO(overflow_shl, overflow-shl)
846846
IREP_ID_ONE(lvsa_evs_type)
847847
IREP_ID_ONE(is_initializer)
848+
IREP_ID_TWO(C_is_taint_wrapper_type, #is_taint_wrapper_type)
848849

849850
#undef IREP_ID_ONE
850851
#undef IREP_ID_TWO

regression/end_to_end/.gitignore

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
# Ensure Ant build directories are ignored below here:
2+
build/
3+
dist/

regression/end_to_end/driver.py

+15-7
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@ def working_dir(new_dir):
1818
@contextlib.contextmanager
1919
def temp_dir_deleter(dirname):
2020
yield
21+
if "SECURITY_ANALYSER_END_TO_END_TESTS_KEEP_RESULTS" in os.environ:
22+
return
2123
try:
2224
shutil.rmtree(dirname)
2325
except:
@@ -51,8 +53,9 @@ def trace_exists(self, function, line_no):
5153
return False
5254

5355
def run_security_analyser_pipeline(
54-
relative_jar_path,
56+
relative_binary_path,
5557
relative_rules_path,
58+
base_path,
5659
extra_args = []):
5760

5861
regression_tests_path = os.getcwd()
@@ -61,22 +64,24 @@ def run_security_analyser_pipeline(
6164
raise Exception("Set SECURITY_SCANNER_HOME to a path containing the 'security-analyzer' binary")
6265
pipeline_driver_path = \
6366
os.path.realpath(os.path.join(regression_tests_path, "..", "driver", "run.py"))
64-
absolute_jar_path = \
65-
os.path.join(regression_tests_path, "end_to_end", relative_jar_path)
67+
absolute_binary_path = \
68+
os.path.join(base_path, relative_binary_path)
6669
absolute_rules_path = \
67-
os.path.join(regression_tests_path, "end_to_end", relative_rules_path)
70+
os.path.join(base_path, relative_rules_path)
6871

6972
results_dir = tempfile.mkdtemp()
7073
temporary_dir = tempfile.mkdtemp()
7174

7275
cmdline = ["python", pipeline_driver_path,
7376
"-C", absolute_rules_path,
74-
"-I", absolute_jar_path,
77+
"-I", absolute_binary_path,
7578
"-R", results_dir,
7679
"-T", temporary_dir,
77-
"--name", relative_jar_path,
78-
"--verbosity", "0"]
80+
"--name", relative_binary_path,
81+
"--verbosity", "9"]
7982
cmdline.extend(extra_args)
83+
if "SECURITY_ANALYSER_END_TO_END_TESTS_EXTRA_ARGS" in os.environ:
84+
cmdline.extend(os.environ["SECURITY_ANALYSER_END_TO_END_TESTS_EXTRA_ARGS"].split(","))
8085

8186
with working_dir(analyzer_home), \
8287
temp_dir_deleter(results_dir), \
@@ -106,4 +111,7 @@ def run_security_analyser_pipeline(
106111
trace_json = json.load(trace_file)
107112
inline_traces.append(trace_json)
108113

114+
if "SECURITY_ANALYSER_END_TO_END_TESTS_KEEP_RESULTS" in os.environ:
115+
print("Test %s kept results (%s) and temporary directory (%s)" % (cmdline, results_dir, temporary_dir))
116+
109117
return ErrorTraces(traces)

regression/end_to_end/general001/test_general001.py

+5-2
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,12 @@
22
from regression.end_to_end.driver \
33
import run_security_analyser_pipeline
44

5+
import os
6+
57
def test_general001():
68
traces = run_security_analyser_pipeline(
7-
"general001/taint_traces_01.jar",
8-
"general001/taint_traces_01_rules.json")
9+
"taint_traces_01.jar",
10+
"taint_traces_01_rules.json",
11+
os.path.realpath(os.path.dirname(__file__)))
912
assert traces.count_traces() > 0
1013
assert traces.trace_exists("java::Main.bug:(I)V", 84)

regression/end_to_end/general002/test_general002.py

+5-2
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,11 @@
22
from regression.end_to_end.driver \
33
import run_security_analyser_pipeline
44

5+
import os
6+
57
def test_general002():
68
traces = run_security_analyser_pipeline(
7-
"general002/taint_traces_02.jar",
8-
"general002/taint_traces_02_rules.json")
9+
"taint_traces_02.jar",
10+
"taint_traces_02_rules.json",
11+
os.path.realpath(os.path.dirname(__file__)))
912
assert traces.count_traces() == 0

regression/end_to_end/general003/test_general003.py

+5-2
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,11 @@
22
from regression.end_to_end.driver \
33
import run_security_analyser_pipeline
44

5+
import os
6+
57
def test_general003():
68
traces = run_security_analyser_pipeline(
7-
"general003/taint_traces_03.jar",
8-
"general003/taint_traces_03_rules.json")
9+
"taint_traces_03.jar",
10+
"taint_traces_03_rules.json",
11+
os.path.realpath(os.path.dirname(__file__)))
912
assert traces.count_traces() == 0

regression/end_to_end/general004/test_general004.py

+5-2
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,13 @@
22
from regression.end_to_end.driver \
33
import run_security_analyser_pipeline
44

5+
import os
6+
57
def test_general004():
68
traces = run_security_analyser_pipeline(
7-
"general004/taint_traces_04.jar",
8-
"general004/taint_traces_04_rules.json")
9+
"taint_traces_04.jar",
10+
"taint_traces_04_rules.json",
11+
os.path.realpath(os.path.dirname(__file__)))
912
assert traces.count_traces() > 0
1013
assert traces.trace_exists("java::Main.baz0:()V", 19)
1114
assert traces.trace_exists("java::Main.baz1:()V", 26)

regression/end_to_end/general005/test_general005.py

+5-2
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,13 @@
22
from regression.end_to_end.driver \
33
import run_security_analyser_pipeline
44

5+
import os
6+
57
def test_general005():
68
traces = run_security_analyser_pipeline(
7-
"general005/taint_traces_05.jar",
8-
"general005/taint_traces_05_rules.json",
9+
"taint_traces_05.jar",
10+
"taint_traces_05_rules.json",
11+
os.path.realpath(os.path.dirname(__file__)),
912
["--data-flow-insensitive-instrumentation"])
1013
assert traces.count_traces() > 0
1114
assert traces.trace_exists("java::DummyAssignmentSubmissionEdit.setSubmittedText:(Ljava/lang/String;)V", 3)

regression/end_to_end/general006/test_general006.py

+5-2
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,13 @@
22
from regression.end_to_end.driver \
33
import run_security_analyser_pipeline
44

5+
import os
6+
57
def test_general006():
68
traces = run_security_analyser_pipeline(
7-
"general006/taint_traces_06.jar",
8-
"general006/taint_traces_06_rules.json",
9+
"taint_traces_06.jar",
10+
"taint_traces_06_rules.json",
11+
os.path.realpath(os.path.dirname(__file__)),
912
["--data-flow-insensitive-instrumentation"])
1013
assert traces.count_traces() > 0
1114
assert traces.trace_exists("java::taint_test.test.doGet:(Ljavax/servlet/http/HttpServletRequest;Ljavax/servlet/http/HttpServletResponse;)V", 165)

regression/end_to_end/general007/test_general007.py

+5-2
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,12 @@
22
from regression.end_to_end.driver \
33
import run_security_analyser_pipeline
44

5+
import os
6+
57
def test_general007():
68
traces = run_security_analyser_pipeline(
7-
"general007/taint_traces_07.jar",
8-
"general007/taint_traces_07_rules.json")
9+
"taint_traces_07.jar",
10+
"taint_traces_07_rules.json",
11+
os.path.realpath(os.path.dirname(__file__)))
912
assert traces.count_traces() > 0
1013
assert traces.trace_exists("java::training07.test.doGet:(Ltraining07/HttpServletRequest;Ltraining07/HttpServletResponse;)V", 109)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
{
2+
"rules":
3+
[
4+
{
5+
"comment": "Taint source",
6+
"id": "basic1_source",
7+
"class": "test",
8+
"method": "source:()[Ljava/lang/Object;",
9+
"result": {
10+
"location": "return_value",
11+
"taint": "XXX"
12+
}
13+
},
14+
{
15+
"comment": "Cleans argument",
16+
"id": "basic1_sanitiser",
17+
"class": "test",
18+
"method": "mark_clean:([Ljava/lang/Object;)V",
19+
"sanitizes": {
20+
"location": "arg0",
21+
"taint": "XXX"
22+
}
23+
},
24+
{
25+
"comment": "Taint sink",
26+
"id": "basic1_sink",
27+
"class": "test",
28+
"method": "sink:([Ljava/lang/Object;)V",
29+
"sinkTarget": {
30+
"location": "arg0",
31+
"vulnerability": "XXX"
32+
}
33+
}
34+
]
35+
}
592 Bytes
Binary file not shown.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
public class test {
2+
3+
public static void mark_clean(Object[] x) { }
4+
public static Object[] source() { return new Object[1]; }
5+
public static void sink(Object[] x) { }
6+
7+
public static void main(int unknown) {
8+
9+
Object[] tainted = source();
10+
Object[] untainted = new Object[1];
11+
12+
Object[] maybe_tainted = unknown == 100 ? tainted : untainted;
13+
14+
if(unknown == 200)
15+
mark_clean(maybe_tainted);
16+
sink(maybe_tainted);
17+
18+
}
19+
20+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
2+
from regression.end_to_end.driver \
3+
import run_security_analyser_pipeline
4+
5+
import pytest
6+
import os.path
7+
8+
def test_user_class():
9+
traces = run_security_analyser_pipeline(
10+
"test.class",
11+
"rules.json",
12+
os.path.realpath(os.path.dirname(__file__)))
13+
assert traces.count_traces() > 0
14+
assert traces.trace_exists("java::test.main:(I)V", 16)
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
{
2+
"rules":
3+
[
4+
{
5+
"comment": "Taint source",
6+
"id": "basic1_source",
7+
"class": "taint_fns",
8+
"method": "source:()I",
9+
"result": {
10+
"location": "return_value",
11+
"taint": "XXX"
12+
}
13+
},
14+
15+
{
16+
"comment": "Cleans argument",
17+
"id": "basic1_sanitiser",
18+
"class": "taint_fns",
19+
"method": "mark_clean:(I)V",
20+
"sanitizes": {
21+
"location": "arg0",
22+
"taint": "XXX"
23+
}
24+
},
25+
{
26+
"comment": "Taint sink",
27+
"id": "basic1_sink",
28+
"class": "taint_fns",
29+
"method": "sink:(I)V",
30+
"sinkTarget": {
31+
"location": "arg0",
32+
"vulnerability": "XXX"
33+
}
34+
},
35+
{
36+
"comment": "XXX taint becomes YYY",
37+
"id": "xxx_to_yyy",
38+
"class": "dependent_taint",
39+
"method": "xxx_taint_to_yyy:(I)I",
40+
"input": {
41+
"location": "arg0",
42+
"taint": "XXX"
43+
},
44+
"result": {
45+
"location": "return_value",
46+
"taint": "YYY"
47+
}
48+
},
49+
{
50+
"comment": "YYY taint becomes XXX",
51+
"id": "yyy_to_xxx",
52+
"class": "dependent_taint",
53+
"method": "yyy_taint_to_xxx:(I)I",
54+
"input": {
55+
"location": "arg0",
56+
"taint": "YYY"
57+
},
58+
"result": {
59+
"location": "return_value",
60+
"taint": "XXX"
61+
}
62+
}
63+
]
64+
}
Binary file not shown.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
<project name="Main" basedir="." default="jars">
2+
3+
<property name="root.dir" value="./"/>
4+
<property name="src.dir" value="${root.dir}"/>
5+
<property name="classes.dir" value="${root.dir}/build"/>
6+
<property name="install.dir" value="${root.dir}/dist"/>
7+
8+
<target name="jar1">
9+
<antcall target="compile" />
10+
<mkdir dir="${install.dir}"/>
11+
<jar destfile="${install.dir}/flow_in.jar" basedir="${classes.dir}" includes="flow_in.class, taint_fns.class"/>
12+
</target>
13+
14+
<target name="jar2">
15+
<antcall target="compile" />
16+
<mkdir dir="${install.dir}"/>
17+
<jar destfile="${install.dir}/flow_out.jar" basedir="${classes.dir}" includes="flow_out.class, taint_fns.class"/>
18+
</target>
19+
20+
<target name="jar3">
21+
<antcall target="compile" />
22+
<mkdir dir="${install.dir}"/>
23+
<jar destfile="${install.dir}/single_function.jar" basedir="${classes.dir}" includes="single_function.class, taint_fns.class"/>
24+
</target>
25+
26+
<target name="jar4">
27+
<antcall target="compile" />
28+
<mkdir dir="${install.dir}"/>
29+
<jar destfile="${install.dir}/stored_in_array.jar" basedir="${classes.dir}" includes="stored_in_array.class, taint_fns.class"/>
30+
</target>
31+
32+
<target name="jar5">
33+
<antcall target="compile" />
34+
<mkdir dir="${install.dir}"/>
35+
<jar destfile="${install.dir}/stored_in_fields.jar" basedir="${classes.dir}" includes="stored_in_fields.class, taint_fns.class"/>
36+
</target>
37+
38+
<target name="jar6">
39+
<antcall target="compile" />
40+
<mkdir dir="${install.dir}"/>
41+
<jar destfile="${install.dir}/dependent_taint.jar" basedir="${classes.dir}" includes="dependent_taint.class, taint_fns.class"/>
42+
</target>
43+
44+
<target name="jar7">
45+
<antcall target="compile" />
46+
<mkdir dir="${install.dir}"/>
47+
<jar destfile="${install.dir}/dependent_taint_in_summary.jar" basedir="${classes.dir}" includes="dependent_taint.class, dependent_taint_in_summary.class, taint_fns.class"/>
48+
</target>
49+
50+
<target name="jars">
51+
<antcall target="jar1"/>
52+
<antcall target="jar2"/>
53+
<antcall target="jar3"/>
54+
<antcall target="jar4"/>
55+
<antcall target="jar5"/>
56+
<antcall target="jar6"/>
57+
<antcall target="jar7"/>
58+
</target>
59+
60+
<target name="compile">
61+
<mkdir dir="${classes.dir}"/>
62+
<javac srcdir="${src.dir}" destdir="${classes.dir}" includeantruntime="false" debug="on" />
63+
</target>
64+
65+
<target name="clean">
66+
<delete dir="${classes.dir}"/>
67+
<delete dir="${install.dir}"/>
68+
</target>
69+
70+
71+
</project>
72+

0 commit comments

Comments
 (0)