Unverified Commit 37fb78a4 by Melvin Klimke Committed by GitHub

Callee saved return targets in CWE78 check (#167)

parent 4bdf6504
......@@ -7,7 +7,7 @@ use petgraph::graph::NodeIndex;
use super::{state::State, BlockMaps, SymbolMaps, CWE_MODULE};
use crate::{
abstract_domain::AbstractDomain,
abstract_domain::{AbstractDomain, DataDomain, IntervalDomain},
analysis::{
forward_interprocedural_fixpoint::Context as PiContext, graph::Graph,
interprocedural_fixpoint_generic::NodeValue,
......@@ -147,25 +147,37 @@ impl<'a> Context<'a> {
panic!("Missing parameters for string related function!");
};
if relevant_fuction_call {
for parameter in string_symbol.parameters.iter() {
match parameter {
Arg::Register(var) => {
new_state.set_register_taint(var, Taint::Tainted(var.size))
self.taint_function_arguments(
&mut new_state,
pi_state,
string_symbol.parameters.clone(),
);
}
}
new_state
}
/// Taints register and stack function arguments.
pub fn taint_function_arguments(
&self,
state: &mut State,
pi_state: &PointerInferenceState,
parameters: Vec<Arg>,
) {
for parameter in parameters.iter() {
match parameter {
Arg::Register(var) => state.set_register_taint(var, Taint::Tainted(var.size)),
Arg::Stack { size, .. } => {
if let Ok(address) = pi_state.eval_parameter_arg(
parameter,
&self.project.stack_pointer_register,
self.runtime_memory_image,
) {
new_state.save_taint_to_memory(&address, Taint::Tainted(*size))
}
}
state.save_taint_to_memory(&address, Taint::Tainted(*size))
}
}
}
}
new_state
}
/// Checks whether the firt parameter of a string related function points to a taint.
......@@ -176,18 +188,50 @@ impl<'a> Context<'a> {
state: &mut State,
parameter: &Arg,
) -> bool {
let mut points_to_memory_taint: bool = false;
if let Ok(address) = pi_state.eval_parameter_arg(
parameter,
&self.project.stack_pointer_register,
self.runtime_memory_image,
) {
if state.check_if_address_points_to_taint(address.clone(), pi_state) {
let temp_mem_taints: Vec<DataDomain<IntervalDomain>> =
self.add_temporary_callee_saved_register_taints_to_mem_taints(pi_state, state);
if state.address_points_to_taint(address.clone(), pi_state) {
state.remove_mem_taint_at_target(&address);
return true;
points_to_memory_taint = true;
}
temp_mem_taints
.iter()
.for_each(|addr| state.remove_mem_taint_at_target(addr));
}
false
points_to_memory_taint
}
/// Takes taints of callee saved registers and adds them temporarily to the corresponding memory
/// taints if possible.
pub fn add_temporary_callee_saved_register_taints_to_mem_taints(
&self,
pi_state: &PointerInferenceState,
state: &mut State,
) -> Vec<DataDomain<IntervalDomain>> {
let mut temp_mem_taints: Vec<DataDomain<IntervalDomain>> = Vec::new();
if let Some(standard_cconv) = self.project.get_standard_calling_convention() {
for (var, _) in state
.get_callee_saved_register_taints(standard_cconv)
.iter()
{
let address = pi_state.eval(&Expression::Var(var.clone()));
if !state.address_points_to_taint(address.clone(), pi_state) {
temp_mem_taints.push(address.clone());
state.save_taint_to_memory(&address, Taint::Tainted(var.size));
}
}
}
temp_mem_taints
}
/// This function taints the registers and stack positions of the parameter pointers of external functions
......@@ -236,57 +280,14 @@ impl<'a> Context<'a> {
&new_state.get_current_sub().as_ref().unwrap().term.name,
);
}
return self.taint_parameters(
&new_state,
symbol.parameters.clone(),
call_source_node,
);
}
}
new_state
}
/// Taints a stack parameter given a size and an offset
pub fn taint_stack_parameters(
&self,
state: State,
call_source_node: NodeIndex,
offset: i64,
size: ByteSize,
) -> State {
let mut new_state = state;
if let Some(NodeValue::Value(pi_state)) = self
.pointer_inference_results
.get_node_value(call_source_node)
{
let address_exp =
Expression::Var(self.project.stack_pointer_register.clone()).plus_const(offset);
let address = pi_state.eval(&address_exp);
new_state.save_taint_to_memory(&address, Taint::Tainted(size));
}
new_state
}
/// Iterates over the given parameters of a function and returns an updated state
pub fn taint_parameters(
&self,
state: &State,
parameters: Vec<Arg>,
call_source_node: NodeIndex,
) -> State {
let mut new_state = state.clone();
for parameter in parameters {
match parameter {
Arg::Register(param) => {
new_state.set_register_taint(&param, Taint::Tainted(param.size))
}
Arg::Stack { offset, size } => {
new_state = self.taint_stack_parameters(
new_state.clone(),
call_source_node,
offset,
size,
self.taint_function_arguments(
&mut new_state,
pi_state,
symbol.parameters.clone(),
);
}
}
......
......@@ -220,11 +220,11 @@ fn tainting_string_function_parameters() {
context.taint_string_function_parameters(&setup.state, &setup.string_sym, *node_id);
assert_eq!(
new_state.check_if_address_points_to_taint(setup.base_sixteen_offset, &setup.pi_state),
new_state.address_points_to_taint(setup.base_sixteen_offset, &setup.pi_state),
true
);
assert_eq!(
new_state.check_if_address_points_to_taint(setup.base_eight_offset, &setup.pi_state),
new_state.address_points_to_taint(setup.base_eight_offset, &setup.pi_state),
false
);
assert_eq!(
......@@ -242,6 +242,91 @@ fn tainting_string_function_parameters() {
}
#[test]
fn tainting_function_arguments() {
let mut setup = Setup::new();
let rdi_reg = Variable::mock("RDI", 8);
let args = vec![
Arg::Register(rdi_reg.clone()),
Arg::Stack {
offset: 24,
size: ByteSize::from(8),
},
];
let mem_image = RuntimeMemoryImage::mock();
let graph = crate::analysis::graph::get_program_cfg(&setup.project.program, HashSet::new());
let mut pi_results = PointerInferenceComputation::mock(&setup.project, &mem_image, &graph);
pi_results.compute();
let context = Context::mock(&setup.project, HashMap::new(), &pi_results, &mem_image);
setup
.pi_state
.write_to_address(
&Expression::BinOp {
op: BinOpType::IntAdd,
lhs: Box::new(Expression::Var(Variable {
name: String::from("RSP"),
size: ByteSize::new(8),
is_temp: false,
})),
rhs: Box::new(Expression::Const(Bitvector::from_u64(24))),
},
&Data::Pointer(PointerDomain::new(setup.pi_state.stack_id.clone(), bv(32))),
context.runtime_memory_image,
)
.expect("Failed to write to address.");
context.taint_function_arguments(&mut setup.state, &setup.pi_state, args);
assert_eq!(
setup.state.get_register_taint(&rdi_reg),
Some(&Taint::Tainted(rdi_reg.size))
);
assert!(setup.state.address_points_to_taint(
Data::Pointer(PointerDomain::new(setup.pi_state.stack_id.clone(), bv(32))),
&setup.pi_state
));
}
#[test]
fn adding_temporary_callee_saved_register_taints_to_mem_taints() {
let mut setup = Setup::new();
let rbp_reg = Variable::mock("RBP", 8 as u64);
let rcx_reg = Variable::mock("RCX", 8 as u64);
setup
.pi_state
.set_register(&rbp_reg, setup.base_eight_offset.clone());
setup
.pi_state
.set_register(&rcx_reg, setup.base_sixteen_offset.clone());
setup
.state
.set_register_taint(&rbp_reg, Taint::Tainted(rbp_reg.size));
setup
.state
.set_register_taint(&rcx_reg, Taint::Tainted(rcx_reg.size));
let mem_image = RuntimeMemoryImage::mock();
let graph = crate::analysis::graph::get_program_cfg(&setup.project.program, HashSet::new());
let mut pi_results = PointerInferenceComputation::mock(&setup.project, &mem_image, &graph);
pi_results.compute();
let context = Context::mock(&setup.project, HashMap::new(), &pi_results, &mem_image);
let result = context.add_temporary_callee_saved_register_taints_to_mem_taints(
&setup.pi_state,
&mut setup.state,
);
assert!(result.len() == 1);
assert!(setup
.state
.address_points_to_taint(result.get(0).unwrap().clone(), &setup.pi_state))
}
#[test]
fn first_param_pointing_to_memory_taint() {
let mut setup = Setup::new();
......@@ -268,7 +353,7 @@ fn first_param_pointing_to_memory_taint() {
assert_eq!(
setup
.state
.check_if_address_points_to_taint(setup.base_eight_offset, &setup.pi_state),
.address_points_to_taint(setup.base_eight_offset, &setup.pi_state),
false
);
}
......@@ -362,86 +447,6 @@ fn tainting_generic_function_parameters_and_removing_non_callee_saved() {
}
#[test]
fn tainting_stack_parameters() {
let setup = Setup::new();
let offset = 4 as i64;
let size = ByteSize::new(8);
let stack_id = setup.pi_state.stack_id.clone();
let mem_image = RuntimeMemoryImage::mock();
let graph = crate::analysis::graph::get_program_cfg(&setup.project.program, HashSet::new());
let mut pi_results = PointerInferenceComputation::mock(&setup.project, &mem_image, &graph);
pi_results.compute();
let context = Context::mock(&setup.project, HashMap::new(), &pi_results, &mem_image);
let call_source_node = context
.block_maps
.jmp_to_blk_end_node_map
.get(&(Tid::new("call_string"), Tid::new("func")))
.unwrap();
let new_state =
context.taint_stack_parameters(setup.state, call_source_node.clone(), offset, size);
assert_eq!(
new_state.check_if_address_points_to_taint(
Data::Pointer(PointerDomain::new(stack_id.clone(), bv(4))),
&setup.pi_state
),
true
);
}
#[test]
fn tainting_parameters() {
let setup = Setup::new();
let rdi_reg = Variable::mock("RDI", 8 as u64);
let rsi_reg = Variable::mock("RSI", 8 as u64);
let params = vec![
Arg::Register(rdi_reg.clone()),
Arg::Register(rsi_reg.clone()),
Arg::Stack {
offset: 4,
size: ByteSize::new(8),
},
];
let stack_id = setup.pi_state.stack_id.clone();
let mem_image = RuntimeMemoryImage::mock();
let graph = crate::analysis::graph::get_program_cfg(&setup.project.program, HashSet::new());
let mut pi_results = PointerInferenceComputation::mock(&setup.project, &mem_image, &graph);
pi_results.compute();
let context = Context::mock(&setup.project, HashMap::new(), &pi_results, &mem_image);
let call_source_node = context
.block_maps
.jmp_to_blk_end_node_map
.get(&(Tid::new("call_string"), Tid::new("func")))
.unwrap();
let new_state = context.taint_parameters(&setup.state, params, call_source_node.clone());
assert_eq!(
new_state.get_register_taint(&rdi_reg),
Some(&Taint::Tainted(rdi_reg.size))
);
assert_eq!(
new_state.get_register_taint(&rsi_reg),
Some(&Taint::Tainted(rsi_reg.size))
);
assert_eq!(
new_state.check_if_address_points_to_taint(
Data::Pointer(PointerDomain::new(stack_id.clone(), bv(4))),
&setup.pi_state
),
true
);
}
#[test]
fn creating_pi_def_map() {
let setup = Setup::new();
let rdi_reg = Variable::mock("RDI", 8 as u64);
......@@ -662,7 +667,7 @@ fn handling_assign_and_load() {
new_state = context.update_def(&new_state, &mock_assign_stack).unwrap();
assert_eq!(new_state.get_register_taint(&r9_reg), None);
assert_eq!(
new_state.check_if_address_points_to_taint(
new_state.address_points_to_taint(
Data::Pointer(PointerDomain::new(stack_id.clone(), bv(0))),
&setup.pi_state
),
......@@ -740,7 +745,7 @@ fn updating_def() {
new_state = context.update_def(&new_state, &mock_assign_stack).unwrap();
assert_eq!(new_state.get_register_taint(&r9_reg), None);
assert_eq!(
new_state.check_if_address_points_to_taint(
new_state.address_points_to_taint(
Data::Pointer(PointerDomain::new(stack_id.clone(), bv(0))),
&setup.pi_state
),
......@@ -769,7 +774,7 @@ fn updating_def() {
Some(&Taint::Tainted(rdi_reg.size))
);
assert_eq!(
new_state.check_if_address_points_to_taint(setup.base_eight_offset, &setup.pi_state,),
new_state.address_points_to_taint(setup.base_eight_offset, &setup.pi_state,),
false
);
}
......@@ -811,7 +816,7 @@ fn updating_jumpsite() {
Some(&Taint::Tainted(r9_reg.size))
);
assert_eq!(
new_state.check_if_address_points_to_taint(
new_state.address_points_to_taint(
setup.base_eight_offset,
new_state
.get_pointer_inference_state_at_def(&Tid::new("initial"))
......@@ -944,7 +949,7 @@ fn splitting_call_stub() {
Some(&Taint::Tainted(r9_reg.size))
);
assert_eq!(
new_state.check_if_address_points_to_taint(
new_state.address_points_to_taint(
setup.base_eight_offset,
new_state
.get_pointer_inference_state_at_def(&Tid::new("initial"))
......@@ -993,7 +998,7 @@ fn splitting_return_stub() {
Some(&Taint::Tainted(rax_reg.size))
);
assert_eq!(
new_state.check_if_address_points_to_taint(
new_state.address_points_to_taint(
setup.base_eight_offset,
new_state
.get_pointer_inference_state_at_def(&Tid::new("initial"))
......@@ -1042,11 +1047,11 @@ fn updating_call_stub() {
let new_state = context.update_call_stub(&setup.state, &mock_call).unwrap();
assert_eq!(
new_state.check_if_address_points_to_taint(setup.base_sixteen_offset, &setup.pi_state),
new_state.address_points_to_taint(setup.base_sixteen_offset, &setup.pi_state),
true
);
assert_eq!(
new_state.check_if_address_points_to_taint(setup.base_eight_offset, &setup.pi_state),
new_state.address_points_to_taint(setup.base_eight_offset, &setup.pi_state),
false
);
assert_eq!(
......@@ -1094,7 +1099,7 @@ fn specializing_conditional() {
Some(&Taint::Tainted(r9_reg.size))
);
assert_eq!(
new_state.check_if_address_points_to_taint(
new_state.address_points_to_taint(
setup.base_eight_offset,
new_state
.get_pointer_inference_state_at_def(&Tid::new("initial"))
......
......@@ -183,6 +183,28 @@ impl State {
self.register_taint.iter()
}
/// Gets the callee saved taints from the register taints.
pub fn get_callee_saved_register_taints(
&self,
calling_conv: &CallingConvention,
) -> HashMap<Variable, Taint> {
self.register_taint
.clone()
.iter()
.filter_map(|(register, taint)| {
if calling_conv
.callee_saved_register
.iter()
.any(|callee_saved_reg| register.name == *callee_saved_reg)
{
Some((register.clone(), *taint))
} else {
None
}
})
.collect()
}
/// Gets the string constant saved at the given address and saves it to the string constants field.
pub fn evaluate_constant(&mut self, constant: Bitvector) {
// TODO: check whether the constant is a valid memory address in the binary
......@@ -232,7 +254,7 @@ impl State {
if let Some(pid_map) = self.pi_def_map.as_ref() {
if let Some(pi_state) = pid_map.get(def_tid) {
let address = pi_state.eval(target);
if self.check_if_address_points_to_taint(address.clone(), &pi_state) {
if self.address_points_to_taint(address.clone(), &pi_state) {
self.taint_def_input_register(value, stack_pointer_register, def_tid);
self.remove_mem_taint_at_target(&address);
}
......@@ -332,11 +354,7 @@ impl State {
/// return true if and only if the value at that stack position is tainted.
/// If the given address points to a non-stack memory object,
/// return true if the memory object contains any tainted value (at any position).
pub fn check_if_address_points_to_taint(
&self,
address: Data,
pi_state: &PointerInferenceState,
) -> bool {
pub fn address_points_to_taint(&self, address: Data, pi_state: &PointerInferenceState) -> bool {
use crate::analysis::pointer_inference::object::ObjectType;
if let Data::Pointer(pointer) = address {
for (target, offset) in pointer.targets() {
......
......@@ -166,7 +166,7 @@ fn setting_expression_and_constants() {
assert_eq!(
setup
.state
.check_if_address_points_to_taint(setup.stack_pointer, &setup.pi_state),
.address_points_to_taint(setup.stack_pointer, &setup.pi_state),
true
);
......@@ -186,7 +186,7 @@ fn setting_expression_and_constants() {
assert_eq!(
setup
.state
.check_if_address_points_to_taint(setup.base_eight_offset, &setup.pi_state),
.address_points_to_taint(setup.base_eight_offset, &setup.pi_state),
true
);
......@@ -234,7 +234,7 @@ fn tainting_values_to_be_stored() {
assert_eq!(
setup
.state
.check_if_address_points_to_taint(setup.base_eight_offset, &setup.pi_state),
.address_points_to_taint(setup.base_eight_offset, &setup.pi_state),
false
);
assert_eq!(
......@@ -286,7 +286,7 @@ fn tainting_def_input_register() {
assert_eq!(
setup
.state
.check_if_address_points_to_taint(setup.stack_pointer.clone(), &setup.pi_state),
.address_points_to_taint(setup.stack_pointer.clone(), &setup.pi_state),
true
);
......@@ -344,7 +344,7 @@ fn tainting_variable_input() {
assert_eq!(
setup
.state
.check_if_address_points_to_taint(setup.stack_pointer.clone(), &setup.pi_state),
.address_points_to_taint(setup.stack_pointer.clone(), &setup.pi_state),
true
);
}
......@@ -360,7 +360,7 @@ fn removing_memory_taint_at_target() {
assert_eq!(
setup
.state
.check_if_address_points_to_taint(setup.base_eight_offset.clone(), &setup.pi_state),
.address_points_to_taint(setup.base_eight_offset.clone(), &setup.pi_state),
true
);
setup
......@@ -369,7 +369,7 @@ fn removing_memory_taint_at_target() {
assert_eq!(
setup
.state
.check_if_address_points_to_taint(setup.base_eight_offset, &setup.pi_state),
.address_points_to_taint(setup.base_eight_offset, &setup.pi_state),
false
);
......@@ -377,7 +377,7 @@ fn removing_memory_taint_at_target() {
assert_eq!(
setup
.state
.check_if_address_points_to_taint(setup.base_sixteen_offset.clone(), &setup.pi_state),
.address_points_to_taint(setup.base_sixteen_offset.clone(), &setup.pi_state),
false
);
setup
......@@ -386,7 +386,7 @@ fn removing_memory_taint_at_target() {
assert_eq!(
setup
.state
.check_if_address_points_to_taint(setup.base_sixteen_offset, &setup.pi_state),
.address_points_to_taint(setup.base_sixteen_offset, &setup.pi_state),
false
);
}
......@@ -398,7 +398,7 @@ fn saving_taint_to_memory() {
assert_eq!(
setup
.state
.check_if_address_points_to_taint(setup.base_eight_offset.clone(), &setup.pi_state),
.address_points_to_taint(setup.base_eight_offset.clone(), &setup.pi_state),
false
);
setup
......@@ -407,7 +407,7 @@ fn saving_taint_to_memory() {
assert_eq!(
setup
.state
.check_if_address_points_to_taint(setup.base_eight_offset.clone(), &setup.pi_state),
.address_points_to_taint(setup.base_eight_offset.clone(), &setup.pi_state),
true
);
}
......@@ -494,13 +494,13 @@ fn checking_if_address_points_to_taint() {
assert_eq!(
setup
.state
.check_if_address_points_to_taint(setup.base_eight_offset, &setup.pi_state),
.address_points_to_taint(setup.base_eight_offset, &setup.pi_state),
true
);
assert_eq!(
setup
.state
.check_if_address_points_to_taint(setup.base_sixteen_offset, &setup.pi_state),
.address_points_to_taint(setup.base_sixteen_offset, &setup.pi_state),
false
);
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment