Skip to content

Commit 2c018c8

Browse files
committed
Added requested regression tests.
1 parent 73e426d commit 2c018c8

File tree

7 files changed

+217
-35
lines changed

7 files changed

+217
-35
lines changed

driver/run.py

Lines changed: 23 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -294,32 +294,29 @@ def run_scan(cmdline):
294294

295295
instrumented_program_json_path = os.path.join(cmdline.results_dir, "program_slicing", "instrumented_goto_program.json")
296296

297-
if not os.path.exists(instrumented_program_json_path):
298-
print("Instrumented program .json don't exist at " + instrumented_program_json_path + ".")
299-
return
300-
301-
with open(instrumented_program_json_path, "r") as f:
302-
instrumented_program = json.load(f)
303-
# Instrumented GOTO binaries are specified relative to the results directory
304-
# (the security-analyser working directory). Rewrite them with absolute paths:
305-
instrumented_program["goto_binary_file"] = os.path.abspath(os.path.join(cmdline.results_dir, instrumented_program["goto_binary_file"]))
306-
307-
print("Starting program slicing.")
308-
prof["program_slicing"] = analyser.run_program_slicing(
309-
instrumented_program,
310-
os.path.abspath(os.path.join(cmdline.results_dir,"program_slicing")),
311-
cmdline.timeout,
312-
cmdline.verbosity,
313-
cmdline.dump_html_instrumented_goto
314-
)
315-
316-
print("Starting the search for error traces.")
317-
prof["search_for_error_traces"] = analyser.run_search_for_error_traces(
318-
os.path.abspath(os.path.join(cmdline.results_dir,"program_slicing","sliced_goto_program.json")),
319-
os.path.abspath(os.path.join(cmdline.results_dir,"search_for_error_traces")),
320-
cmdline.timeout,
321-
cmdline.verbosity
322-
)
297+
if os.path.exists(instrumented_program_json_path):
298+
with open(instrumented_program_json_path, "r") as f:
299+
instrumented_program = json.load(f)
300+
# Instrumented GOTO binaries are specified relative to the results directory
301+
# (the security-analyser working directory). Rewrite them with absolute paths:
302+
instrumented_program["goto_binary_file"] = os.path.abspath(os.path.join(cmdline.results_dir, instrumented_program["goto_binary_file"]))
303+
304+
print("Starting program slicing.")
305+
prof["program_slicing"] = analyser.run_program_slicing(
306+
instrumented_program,
307+
os.path.abspath(os.path.join(cmdline.results_dir,"program_slicing")),
308+
cmdline.timeout,
309+
cmdline.verbosity,
310+
cmdline.dump_html_instrumented_goto
311+
)
312+
313+
print("Starting the search for error traces.")
314+
prof["search_for_error_traces"] = analyser.run_search_for_error_traces(
315+
os.path.abspath(os.path.join(cmdline.results_dir,"program_slicing","sliced_goto_program.json")),
316+
os.path.abspath(os.path.join(cmdline.results_dir,"search_for_error_traces")),
317+
cmdline.timeout,
318+
cmdline.verbosity
319+
)
323320

324321
print("Building performance plots.")
325322
prof_plots = {}

regression/end_to_end/driver.py

Lines changed: 18 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,9 @@
1111

1212
class ErrorTraces:
1313

14-
def __init__(self, traces, cmdline):
14+
def __init__(self, traces, pretty_cmdline, cmdline):
1515
self.traces = traces
16+
self.pretty_cmdline = pretty_cmdline
1617
self.cmdline = cmdline
1718

1819
def count_traces(self):
@@ -64,12 +65,21 @@ def trace_goes_through(
6465
pass
6566
return False
6667

68+
def get_cmdline(self):
69+
return self.cmdline
70+
71+
def get_results_dir(self):
72+
return self.cmdline[self.cmdline.index("-R") + 1]
73+
74+
def get_temp_dir(self):
75+
return self.cmdline[self.cmdline.index("-T") + 1]
76+
6777
def __enter__(self):
6878
return self
6979

7080
def __exit__(self, exc_type, exc_value, traceback):
7181
if exc_value is not None:
72-
print("Failure may relate to command: ", self.cmdline, file=sys.stderr)
82+
print("Failure may relate to command: ", self.pretty_cmdline, file=sys.stderr)
7383

7484

7585
def pretty_print_commandline(cmdline):
@@ -109,7 +119,8 @@ def run_security_analyser_pipeline(
109119
base_path,
110120
entry_point,
111121
load_strategy=LoadStrategy.conventional_lazy_loading,
112-
extra_args=None):
122+
extra_args=None,
123+
keep_results=False):
113124

114125
if extra_args is None:
115126
extra_args = []
@@ -148,9 +159,9 @@ def run_security_analyser_pipeline(
148159
cmdline.append("--verify-csvsa-sparse-domains")
149160

150161
with utils.working_dir(analyzer_home), \
151-
utils.temp_dir_deleter(results_dir), \
152-
utils.temp_dir_deleter(temporary_dir), \
153-
utils.temp_dir_deleter(common_dir):
162+
utils.temp_dir_deleter(results_dir, keep_results), \
163+
utils.temp_dir_deleter(temporary_dir, keep_results), \
164+
utils.temp_dir_deleter(common_dir, keep_results):
154165

155166
run_security_driver_script(cmdline)
156167

@@ -179,4 +190,4 @@ def run_security_analyser_pipeline(
179190
print("Test \"%s\" kept results (%s) and temporary directory (%s)" %
180191
(pretty_cmdline, results_dir, temporary_dir))
181192

182-
return ErrorTraces(traces, pretty_cmdline)
193+
return ErrorTraces(traces, pretty_cmdline, cmdline)
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
<project name="Main" basedir="." default="compile">
2+
3+
<property name="root.dir" value="./"/>
4+
<property name="src.dir" value="${root.dir}/src"/>
5+
<property name="classes.dir" value="${root.dir}/build"/>
6+
7+
<target name="compile">
8+
<antcall target="clean" />
9+
<mkdir dir="${classes.dir}"/>
10+
<javac srcdir="${src.dir}" destdir="${classes.dir}" includeantruntime="false" debug="on" />
11+
</target>
12+
13+
<target name="clean">
14+
<delete dir="${classes.dir}"/>
15+
</target>
16+
17+
</project>
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
{
2+
"rules":
3+
[
4+
{
5+
"comment": "Obtaining a tainted string.",
6+
"class": "Main",
7+
"method": "source:()Ljava/lang/String;",
8+
"result": {
9+
"location": "return_value",
10+
"taint": "Tainted string"
11+
}
12+
},
13+
{
14+
"comment": "Returning a sanitized string.",
15+
"class": "Main",
16+
"method": "sanitize:(Ljava/lang/String;)Ljava/lang/String;",
17+
"sanitizes": {
18+
"location": "returns",
19+
"taint": "Clean string"
20+
}
21+
},
22+
{
23+
"comment": "Writing a potentially tainted data into the sink",
24+
"class": "Main",
25+
"method": "sink:(Ljava/lang/String;)V",
26+
"sinkTarget": {
27+
"location": "arg0",
28+
"vulnerability": "Tainted string"
29+
}
30+
}
31+
]
32+
}
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
public class Main {
2+
3+
public static String source() {
4+
return "Tainted string";
5+
}
6+
7+
public static void sink(String s) {
8+
}
9+
10+
public static String sanitize(String s) {
11+
return "sanitised string";
12+
}
13+
14+
// Test cases
15+
16+
public static void catch_impossible_taint_flow_01() {
17+
String s = "no taint";
18+
sink(s);
19+
}
20+
21+
public static void catch_impossible_taint_flow_02() {
22+
String s = source();
23+
s = sanitize(s);
24+
sink(s);
25+
}
26+
27+
public static void miss_impossible_taint_flow_01() {
28+
String s = source();
29+
int i = 0;
30+
if (i == 1)
31+
sink(s);
32+
}
33+
34+
public static void miss_impossible_taint_flow_02() {
35+
String s = source();
36+
int i = 20;
37+
if (i == 20)
38+
s = sanitize(s);
39+
sink(s);
40+
}
41+
}
42+
Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
import fasteners
2+
import os
3+
import subprocess
4+
import pytest
5+
6+
from regression.end_to_end.driver import run_security_analyser_pipeline
7+
import regression.utils as utils
8+
9+
10+
@fasteners.interprocess_locked(os.path.join(os.path.dirname(__file__), ".build_lock"))
11+
def test_early_check_catch_impossible_taint_flow_01(load_strategy):
12+
with utils.working_dir(os.path.abspath(os.path.dirname(__file__))):
13+
subprocess.call(["ant"])
14+
with run_security_analyser_pipeline(
15+
"build",
16+
"rules.json",
17+
os.path.realpath(os.path.dirname(__file__)),
18+
"Main.catch_impossible_taint_flow_01",
19+
load_strategy,
20+
keep_results=True) as traces:
21+
assert traces.count_traces() == 0
22+
index_file = os.path.join(traces.get_results_dir(), "Main.catch_impossible_taint_flow_01/index.html")
23+
assert os.path.exists(index_file)
24+
with open(index_file, "r") as ifile:
25+
content = ifile.read()
26+
assert "The program is safe. No tainted data may reach any sink." in content
27+
28+
29+
@fasteners.interprocess_locked(os.path.join(os.path.dirname(__file__), ".build_lock"))
30+
def test_early_check_catch_impossible_taint_flow_02(load_strategy):
31+
with utils.working_dir(os.path.abspath(os.path.dirname(__file__))):
32+
subprocess.call(["ant"])
33+
with run_security_analyser_pipeline(
34+
"build",
35+
"rules.json",
36+
os.path.realpath(os.path.dirname(__file__)),
37+
"Main.catch_impossible_taint_flow_02",
38+
load_strategy,
39+
keep_results=True) as traces:
40+
assert traces.count_traces() == 0
41+
index_file = os.path.join(traces.get_results_dir(), "Main.catch_impossible_taint_flow_02/index.html")
42+
assert os.path.exists(index_file)
43+
with open(index_file, "r") as ifile:
44+
content = ifile.read()
45+
assert "The program is safe. No tainted data may reach any sink." in content
46+
47+
48+
@fasteners.interprocess_locked(os.path.join(os.path.dirname(__file__), ".build_lock"))
49+
def test_early_check_miss_impossible_taint_flow_01(load_strategy):
50+
with utils.working_dir(os.path.abspath(os.path.dirname(__file__))):
51+
subprocess.call(["ant"])
52+
with run_security_analyser_pipeline(
53+
"build",
54+
"rules.json",
55+
os.path.realpath(os.path.dirname(__file__)),
56+
"Main.miss_impossible_taint_flow_01",
57+
load_strategy,
58+
keep_results=True) as traces:
59+
assert traces.count_traces() == 0
60+
index_file = os.path.join(traces.get_results_dir(), "Main.miss_impossible_taint_flow_01/index.html")
61+
assert os.path.exists(index_file)
62+
with open(index_file, "r") as ifile:
63+
content = ifile.read()
64+
assert "The program is safe. No tainted data may reach any sink." not in content
65+
66+
67+
@fasteners.interprocess_locked(os.path.join(os.path.dirname(__file__), ".build_lock"))
68+
def test_early_check_miss_impossible_taint_flow_02(load_strategy):
69+
with utils.working_dir(os.path.abspath(os.path.dirname(__file__))):
70+
subprocess.call(["ant"])
71+
with run_security_analyser_pipeline(
72+
"build",
73+
"rules.json",
74+
os.path.realpath(os.path.dirname(__file__)),
75+
"Main.miss_impossible_taint_flow_02",
76+
load_strategy,
77+
keep_results=True) as traces:
78+
assert traces.count_traces() == 0
79+
index_file = os.path.join(traces.get_results_dir(), "Main.miss_impossible_taint_flow_02/index.html")
80+
assert os.path.exists(index_file)
81+
with open(index_file, "r") as ifile:
82+
content = ifile.read()
83+
assert "The program is safe. No tainted data may reach any sink." not in content

regression/utils.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,9 @@ def working_dir(new_dir):
1414

1515

1616
@contextlib.contextmanager
17-
def temp_dir_deleter(dirname):
17+
def temp_dir_deleter(dirname, explicit_keep=False):
1818
yield
19-
if "SECURITY_ANALYSER_END_TO_END_TESTS_KEEP_RESULTS" in os.environ:
19+
if explicit_keep is True or "SECURITY_ANALYSER_END_TO_END_TESTS_KEEP_RESULTS" in os.environ:
2020
return
2121
try:
2222
shutil.rmtree(dirname)

0 commit comments

Comments
 (0)