Skip to content

Commit 6fc8f97

Browse files
authored
Merge pull request diffblue#330 from diffblue/bugfix/downcast_issue_solved_by_moving_shadow_vars_to_Object
SEC-218: Bugfix: Downcast issue resolved by moving shadow vars to java.lang.Object.
2 parents 7610b3f + ac743e4 commit 6fc8f97

File tree

4 files changed

+75
-73
lines changed

4 files changed

+75
-73
lines changed

regression/end_to_end/taint_over_downcast/test_taint_over_downcast.py

Lines changed: 0 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,10 @@
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_taint_over_downcast():
10-
"""
11-
Wrong handling of down-casting. Here are related lines of the goto program:
12-
new_tmp0 = ALLOCATE(struct Derived, 5ul, false);
13-
a = (struct Base *)&new_tmp0->@Base;
14-
a->@__CPROVER_com_diffblue_security_Tainted_data = true;
15-
IF !((struct Derived *)a)->@__CPROVER_com_diffblue_security_Tainted_data THEN GOTO 2
16-
ASSERT false
17-
2: ...
18-
So, the access path to @__CPROVER_com_diffblue_security_Tainted in the IF
19-
statement should rather be
20-
(&(((struct Derived *)a)->@Base))->@__CPROVER_com_diffblue_security_Tainted
21-
"""
228
with utils.working_dir(os.path.abspath(os.path.dirname(__file__))):
239
subprocess.call("ant")
2410
traces = pipeline_executor.run_security_analyser_pipeline(

regression/end_to_end/tainted-user-class/test_tainted_user_class.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
import os.path
66
import pytest
77

8+
@pytest.mark.user_class
89
def test_user_class():
910
traces = run_security_analyser_pipeline(
1011
"test.class",
@@ -13,7 +14,7 @@ def test_user_class():
1314
assert traces.count_traces() > 0
1415
assert traces.trace_exists("java::test.main:(I)V", 16)
1516

16-
@pytest.mark.xfail(strict=True)
17+
@pytest.mark.user_subclass
1718
def test_user_subclass():
1819
"""
1920
The issue is the instrumentation; Although the taint var is here
@@ -22,7 +23,7 @@ def test_user_subclass():
2223
IF !((struct test *)anonlocal::3a)->@__CPROVER_XXX THEN GOTO 5
2324
"""
2425
traces = run_security_analyser_pipeline(
25-
"subclass.class",
26+
"./",
2627
"subclass_rules.json",
2728
os.path.realpath(os.path.dirname(__file__)))
2829
assert traces.count_traces() == 1

src/taint-slicer/instrumentation_props.cpp

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -55,9 +55,7 @@ bool is_java_array_type_name(const std::string &datatype)
5555
bool does_instrumentation_of_type_require_subclass(
5656
const std::string &datatype, const typet &type)
5757
{
58-
return is_primitive_type(type) ||
59-
is_java_array_type_name(datatype) ||
60-
datatype=="java::java.lang.Object";
58+
return is_primitive_type(type) || is_java_array_type_name(datatype);
6159
}
6260

6361
static typet get_return_type_from_function_name(

src/taint-slicer/instrumenter.cpp

Lines changed: 71 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -606,42 +606,6 @@ void taint_instrumentert::instrument_instructions_with_shadow_variables(
606606
}
607607
}
608608

609-
static irept add_shadow_variables_to_type(
610-
const irept &type,
611-
const std::vector<taint_instrumentert::automaton_variable_idt> &vars,
612-
const taint_datatype_infot &info)
613-
{
614-
if(type.id()==ID_struct)
615-
{
616-
const struct_typet &struct_type=
617-
to_struct_type(static_cast<const typet &>(type));
618-
const auto tag="java::"+as_string(struct_type.get_tag());
619-
if(tag==info.get_id())
620-
{
621-
if(info.subclass_required())
622-
{
623-
// Nothing to do here, because we handle subclassed data types
624-
// differently. See calls to 'substitute_subclassed_types' from
625-
// 'taint_instrumentert::instrument_data_types' for details.
626-
}
627-
else
628-
{
629-
struct_typet result=struct_type;
630-
struct_typet::componentst &components=result.components();
631-
for(const taint_instrumentert::automaton_variable_idt &var : vars)
632-
{
633-
components.push_back(struct_typet::componentt{
634-
var, bool_typet() });
635-
components.back().set_pretty_name(var);
636-
components.back().set_access(ID_public);
637-
}
638-
return result;
639-
}
640-
}
641-
}
642-
return type;
643-
}
644-
645609
taint_instrumentert::taint_instrumentert(
646610
const taint_instrumentation_propst &in_props,
647611
const taint_programt *const in_program,
@@ -870,13 +834,37 @@ void taint_instrumentert::instrument_data_types(
870834
}
871835
else
872836
{
873-
symbolt &symbol=*instrumented_symbol_table.get_writeable(id_info.first);
874-
const irept itype=instrument(symbol.type, std::bind(
875-
&add_shadow_variables_to_type,
876-
std::placeholders::_1,
877-
std::cref(vars),
878-
std::cref(id_info.second)));
879-
symbol.type=static_cast<const typet&>(itype);
837+
namespacet ns(instrumented_symbol_table);
838+
const symbolt *symbol_ptr = &ns.lookup(id_info.first);
839+
while(true)
840+
{
841+
INVARIANT(
842+
symbol_ptr->type.id() == ID_struct,
843+
"In this branch the instrumented type must always be a struct type.");
844+
const struct_typet &struct_type = to_struct_type(symbol_ptr->type);
845+
const struct_typet::componentst &components = struct_type.components();
846+
INVARIANT(
847+
!components.empty(),
848+
"The class has either a parent or class identifier.");
849+
auto type = namespacet(instrumented_symbol_table)
850+
.follow(components.front().type());
851+
if(type.id() != ID_struct)
852+
break;
853+
symbol_ptr =
854+
&ns.lookup("java::" + as_string(to_struct_type(type).get_tag()));
855+
}
856+
struct_typet &struct_type = to_struct_type(
857+
instrumented_symbol_table.get_writeable(symbol_ptr->name)->type);
858+
struct_typet::componentst &components = struct_type.components();
859+
for(const taint_instrumentert::automaton_variable_idt &var : vars)
860+
{
861+
if(!struct_type.has_component(var))
862+
{
863+
components.push_back(struct_typet::componentt{var, bool_typet()});
864+
components.back().set_pretty_name(var);
865+
components.back().set_access(ID_public);
866+
}
867+
}
880868
}
881869
}
882870

@@ -927,18 +915,45 @@ static exprt get_accessor_expression_to_shadow_variable_from_call_expression(
927915
}
928916

929917
static exprt make_accessor_expression_to_shadow_variable(
930-
const exprt &argument, const std::string &shadow_variable_name)
918+
const exprt &argument,
919+
const std::string &shadow_variable_name,
920+
const symbol_tablet &symbol_table)
931921
{
932-
if(argument.type().id()==ID_pointer)
922+
namespacet ns(symbol_table);
923+
const typet &arg_type = ns.follow(argument.type());
924+
if(arg_type.id() == ID_pointer)
933925
{
934-
const pointer_typet pt=to_pointer_type(argument.type());
935-
return member_exprt(
926+
const pointer_typet pt = to_pointer_type(arg_type);
927+
return make_accessor_expression_to_shadow_variable(
936928
dereference_exprt(argument, pt.subtype()),
937929
shadow_variable_name,
938-
bool_typet());
930+
symbol_table);
939931
}
940-
else
941-
return member_exprt(argument, shadow_variable_name, bool_typet());
932+
INVARIANT(
933+
arg_type.id() == ID_struct,
934+
"The remaining possible case is that the arg_type is of a class type.");
935+
exprt access_path = argument;
936+
typet type = arg_type;
937+
while(true)
938+
{
939+
const struct_typet &struct_type = to_struct_type(type);
940+
if(struct_type.has_component(shadow_variable_name))
941+
{
942+
access_path =
943+
member_exprt(access_path, shadow_variable_name, bool_typet());
944+
break;
945+
}
946+
const struct_typet::componentst &components = struct_type.components();
947+
INVARIANT(
948+
!components.empty(), "The class has either the shadow var of a parent.");
949+
access_path = member_exprt(
950+
access_path, components.front().get_name(), components.front().type());
951+
type = ns.follow(components.front().type());
952+
INVARIANT(
953+
type.id() == ID_struct,
954+
"The base class instance is stored by value and must be available.");
955+
}
956+
return access_path;
942957
}
943958

944959
void taint_instrumentert::instrument_location(
@@ -989,9 +1004,10 @@ void taint_instrumentert::instrument_location(
9891004
fn_call,
9901005
assumption.get_argidx(),
9911006
instrumented_symbol_table);
992-
const exprt proposition=make_accessor_expression_to_shadow_variable(
1007+
const exprt proposition = make_accessor_expression_to_shadow_variable(
9931008
acc_path,
994-
from_tokens_to_vars.at(assumption.get_token_name()));
1009+
from_tokens_to_vars.at(assumption.get_token_name()),
1010+
instrumented_symbol_table);
9951011
conjuncts.push_back(proposition);
9961012
}
9971013
auto iit=instrumentation_code.add_instruction();
@@ -1019,10 +1035,11 @@ void taint_instrumentert::instrument_location(
10191035
get_accessor_expression_to_shadow_variable_from_call_expression(
10201036
fn_call, arg_token.get_argidx(), symbol_table);
10211037
auto iit=instrumentation_code.add_instruction(ASSIGN);
1022-
iit->code=code_assignt(
1038+
iit->code = code_assignt(
10231039
make_accessor_expression_to_shadow_variable(
10241040
acc_path,
1025-
from_tokens_to_vars.at(arg_token.get_token_name())),
1041+
from_tokens_to_vars.at(arg_token.get_token_name()),
1042+
symbol_table),
10261043
constant_exprt(bool_state_name, typet(ID_bool)));
10271044
iit->function=function_id;
10281045
}

0 commit comments

Comments
 (0)