Skip to content

Commit bd5441f

Browse files
authored
Merge pull request diffblue#333 from diffblue/bugfix/more_input_params_per_rule
SEC-222: Extended taint rules so that there can be more than one rule for one function.
2 parents ed55ad8 + 5fc38a2 commit bd5441f

File tree

9 files changed

+380
-373
lines changed

9 files changed

+380
-373
lines changed

regression/end_to_end/multitaint/rules.json

+14-1
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
}
1313
},
1414
{
15-
"comment": "Put tainted name to cookie",
15+
"comment": "Put tainted name to cookie via the first parameter.",
1616
"class": "Cookie",
1717
"method": "<init>:(Ljava/lang/Object;Ljava/lang/Object;)V",
1818
"input": {
@@ -24,6 +24,19 @@
2424
"taint": "Tainted cookie"
2525
}
2626
},
27+
{
28+
"comment": "Put tainted name to cookie via the second parameter.",
29+
"class": "Cookie",
30+
"method": "<init>:(Ljava/lang/Object;Ljava/lang/Object;)V",
31+
"input": {
32+
"location": "arg2",
33+
"taint": "Tainted data"
34+
},
35+
"result": {
36+
"location": "this",
37+
"taint": "Tainted cookie"
38+
}
39+
},
2740
{
2841
"comment": "Writing potentially tainted data to a sink.",
2942
"class": "Main",

regression/end_to_end/multitaint/src/Main.java

+9
Original file line numberDiff line numberDiff line change
@@ -21,4 +21,13 @@ public static void taint_via_value() {
2121
Cookie c = new Cookie(name, value);
2222
sink(c);
2323
}
24+
25+
public static void taint_via_both() {
26+
Object name = new Object();
27+
Object value = new Object();
28+
makeTainted(name);
29+
makeTainted(value);
30+
Cookie c = new Cookie(name, value);
31+
sink(c);
32+
}
2433
}
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,17 @@
11
import regression.end_to_end.driver as pipeline_executor
22
import os
33
import subprocess
4-
import pytest
54
import regression.utils as utils
65

76

8-
@pytest.mark.xfail(strict=True)
97
def test_multitaint():
10-
"""
11-
The test case shows a weakness in our rules system. The test defines
12-
a class Cookie, whose constructor takes 2 arguments, and each of them
13-
can bring tainted data to the created instance. However, our rule
14-
allows only for 1 tainted input.
15-
"""
168
with utils.working_dir(os.path.abspath(os.path.dirname(__file__))):
179
subprocess.call("ant")
1810
traces = pipeline_executor.run_security_analyser_pipeline(
1911
os.path.join("dist", "multitaint.jar"),
2012
"rules.json",
2113
os.path.realpath(os.path.dirname(__file__)))
22-
assert traces.count_traces() == 2
23-
assert traces.trace_exists("java::Main.taint_via_name:()V", 13)
24-
assert traces.trace_exists("java::Main.taint_via_value:()V", 20)
14+
assert traces.count_traces() == 3
15+
assert traces.trace_exists("java::Main.taint_via_name:()V", 14)
16+
assert traces.trace_exists("java::Main.taint_via_value:()V", 22)
17+
assert traces.trace_exists("java::Main.taint_via_both:()V", 31)

src/taint-analysis/taint_rules.h

+30-21
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
#include <util/message.h>
1515
#include <map>
1616
#include <string>
17+
#include <vector>
1718
#include <memory>
1819
#include <boost/optional.hpp>
1920

@@ -196,9 +197,9 @@ class taint_sink_rulet : public taint_rulet
196197
class taint_rulest
197198
{
198199
private:
199-
std::map<irep_idt, taint_propagation_rulet> propagation_rules;
200-
std::map<irep_idt, taint_sanitizer_rulet> sanitizer_rules;
201-
std::map<irep_idt, taint_sink_rulet> sink_rules;
200+
std::multimap<irep_idt, taint_propagation_rulet> propagation_rules;
201+
std::multimap<irep_idt, taint_sanitizer_rulet> sanitizer_rules;
202+
std::multimap<irep_idt, taint_sink_rulet> sink_rules;
202203

203204
taint_rulest() { }
204205

@@ -233,41 +234,49 @@ class taint_rulest
233234
|| sink_rules.find(fn_name) != sink_rules.end();
234235
}
235236

236-
boost::optional<const taint_propagation_rulet &> find_propagation_rule(
237-
const irep_idt &fn_name) const
237+
std::vector<std::reference_wrapper<const taint_propagation_rulet>>
238+
find_propagation_rule(const irep_idt &fn_name) const
238239
{
239240
// We currently match directly on the name
240241
// TODO: Search for any methods derived on base classes of the class name
241242
// used in the call
242-
// class_hierarchyt::idst parents = class_hierarchy.get_parents_trans(class_id);
243-
auto it = propagation_rules.find(fn_name);
244-
if(it == propagation_rules.end())
245-
return boost::none;
246-
return it->second;
243+
std::vector<std::reference_wrapper<const taint_propagation_rulet>>
244+
matching_rules;
245+
auto range = propagation_rules.equal_range(fn_name);
246+
for(auto it = range.first; it != range.second; ++it)
247+
matching_rules.push_back(
248+
std::reference_wrapper<const taint_propagation_rulet>(it->second));
249+
return matching_rules;
247250
}
248251

249-
boost::optional<const taint_sanitizer_rulet &> find_sanitizer_rule(const irep_idt &fn_name) const
252+
std::vector<std::reference_wrapper<const taint_sanitizer_rulet>>
253+
find_sanitizer_rule(const irep_idt &fn_name) const
250254
{
251255
// We currently match directly on the name
252256
// TODO: Search for any methods derived on base classes of the class name
253257
// used in the call
254-
// class_hierarchyt::idst parents = class_hierarchy.get_parents_trans(class_id);
255-
auto it = sanitizer_rules.find(fn_name);
256-
if(it == sanitizer_rules.end())
257-
return boost::none;
258-
return it->second;
258+
std::vector<std::reference_wrapper<const taint_sanitizer_rulet>>
259+
matching_rules;
260+
auto range = sanitizer_rules.equal_range(fn_name);
261+
for(auto it = range.first; it != range.second; ++it)
262+
matching_rules.push_back(
263+
std::reference_wrapper<const taint_sanitizer_rulet>(it->second));
264+
return matching_rules;
259265
}
260266

261-
boost::optional<const taint_sink_rulet &> find_sink_rule(const irep_idt &fn_name) const
267+
std::vector<std::reference_wrapper<const taint_sink_rulet>>
268+
find_sink_rule(const irep_idt &fn_name) const
262269
{
263270
// We currently match directly on the name
264271
// TODO: Search for any methods derived on base classes of the class name
265272
// used in the call
266273
// class_hierarchyt::idst parents = class_hierarchy.get_parents_trans(class_id);
267-
auto it = sink_rules.find(fn_name);
268-
if(it == sink_rules.end())
269-
return boost::none;
270-
return it->second;
274+
std::vector<std::reference_wrapper<const taint_sink_rulet>> matching_rules;
275+
auto range = sink_rules.equal_range(fn_name);
276+
for(auto it = range.first; it != range.second; ++it)
277+
matching_rules.push_back(
278+
std::reference_wrapper<const taint_sink_rulet>(it->second));
279+
return matching_rules;
271280
}
272281

273282

0 commit comments

Comments
 (0)