Skip to content

Commit 184c8c0

Browse files
authored
Merge pull request diffblue#279 from diffblue/marek/may_alias_to_vsa
SEC-144: Introducing function 'get_may_alias_values'.
2 parents 40c21ff + 1dc8853 commit 184c8c0

File tree

10 files changed

+313
-2
lines changed

10 files changed

+313
-2
lines changed

cbmc/src/pointer-analysis/value_set.cpp

+1
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010

1111
#include <cassert>
1212
#include <ostream>
13+
#include <algorithm>
1314

1415
#include <util/symbol_table.h>
1516
#include <util/simplify_expr.h>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
<project name="interprocedural01" basedir="." default="jar">
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+
<property name="install.dir" value="${root.dir}/dist"/>
7+
8+
<target name="jar">
9+
<antcall target="compile" />
10+
<mkdir dir="${install.dir}"/>
11+
<jar destfile="${install.dir}/interprocedural01.jar" basedir="${classes.dir}" />
12+
</target>
13+
14+
<target name="compile">
15+
<antcall target="clean" />
16+
<mkdir dir="${classes.dir}"/>
17+
<javac srcdir="${src.dir}" destdir="${classes.dir}" includeantruntime="false" debug="on">
18+
</javac>
19+
</target>
20+
21+
<target name="clean">
22+
<delete dir="${classes.dir}"/>
23+
<delete dir="${install.dir}"/>
24+
</target>
25+
26+
27+
</project>
28+
29+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
{
2+
"namespace": "com.diffblue.security",
3+
"rules":
4+
[
5+
{
6+
"comment": "Obtaining a stream with potentially tainted data.",
7+
"class": "Main",
8+
"method": "getInStream:()LIStream;",
9+
"result": {
10+
"location": "returns",
11+
"taint": "Tainted stream"
12+
}
13+
},
14+
{
15+
"comment": "Obtaining a vulnerable stream",
16+
"class": "Main",
17+
"method": "getOutStream:()LOStream;",
18+
"result": {
19+
"location": "returns",
20+
"vulnerability": "Vulnerable stream"
21+
}
22+
},
23+
{
24+
"comment": "Read from tainted stream gives tainted string",
25+
"class": "IStream",
26+
"method": "read:(LData;)V",
27+
"input": {
28+
"location": "this",
29+
"taint": "Tainted stream"
30+
},
31+
"result": {
32+
"location": "arg1",
33+
"taint": "Tainted data"
34+
}
35+
},
36+
{
37+
"comment": "Writing potentially tainted data to a vulnerable stream.",
38+
"class": "OStream",
39+
"method": "write:(LData;)V",
40+
"input": {
41+
"location": "arg1",
42+
"taint": "Tainted data"
43+
},
44+
"sinkTarget": {
45+
"location": "this",
46+
"vulnerability": "Vulnerable stream"
47+
},
48+
"message": "Writing potentially tainted data to a vulnerable stream."
49+
},
50+
{
51+
"comment": "Sanitise tainted data.",
52+
"class": "Main",
53+
"method": "sanitise:(LData;)V",
54+
"sanitizes": {
55+
"location": "arg0",
56+
"taint": "Tainted data"
57+
}
58+
}
59+
]
60+
}
61+
62+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
class Data {
2+
}
3+
4+
class IStream {
5+
public void read(Data d) {
6+
}
7+
}
8+
9+
class OStream {
10+
public void write(Data d) {
11+
}
12+
}
13+
14+
public class Main {
15+
16+
public static IStream getInStream() {
17+
return new IStream();
18+
}
19+
20+
public static OStream getOutStream() {
21+
return new OStream();
22+
}
23+
24+
public static Data getData1() {
25+
return new Data();
26+
}
27+
28+
public static Data getData2() {
29+
return new Data();
30+
}
31+
32+
private static void getBytes(Data data, IStream in) {
33+
Data alias = data;
34+
in.read(alias);
35+
}
36+
37+
private static void postBytes(Data data, OStream out) {
38+
out.write(data);
39+
}
40+
41+
public static void sanitise(Data d) {
42+
}
43+
44+
public static void main() {
45+
IStream in = getInStream();
46+
OStream out = getOutStream();
47+
Data d = getData1();
48+
Data e = getData2();
49+
Data q = d;
50+
getBytes(d, in);
51+
getBytes(e, in);
52+
sanitise(q);
53+
postBytes(d, out);
54+
postBytes(q, out);
55+
postBytes(e, out);
56+
}
57+
58+
}
59+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
import regression.end_to_end.driver as pipeline_executor
2+
import os
3+
import subprocess
4+
5+
6+
def test_interprocedural01():
7+
with pipeline_executor.working_dir(os.path.abspath(os.path.dirname(__file__))):
8+
subprocess.call("ant")
9+
traces = pipeline_executor.run_security_analyser_pipeline(
10+
os.path.join("dist", "interprocedural01.jar"),
11+
"rules.json",
12+
os.path.realpath(os.path.dirname(__file__)))
13+
assert traces.count_traces() == 1
14+
assert traces.trace_exists("java::Main.postBytes:(LData;LOStream;)V", 38)
15+
assert traces.trace_goes_through(
16+
"jbmc",
17+
-2,
18+
"java::Main.main:()V",
19+
55,
20+
"java::Main.postBytes:(LData;LOStream;)V",
21+
38
22+
)
23+

src/pointer-analysis/external_value_set_expr.h

+6
Original file line numberDiff line numberDiff line change
@@ -287,4 +287,10 @@ inline const external_value_set_exprt &to_external_value_set(const exprt &e)
287287
return static_cast<const external_value_set_exprt &>(e);
288288
}
289289

290+
template<>
291+
inline bool can_cast_expr<external_value_set_exprt >(const exprt &base)
292+
{
293+
return base.id()==ID_external_value_set;
294+
}
295+
290296
#endif

src/pointer-analysis/local_value_set.cpp

+62
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
#include <util/simplify_expr_class.h>
99
#include <util/infix.h>
1010
#include <util/suffix.h>
11+
#include <util/c_types.h>
1112

1213
#include <pointer-analysis/dynamic_object_name.h>
1314

@@ -76,6 +77,67 @@ void local_value_sett::get_value_set(
7677
baset::get_value_set(tmp, dest, ns, true);
7778
}
7879

80+
/// Builds a version of expr suitable for alias-comparison
81+
/// \param expr: The expression to be converted to the alias-uniform structure
82+
/// \return expr without information which is irrelevant to alias-comparison
83+
static exprt get_uniform_expr(const exprt &expr)
84+
{
85+
if(const auto desc_ptr=expr_try_dynamic_cast<object_descriptor_exprt>(expr))
86+
{
87+
object_descriptor_exprt ob;
88+
ob.object() = get_uniform_expr(desc_ptr->object());
89+
ob.offset() = desc_ptr->offset();
90+
return ob;
91+
}
92+
if(can_cast_expr<external_value_set_exprt>(expr))
93+
{
94+
exprt copy = expr;
95+
copy.set(ID_is_initializer, ID_0);
96+
return copy;
97+
}
98+
return expr;
99+
}
100+
101+
/// Reconstructs a type of a pointer to the object expr
102+
/// \param expr: An object in a points-to set we make an alias type for
103+
/// \return A type of a pointer to the object expr
104+
static typet get_alias_type(const exprt &expr)
105+
{
106+
if(expr.id()==ID_object_descriptor)
107+
{
108+
object_descriptor_exprt ob_expr=to_object_descriptor_expr(expr);
109+
if(ob_expr.offset().id()==ID_invalid || ob_expr.offset().id()==ID_unknown)
110+
return pointer_type(ob_expr.object().type());
111+
}
112+
return pointer_type(expr.type());
113+
}
114+
115+
void local_value_sett::get_may_alias_set(
116+
const exprt &expr,
117+
value_setst::valuest &dest,
118+
const namespacet &ns) const
119+
{
120+
object_mapt pointed_objects;
121+
get_value_set(expr, pointed_objects, ns, false);
122+
std::vector<exprt> uniform_pointed_objects;
123+
for(const auto &num_obj : pointed_objects.read())
124+
uniform_pointed_objects.push_back(get_uniform_expr(to_expr(num_obj)));
125+
126+
for(const auto &name_entry : values)
127+
for(const auto &enum_eobj : name_entry.second.object_map.read())
128+
{
129+
if(std::find(uniform_pointed_objects.cbegin(),
130+
uniform_pointed_objects.cend(),
131+
get_uniform_expr(to_expr(enum_eobj)))!=
132+
uniform_pointed_objects.cend())
133+
{
134+
dest.push_back(symbol_exprt(
135+
name_entry.second.identifier,
136+
get_alias_type(to_expr(enum_eobj))));
137+
}
138+
}
139+
}
140+
79141
/// Value-set analysis accrues a `suffix` as it walks down an expression tree--
80142
/// for example, it transforms a `get_value_set_rec(x.y.z)` into
81143
/// `get_value_set_rec(x, suffix = "y.z")`. This function recovers the type

src/pointer-analysis/local_value_set.h

+9
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,15 @@ class local_value_sett:public value_sett
5858
const namespacet &ns,
5959
bool is_simplified) const override;
6060

61+
/// Computes all pointers which MAY point to objects pointed to by expr
62+
/// \param expr: Identifies a points-to set for which to compute aliases
63+
/// \param dest: Output container for pointers to objects pointed to by expr
64+
/// \param ns: A reference to a symbol table
65+
void get_may_alias_set(
66+
const exprt &expr,
67+
value_setst::valuest &dest,
68+
const namespacet &ns) const;
69+
6170
/// Overrides `value_sett::assign` to (a) tag all external-value-set
6271
/// expressions from `rhs` indicating they have been assigned, and (b)
6372
/// apply side-effects of this assignment to the whole domain, which currently

src/pointer-analysis/local_value_set_analysis.h

+16-1
Original file line numberDiff line numberDiff line change
@@ -186,7 +186,22 @@ class local_value_set_analysist
186186
/// Counts summary assignment steps performed in `transform_function_stub`
187187
size_t nstub_assignments;
188188

189-
protected:
189+
/// Fills in dest with all pointers to any object pointed to be expr
190+
/// \param l: A program location w.r.t which the operation will be performed
191+
/// \param expr: Identifies a points-to set whose aliases we will compute
192+
/// \param dest: Output container for aliases
193+
void get_may_alias_values(
194+
locationt l,
195+
const exprt &expr,
196+
value_setst::valuest &dest)
197+
{
198+
((const local_value_sett&)(*this)[l].value_set).get_may_alias_set(
199+
expr,
200+
dest,
201+
baset::ns);
202+
}
203+
204+
protected:
190205
/// Type of function under analysis
191206
const code_typet& function_type;
192207
/// Name of function under analysis

src/taint-analysis/taint_summary.cpp

+46-1
Original file line numberDiff line numberDiff line change
@@ -237,6 +237,27 @@ static void collect_lvsa_access_paths(
237237
result.insert(taint_object_numbering.number(object));
238238
}
239239

240+
/// Invokes LVSA for the aliases and converts them to numbers
241+
/// \param query_in: Identifies a points to set (e.g. a pointer to some object)
242+
/// \param ns: A symbol table (for internal use in LVSA)
243+
/// \param lvsa: The LVSA analysis
244+
/// \param inst_it: A program location w.r.t which the operation will be performed
245+
/// \param taint_object_numbering: For conversion of aliases to numbers
246+
/// \param result: The output container for numbers of computed aliases
247+
static void collect_lvsa_alias_access_paths(
248+
exprt const& query_in,
249+
namespacet const& ns,
250+
local_value_set_analysist& lvsa,
251+
instruction_iteratort const& inst_it,
252+
object_numberingt& taint_object_numbering,
253+
lvalue_numbers_sett& result)
254+
{
255+
value_setst::valuest dest;
256+
lvsa.get_may_alias_values(inst_it, query_in, dest);
257+
for(const exprt &object : dest)
258+
result.insert(taint_object_numbering.number(object));
259+
}
260+
240261
static void collect_lvsa_access_paths(
241262
exprt const& querye_in,
242263
namespacet const& ns,
@@ -555,9 +576,25 @@ void taint_algorithm_computing_summary_of_functiont::
555576
lvsa,
556577
Iit,
557578
*numbering);
579+
collect_lvsa_alias_access_paths(
580+
fn_call.arguments().at(param_idx),
581+
program->get_namespace(),
582+
lvsa,
583+
Iit,
584+
*numbering,
585+
argument_lvalues);
558586
}
559587
else
588+
{
560589
argument_lvalues.insert(lvalue_taint.first);
590+
collect_lvsa_alias_access_paths(
591+
lvalue,
592+
program->get_namespace(),
593+
lvsa,
594+
Iit,
595+
*numbering,
596+
argument_lvalues);
597+
}
561598

562599
const object_numbers_by_field_per_functiont &object_numbers_by_field =
563600
numbering_map->get_object_numbers_by_field();
@@ -920,12 +957,20 @@ void taint_algorithm_computing_summary_of_functiont::
920957
*numbering,
921958
numbers_of_aliases,
922959
singular);
960+
collect_lvsa_alias_access_paths(
961+
lvalue,
962+
program->get_namespace(),
963+
lvsa,
964+
Iit,
965+
*numbering,
966+
numbers_of_aliases);
923967

924968
if(singular && is_allowed_pure_assignment)
925969
{
926970
// Singular implies that lhs has exactly one element,
927971
// so we can access it directly
928-
assign(result, *numbers_of_aliases.begin(), taint_from_rule);
972+
for(const auto num : numbers_of_aliases)
973+
assign(result, num, taint_from_rule);
929974
}
930975
else
931976
{

0 commit comments

Comments
 (0)