diff --git a/regression/end_to_end/driver.py b/regression/end_to_end/driver.py index 302dad19fd7..69fc7d61e32 100644 --- a/regression/end_to_end/driver.py +++ b/regression/end_to_end/driver.py @@ -28,6 +28,14 @@ def trace_exists(self, function, line_no): return True return False + def trace_of_length_exists(self, function, line_no, tool_name, trace_length): + for trace in self.traces: + if trace["function"] == function and trace["line"] == line_no: + for error_trace in trace["error_traces"][tool_name]: + if len(error_trace) == trace_length: + return True + return False + def trace_goes_through( self, tool_name, diff --git a/regression/end_to_end/taint_two_tokens/build.xml b/regression/end_to_end/taint_two_tokens/build.xml new file mode 100644 index 00000000000..4c037b99784 --- /dev/null +++ b/regression/end_to_end/taint_two_tokens/build.xml @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + + + + diff --git a/regression/end_to_end/taint_two_tokens/rules.json b/regression/end_to_end/taint_two_tokens/rules.json new file mode 100644 index 00000000000..7a7942e01e6 --- /dev/null +++ b/regression/end_to_end/taint_two_tokens/rules.json @@ -0,0 +1,75 @@ +{ + "namespace": "com.diffblue.security", + "rules": + [ + { + "comment": "Streams returned by getInputStream on ServletRequest are tainted", + "class": "two.tokens.HttpServletRequest", + "method": "getInputStream:()Ltwo/tokens/ServletInputStream;", + "result": { + "location": "returns", + "taint": "Tainted stream" + } + }, + { + "comment": "Read from tainted stream gives tainted string and tainted bytes.", + "class": "two.tokens.ServletInputStream", + "method": "read:([B)Ltwo/tokens/String;", + "input": { + "location": "this", + "taint": "Tainted stream" + }, + "result": { + "location": "arg1", + "namespace": "com.diffblue.security.specialized", + "taint": "Tainted byte array" + } + }, + { + "comment": "Read from tainted stream gives tainted string and tainted bytes.", + "class": "two.tokens.ServletInputStream", + "method": "read:([B)Ltwo/tokens/String;", + "input": { + "location": "this", + "taint": "Tainted stream" + }, + "result": { + "location": "returns", + "namespace": "com.diffblue.security.specialized", + "taint": "Tainted string" + } + }, + { + "comment": "Writing potentially tainted bytes (the whole array) to a vulnerable stream is a sink.", + "class": "two.tokens.HttpServletResponse", + "method": "write:([BLtwo/tokens/String;)V", + "input": { + "location": "arg1", + "namespace": "com.diffblue.security.specialized", + "taint": "Tainted byte array" + }, + "sinkTarget": { + "location": "this", + "vulnerability": "Vulnerable stream" + }, + "message": "Unescaped HTML potentially written back to browser" + }, + { + "comment": "Writing potentially tainted string to a vulnerable stream is a sink.", + "class": "two.tokens.HttpServletResponse", + "method": "write:([BLtwo/tokens/String;)V", + "input": { + "location": "arg2", + "namespace": "com.diffblue.security.specialized", + "taint": "Tainted string" + }, + "sinkTarget": { + "location": "this", + "vulnerability": "Vulnerable stream" + }, + "message": "Unescaped HTML potentially written back to browser" + } + ] +} + + diff --git a/regression/end_to_end/taint_two_tokens/src/Main.java b/regression/end_to_end/taint_two_tokens/src/Main.java new file mode 100644 index 00000000000..9fde4bdc0d0 --- /dev/null +++ b/regression/end_to_end/taint_two_tokens/src/Main.java @@ -0,0 +1,32 @@ +package two.tokens; + +class String { +} + +class ServletInputStream { + String read(byte[] data) { + return new String(); + } +} + +class HttpServletRequest { + public ServletInputStream getInputStream() { + return new ServletInputStream(); + } +} + +class HttpServletResponse { + public void write(byte[] data, String s) { + } +} + +public class Main { + + public void doGet(HttpServletRequest req, HttpServletResponse res) { + byte[] b = new byte[10]; + String s = req.getInputStream().read(b); + res.write(b,s); + } + +} + diff --git a/regression/end_to_end/taint_two_tokens/test_taint_two_tokens.py b/regression/end_to_end/taint_two_tokens/test_taint_two_tokens.py new file mode 100644 index 00000000000..5a3e42ffc7f --- /dev/null +++ b/regression/end_to_end/taint_two_tokens/test_taint_two_tokens.py @@ -0,0 +1,29 @@ +import os +import subprocess + +from regression.end_to_end.driver import run_security_analyser_pipeline +import regression.utils as utils + + +def test_taint_two_tokens(): + + with utils.working_dir(os.path.abspath(os.path.dirname(__file__))): + subprocess.call("ant") + with run_security_analyser_pipeline( + "build", + "rules.json", + os.path.realpath(os.path.dirname(__file__))) as traces: + + # There are two traces here but they are both linked to the same line number even if the goto assert operation + # is different. Right now we can't tell the difference between the two, except of their length. + assert traces.count_traces() == 2 + assert traces.trace_of_length_exists( + "java::two.tokens.Main.doGet:(Ltwo/tokens/HttpServletRequest;Ltwo/tokens/HttpServletResponse;)V", + 28, + "jbmc", + 60) + assert traces.trace_of_length_exists( + "java::two.tokens.Main.doGet:(Ltwo/tokens/HttpServletRequest;Ltwo/tokens/HttpServletResponse;)V", + 28, + "jbmc", + 61)