Unverified Commit 170f44b1 by van den Bosch Committed by GitHub

Refactor runtime memory image (#324)

parent 576c3dd9
...@@ -4,7 +4,8 @@ ...@@ -4,7 +4,8 @@
extern crate cwe_checker_lib; // Needed for the docstring-link to work extern crate cwe_checker_lib; // Needed for the docstring-link to work
use cwe_checker_lib::analysis::graph; use cwe_checker_lib::analysis::graph;
use cwe_checker_lib::utils::binary::{BareMetalConfig, RuntimeMemoryImage}; use cwe_checker_lib::intermediate_representation::RuntimeMemoryImage;
use cwe_checker_lib::utils::binary::BareMetalConfig;
use cwe_checker_lib::utils::log::{print_all_messages, LogLevel}; use cwe_checker_lib::utils::log::{print_all_messages, LogLevel};
use cwe_checker_lib::utils::{get_ghidra_plugin_path, read_config_file}; use cwe_checker_lib::utils::{get_ghidra_plugin_path, read_config_file};
use cwe_checker_lib::AnalysisResults; use cwe_checker_lib::AnalysisResults;
...@@ -159,6 +160,9 @@ fn run_with_ghidra(args: &CmdlineArgs) { ...@@ -159,6 +160,9 @@ fn run_with_ghidra(args: &CmdlineArgs) {
// so that other analyses do not have to adjust their addresses. // so that other analyses do not have to adjust their addresses.
runtime_memory_image.add_global_memory_offset(project.program.term.address_base_offset); runtime_memory_image.add_global_memory_offset(project.program.term.address_base_offset);
} }
project.runtime_memory_image = runtime_memory_image;
// Generate the control flow graph of the program // Generate the control flow graph of the program
let extern_sub_tids = project let extern_sub_tids = project
.program .program
...@@ -169,12 +173,7 @@ fn run_with_ghidra(args: &CmdlineArgs) { ...@@ -169,12 +173,7 @@ fn run_with_ghidra(args: &CmdlineArgs) {
.collect(); .collect();
let control_flow_graph = graph::get_program_cfg(&project.program, extern_sub_tids); let control_flow_graph = graph::get_program_cfg(&project.program, extern_sub_tids);
let analysis_results = AnalysisResults::new( let analysis_results = AnalysisResults::new(&binary, &control_flow_graph, &project);
&binary,
&runtime_memory_image,
&control_flow_graph,
&project,
);
let modules_depending_on_string_abstraction = BTreeSet::from_iter(["CWE78"]); let modules_depending_on_string_abstraction = BTreeSet::from_iter(["CWE78"]);
let modules_depending_on_pointer_inference = let modules_depending_on_pointer_inference =
......
...@@ -22,7 +22,7 @@ impl<'a> Context<'a> { ...@@ -22,7 +22,7 @@ impl<'a> Context<'a> {
for param in callee_fn_sig.parameters.keys() { for param in callee_fn_sig.parameters.keys() {
let param_id = AbstractIdentifier::from_arg(callee_tid, param); let param_id = AbstractIdentifier::from_arg(callee_tid, param);
if let Ok(param_value) = if let Ok(param_value) =
state_before_call.eval_parameter_arg(param, self.runtime_memory_image) state_before_call.eval_parameter_arg(param, &self.project.runtime_memory_image)
{ {
id_map.insert(param_id, param_value); id_map.insert(param_id, param_value);
} else { } else {
......
use crate::abstract_domain::*;
use crate::analysis::function_signature::FunctionSignature; use crate::analysis::function_signature::FunctionSignature;
use crate::analysis::graph::Graph; use crate::analysis::graph::Graph;
use crate::intermediate_representation::*; use crate::intermediate_representation::*;
use crate::prelude::*; use crate::prelude::*;
use crate::utils::log::*; use crate::utils::log::*;
use crate::{abstract_domain::*, utils::binary::RuntimeMemoryImage};
use std::collections::{BTreeMap, BTreeSet}; use std::collections::{BTreeMap, BTreeSet};
use super::state::State; use super::state::State;
...@@ -24,9 +24,6 @@ pub struct Context<'a> { ...@@ -24,9 +24,6 @@ pub struct Context<'a> {
pub graph: &'a Graph<'a>, pub graph: &'a Graph<'a>,
/// A reference to the `Project` object representing the binary /// A reference to the `Project` object representing the binary
pub project: &'a Project, pub project: &'a Project,
/// The runtime memory image for reading global read-only variables.
/// Note that values of writeable global memory segments are not tracked.
pub runtime_memory_image: &'a RuntimeMemoryImage,
/// Maps the TIDs of functions that shall be treated as extern symbols to the `ExternSymbol` object representing it. /// Maps the TIDs of functions that shall be treated as extern symbols to the `ExternSymbol` object representing it.
pub extern_symbol_map: &'a BTreeMap<Tid, ExternSymbol>, pub extern_symbol_map: &'a BTreeMap<Tid, ExternSymbol>,
/// Maps the TIDs of internal functions to the function signatures computed for it. /// Maps the TIDs of internal functions to the function signatures computed for it.
...@@ -54,7 +51,6 @@ impl<'a> Context<'a> { ...@@ -54,7 +51,6 @@ impl<'a> Context<'a> {
Context { Context {
graph: analysis_results.control_flow_graph, graph: analysis_results.control_flow_graph,
project: analysis_results.project, project: analysis_results.project,
runtime_memory_image: analysis_results.runtime_memory_image,
extern_symbol_map: &analysis_results.project.program.term.extern_symbols, extern_symbol_map: &analysis_results.project.program.term.extern_symbols,
fn_signatures: analysis_results.function_signatures.unwrap(), fn_signatures: analysis_results.function_signatures.unwrap(),
log_collector, log_collector,
...@@ -73,7 +69,9 @@ impl<'a> Context<'a> { ...@@ -73,7 +69,9 @@ impl<'a> Context<'a> {
address: &Expression, address: &Expression,
) -> bool { ) -> bool {
if self.project.cpu_architecture.contains("MIPS") && var.name == "gp" { if self.project.cpu_architecture.contains("MIPS") && var.name == "gp" {
if let Ok(gp_val) = state.load_value(address, var.size, self.runtime_memory_image) { if let Ok(gp_val) =
state.load_value(address, var.size, &self.project.runtime_memory_image)
{
gp_val.is_top() gp_val.is_top()
} else { } else {
true true
...@@ -137,23 +135,23 @@ impl<'a> Context<'a> { ...@@ -137,23 +135,23 @@ impl<'a> Context<'a> {
"malloc" => { "malloc" => {
let size_parameter = extern_symbol.parameters.get(0).unwrap(); let size_parameter = extern_symbol.parameters.get(0).unwrap();
state state
.eval_parameter_arg(size_parameter, self.runtime_memory_image) .eval_parameter_arg(size_parameter, &self.project.runtime_memory_image)
.unwrap_or_else(|_| Data::new_top(address_bytesize)) .unwrap_or_else(|_| Data::new_top(address_bytesize))
} }
"realloc" => { "realloc" => {
let size_parameter = extern_symbol.parameters.get(1).unwrap(); let size_parameter = extern_symbol.parameters.get(1).unwrap();
state state
.eval_parameter_arg(size_parameter, self.runtime_memory_image) .eval_parameter_arg(size_parameter, &self.project.runtime_memory_image)
.unwrap_or_else(|_| Data::new_top(address_bytesize)) .unwrap_or_else(|_| Data::new_top(address_bytesize))
} }
"calloc" => { "calloc" => {
let size_param1 = extern_symbol.parameters.get(0).unwrap(); let size_param1 = extern_symbol.parameters.get(0).unwrap();
let size_param2 = extern_symbol.parameters.get(1).unwrap(); let size_param2 = extern_symbol.parameters.get(1).unwrap();
let param1_value = state let param1_value = state
.eval_parameter_arg(size_param1, self.runtime_memory_image) .eval_parameter_arg(size_param1, &self.project.runtime_memory_image)
.unwrap_or_else(|_| Data::new_top(address_bytesize)); .unwrap_or_else(|_| Data::new_top(address_bytesize));
let param2_value = state let param2_value = state
.eval_parameter_arg(size_param2, self.runtime_memory_image) .eval_parameter_arg(size_param2, &self.project.runtime_memory_image)
.unwrap_or_else(|_| Data::new_top(address_bytesize)); .unwrap_or_else(|_| Data::new_top(address_bytesize));
param1_value.bin_op(BinOpType::IntMult, &param2_value) param1_value.bin_op(BinOpType::IntMult, &param2_value)
} }
...@@ -225,7 +223,7 @@ impl<'a> Context<'a> { ...@@ -225,7 +223,7 @@ impl<'a> Context<'a> {
match extern_symbol.get_unique_parameter() { match extern_symbol.get_unique_parameter() {
Ok(parameter) => { Ok(parameter) => {
let parameter_value = let parameter_value =
state.eval_parameter_arg(parameter, self.runtime_memory_image); state.eval_parameter_arg(parameter, &self.project.runtime_memory_image);
match parameter_value { match parameter_value {
Ok(memory_object_pointer) => { Ok(memory_object_pointer) => {
if let Err(possible_double_frees) = if let Err(possible_double_frees) =
...@@ -275,7 +273,7 @@ impl<'a> Context<'a> { ...@@ -275,7 +273,7 @@ impl<'a> Context<'a> {
I: Iterator<Item = &'iter Arg>, I: Iterator<Item = &'iter Arg>,
{ {
for parameter in parameters { for parameter in parameters {
match state.eval_parameter_arg(parameter, self.runtime_memory_image) { match state.eval_parameter_arg(parameter, &self.project.runtime_memory_image) {
Ok(value) => { Ok(value) => {
if state.memory.is_dangling_pointer(&value, true) { if state.memory.is_dangling_pointer(&value, true) {
state state
...@@ -317,10 +315,12 @@ impl<'a> Context<'a> { ...@@ -317,10 +315,12 @@ impl<'a> Context<'a> {
extern_symbol: &ExternSymbol, extern_symbol: &ExternSymbol,
) { ) {
for parameter in extern_symbol.parameters.iter() { for parameter in extern_symbol.parameters.iter() {
match state.eval_parameter_arg(parameter, self.runtime_memory_image) { match state.eval_parameter_arg(parameter, &self.project.runtime_memory_image) {
Ok(data) => { Ok(data) => {
if state.pointer_contains_out_of_bounds_target(&data, self.runtime_memory_image) if state.pointer_contains_out_of_bounds_target(
{ &data,
&self.project.runtime_memory_image,
) {
let warning = CweWarning { let warning = CweWarning {
name: "CWE119".to_string(), name: "CWE119".to_string(),
version: VERSION.to_string(), version: VERSION.to_string(),
...@@ -394,7 +394,7 @@ impl<'a> Context<'a> { ...@@ -394,7 +394,7 @@ impl<'a> Context<'a> {
extern_symbol: &ExternSymbol, extern_symbol: &ExternSymbol,
) -> State { ) -> State {
self.log_debug( self.log_debug(
new_state.clear_stack_parameter(extern_symbol, self.runtime_memory_image), new_state.clear_stack_parameter(extern_symbol, &self.project.runtime_memory_image),
Some(&call.tid), Some(&call.tid),
); );
let calling_conv = self.project.get_calling_convention(extern_symbol); let calling_conv = self.project.get_calling_convention(extern_symbol);
...@@ -413,7 +413,9 @@ impl<'a> Context<'a> { ...@@ -413,7 +413,9 @@ impl<'a> Context<'a> {
} }
} else { } else {
for parameter in extern_symbol.parameters.iter() { for parameter in extern_symbol.parameters.iter() {
if let Ok(data) = state.eval_parameter_arg(parameter, self.runtime_memory_image) { if let Ok(data) =
state.eval_parameter_arg(parameter, &self.project.runtime_memory_image)
{
possible_referenced_ids.extend(data.referenced_ids().cloned()); possible_referenced_ids.extend(data.referenced_ids().cloned());
} }
} }
......
...@@ -42,7 +42,9 @@ impl<'a> crate::analysis::forward_interprocedural_fixpoint::Context<'a> for Cont ...@@ -42,7 +42,9 @@ impl<'a> crate::analysis::forward_interprocedural_fixpoint::Context<'a> for Cont
Ok(false) => (), // no null dereference detected Ok(false) => (), // no null dereference detected
} }
// check for out-of-bounds memory access // check for out-of-bounds memory access
if new_state.contains_out_of_bounds_mem_access(&def.term, self.runtime_memory_image) { if new_state
.contains_out_of_bounds_mem_access(&def.term, &self.project.runtime_memory_image)
{
let (warning_name, warning_description) = match &def.term { let (warning_name, warning_description) = match &def.term {
Def::Load { .. } => ( Def::Load { .. } => (
"CWE125", "CWE125",
...@@ -75,7 +77,7 @@ impl<'a> crate::analysis::forward_interprocedural_fixpoint::Context<'a> for Cont ...@@ -75,7 +77,7 @@ impl<'a> crate::analysis::forward_interprocedural_fixpoint::Context<'a> for Cont
match &def.term { match &def.term {
Def::Store { address, value } => { Def::Store { address, value } => {
self.log_debug( self.log_debug(
new_state.handle_store(address, value, self.runtime_memory_image), new_state.handle_store(address, value, &self.project.runtime_memory_image),
Some(&def.tid), Some(&def.tid),
); );
Some(new_state) Some(new_state)
...@@ -87,7 +89,7 @@ impl<'a> crate::analysis::forward_interprocedural_fixpoint::Context<'a> for Cont ...@@ -87,7 +89,7 @@ impl<'a> crate::analysis::forward_interprocedural_fixpoint::Context<'a> for Cont
Def::Load { var, address } => { Def::Load { var, address } => {
if !self.is_mips_gp_load_to_top_value(state, var, address) { if !self.is_mips_gp_load_to_top_value(state, var, address) {
self.log_debug( self.log_debug(
new_state.handle_load(var, address, self.runtime_memory_image), new_state.handle_load(var, address, &self.project.runtime_memory_image),
Some(&def.tid), Some(&def.tid),
); );
} }
......
...@@ -275,7 +275,11 @@ impl<'a> PointerInference<'a> { ...@@ -275,7 +275,11 @@ impl<'a> PointerInference<'a> {
} }
Def::Load { var, address } => { Def::Load { var, address } => {
let loaded_value = state let loaded_value = state
.load_value(address, var.size, context.runtime_memory_image) .load_value(
address,
var.size,
&context.project.runtime_memory_image,
)
.unwrap_or_else(|_| Data::new_top(var.size)); .unwrap_or_else(|_| Data::new_top(var.size));
self.values_at_defs.insert(def.tid.clone(), loaded_value); self.values_at_defs.insert(def.tid.clone(), loaded_value);
self.addresses_at_defs self.addresses_at_defs
......
...@@ -2,6 +2,8 @@ ...@@ -2,6 +2,8 @@
//! or check whether they are violated. //! or check whether they are violated.
//! E.g. checks for use-after-free or buffer overflow checks. //! E.g. checks for use-after-free or buffer overflow checks.
use crate::intermediate_representation::RuntimeMemoryImage;
use super::*; use super::*;
impl AbstractObjectList { impl AbstractObjectList {
......
use super::object::*; use super::object::*;
use super::{Data, ValueDomain}; use super::{Data, ValueDomain};
use crate::abstract_domain::*;
use crate::prelude::*; use crate::prelude::*;
use crate::{abstract_domain::*, utils::binary::RuntimeMemoryImage};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use std::collections::{BTreeMap, BTreeSet}; use std::collections::{BTreeMap, BTreeSet};
......
//! Methods of [`State`] for handling memory and register access operations. //! Methods of [`State`] for handling memory and register access operations.
use crate::utils::binary::RuntimeMemoryImage;
use super::*; use super::*;
impl State { impl State {
......
...@@ -4,7 +4,6 @@ use crate::abstract_domain::*; ...@@ -4,7 +4,6 @@ use crate::abstract_domain::*;
use crate::analysis::function_signature::FunctionSignature; use crate::analysis::function_signature::FunctionSignature;
use crate::intermediate_representation::*; use crate::intermediate_representation::*;
use crate::prelude::*; use crate::prelude::*;
use crate::utils::binary::RuntimeMemoryImage;
use std::collections::{BTreeMap, BTreeSet}; use std::collections::{BTreeMap, BTreeSet};
mod access_handling; mod access_handling;
......
use super::super::ValueDomain; use super::super::ValueDomain;
use super::*; use super::*;
use crate::analysis::pointer_inference::object::*; use crate::analysis::pointer_inference::object::*;
use crate::utils::binary::RuntimeMemoryImage;
use Expression::*; use Expression::*;
fn bv(value: i64) -> ValueDomain { fn bv(value: i64) -> ValueDomain {
......
...@@ -27,7 +27,7 @@ impl<'a> VsaResult for PointerInference<'a> { ...@@ -27,7 +27,7 @@ impl<'a> VsaResult for PointerInference<'a> {
let state = self.states_at_tids.get(jmp_tid)?; let state = self.states_at_tids.get(jmp_tid)?;
let context = self.computation.get_context().get_context(); let context = self.computation.get_context().get_context();
state state
.eval_parameter_arg(parameter, context.runtime_memory_image) .eval_parameter_arg(parameter, &context.project.runtime_memory_image)
.ok() .ok()
} }
} }
...@@ -17,7 +17,6 @@ use crate::{ ...@@ -17,7 +17,6 @@ use crate::{
pointer_inference::State as PointerInferenceState, pointer_inference::State as PointerInferenceState,
}, },
intermediate_representation::{Def, ExternSymbol, Project, Term, Tid}, intermediate_representation::{Def, ExternSymbol, Project, Term, Tid},
utils::binary::RuntimeMemoryImage,
}; };
use super::{state::State, Config}; use super::{state::State, Config};
...@@ -31,9 +30,6 @@ mod trait_impls; ...@@ -31,9 +30,6 @@ mod trait_impls;
pub struct Context<'a, T: AbstractDomain + DomainInsertion + HasTop + Eq + From<String>> { pub struct Context<'a, T: AbstractDomain + DomainInsertion + HasTop + Eq + From<String>> {
/// A reference to the `Project` object representing the binary /// A reference to the `Project` object representing the binary
pub project: &'a Project, pub project: &'a Project,
/// The runtime memory image for reading global read-only variables.
/// Note that values of writeable global memory segments are not tracked.
pub runtime_memory_image: &'a RuntimeMemoryImage,
/// A pointer to the results of the pointer inference analysis. /// A pointer to the results of the pointer inference analysis.
/// They are used to determine the targets of pointers to memory, /// They are used to determine the targets of pointers to memory,
/// which in turn is used to keep track of taint on the stack or on the heap. /// which in turn is used to keep track of taint on the stack or on the heap.
...@@ -62,7 +58,6 @@ impl<'a, T: AbstractDomain + HasTop + Eq + From<String> + DomainInsertion> Conte ...@@ -62,7 +58,6 @@ impl<'a, T: AbstractDomain + HasTop + Eq + From<String> + DomainInsertion> Conte
/// Create a new context object for a given project. /// Create a new context object for a given project.
pub fn new( pub fn new(
project: &'a Project, project: &'a Project,
runtime_memory_image: &'a RuntimeMemoryImage,
pointer_inference_results: &'a PointerInferenceComputation<'a>, pointer_inference_results: &'a PointerInferenceComputation<'a>,
config: Config, config: Config,
) -> Context<'a, T> { ) -> Context<'a, T> {
...@@ -95,7 +90,6 @@ impl<'a, T: AbstractDomain + HasTop + Eq + From<String> + DomainInsertion> Conte ...@@ -95,7 +90,6 @@ impl<'a, T: AbstractDomain + HasTop + Eq + From<String> + DomainInsertion> Conte
Context { Context {
project, project,
runtime_memory_image,
pointer_inference_results, pointer_inference_results,
format_string_index_map: config.format_string_index.into_iter().collect(), format_string_index_map: config.format_string_index.into_iter().collect(),
string_symbol_map, string_symbol_map,
......
...@@ -169,7 +169,7 @@ impl<'a, T: AbstractDomain + DomainInsertion + HasTop + Eq + From<String>> Conte ...@@ -169,7 +169,7 @@ impl<'a, T: AbstractDomain + DomainInsertion + HasTop + Eq + From<String>> Conte
/// Inserts a char constant into the format string. /// Inserts a char constant into the format string.
pub fn get_constant_char_domain(&self, constant: Bitvector) -> Option<T> { pub fn get_constant_char_domain(&self, constant: Bitvector) -> Option<T> {
if let Ok(Some(char_code)) = self.runtime_memory_image.read( if let Ok(Some(char_code)) = self.project.runtime_memory_image.read(
&constant, &constant,
self.project self.project
.datatype_properties .datatype_properties
...@@ -199,6 +199,7 @@ impl<'a, T: AbstractDomain + DomainInsertion + HasTop + Eq + From<String>> Conte ...@@ -199,6 +199,7 @@ impl<'a, T: AbstractDomain + DomainInsertion + HasTop + Eq + From<String>> Conte
/// Inserts a string constant into the format string. /// Inserts a string constant into the format string.
pub fn get_constant_string_domain(&self, constant: Bitvector) -> Option<T> { pub fn get_constant_string_domain(&self, constant: Bitvector) -> Option<T> {
if let Ok(string) = self if let Ok(string) = self
.project
.runtime_memory_image .runtime_memory_image
.read_string_until_null_terminator(&constant) .read_string_until_null_terminator(&constant)
{ {
...@@ -218,7 +219,7 @@ impl<'a, T: AbstractDomain + DomainInsertion + HasTop + Eq + From<String>> Conte ...@@ -218,7 +219,7 @@ impl<'a, T: AbstractDomain + DomainInsertion + HasTop + Eq + From<String>> Conte
if let Some(dest_arg) = extern_symbol.parameters.first() { if let Some(dest_arg) = extern_symbol.parameters.first() {
if let Some(pi_state) = state.get_pointer_inference_state() { if let Some(pi_state) = state.get_pointer_inference_state() {
if let Ok(pointer) = if let Ok(pointer) =
pi_state.eval_parameter_arg(dest_arg, self.runtime_memory_image) pi_state.eval_parameter_arg(dest_arg, &self.project.runtime_memory_image)
{ {
let heap_to_string_map = state.get_heap_to_string_map(); let heap_to_string_map = state.get_heap_to_string_map();
for (target, _) in pointer.get_relative_values().iter() { for (target, _) in pointer.get_relative_values().iter() {
......
...@@ -44,7 +44,7 @@ impl<'a, T: AbstractDomain + DomainInsertion + HasTop + Eq + From<String>> Conte ...@@ -44,7 +44,7 @@ impl<'a, T: AbstractDomain + DomainInsertion + HasTop + Eq + From<String>> Conte
) -> Result<DataDomain<IntervalDomain>, Error> { ) -> Result<DataDomain<IntervalDomain>, Error> {
if let Some(return_arg) = extern_symbol.parameters.first() { if let Some(return_arg) = extern_symbol.parameters.first() {
if let Ok(return_data) = if let Ok(return_data) =
pi_state.eval_parameter_arg(return_arg, self.runtime_memory_image) pi_state.eval_parameter_arg(return_arg, &self.project.runtime_memory_image)
{ {
if !return_data.get_relative_values().is_empty() { if !return_data.get_relative_values().is_empty() {
return Ok(return_data); return Ok(return_data);
...@@ -62,7 +62,7 @@ impl<'a, T: AbstractDomain + DomainInsertion + HasTop + Eq + From<String>> Conte ...@@ -62,7 +62,7 @@ impl<'a, T: AbstractDomain + DomainInsertion + HasTop + Eq + From<String>> Conte
pi_state: &PointerInferenceState, pi_state: &PointerInferenceState,
) -> Result<DataDomain<IntervalDomain>, Error> { ) -> Result<DataDomain<IntervalDomain>, Error> {
if let Some(input_arg) = extern_symbol.parameters.get(1) { if let Some(input_arg) = extern_symbol.parameters.get(1) {
return pi_state.eval_parameter_arg(input_arg, self.runtime_memory_image); return pi_state.eval_parameter_arg(input_arg, &self.project.runtime_memory_image);
} }
Err(anyhow!("No input values")) Err(anyhow!("No input values"))
......
...@@ -25,7 +25,6 @@ impl<'a, T: AbstractDomain + DomainInsertion + HasTop + Eq + From<String>> Conte ...@@ -25,7 +25,6 @@ impl<'a, T: AbstractDomain + DomainInsertion + HasTop + Eq + From<String>> Conte
pi_state, pi_state,
extern_symbol, extern_symbol,
&self.format_string_index_map, &self.format_string_index_map,
self.runtime_memory_image,
) { ) {
self.create_abstract_domain_entries_for_function_return_values( self.create_abstract_domain_entries_for_function_return_values(
pi_state, pi_state,
...@@ -47,7 +46,8 @@ impl<'a, T: AbstractDomain + DomainInsertion + HasTop + Eq + From<String>> Conte ...@@ -47,7 +46,8 @@ impl<'a, T: AbstractDomain + DomainInsertion + HasTop + Eq + From<String>> Conte
) { ) {
for (argument, value) in arg_to_value_map.into_iter() { for (argument, value) in arg_to_value_map.into_iter() {
if argument.get_data_type().unwrap() == Datatype::Pointer { if argument.get_data_type().unwrap() == Datatype::Pointer {
if let Ok(data) = pi_state.eval_parameter_arg(&argument, self.runtime_memory_image) if let Ok(data) =
pi_state.eval_parameter_arg(&argument, &self.project.runtime_memory_image)
{ {
if !data.get_relative_values().is_empty() { if !data.get_relative_values().is_empty() {
Context::add_constant_or_top_value_to_return_locations( Context::add_constant_or_top_value_to_return_locations(
...@@ -91,8 +91,8 @@ impl<'a, T: AbstractDomain + DomainInsertion + HasTop + Eq + From<String>> Conte ...@@ -91,8 +91,8 @@ impl<'a, T: AbstractDomain + DomainInsertion + HasTop + Eq + From<String>> Conte
let mut new_state = state.clone(); let mut new_state = state.clone();
if let Some(pi_state) = state.get_pointer_inference_state() { if let Some(pi_state) = state.get_pointer_inference_state() {
if let Some(source_string_arg) = extern_symbol.parameters.first() { if let Some(source_string_arg) = extern_symbol.parameters.first() {
if let Ok(source_string) = if let Ok(source_string) = pi_state
pi_state.eval_parameter_arg(source_string_arg, self.runtime_memory_image) .eval_parameter_arg(source_string_arg, &self.project.runtime_memory_image)
{ {
if self.source_string_mapped_to_return_locations( if self.source_string_mapped_to_return_locations(
pi_state, pi_state,
...@@ -120,11 +120,15 @@ impl<'a, T: AbstractDomain + DomainInsertion + HasTop + Eq + From<String>> Conte ...@@ -120,11 +120,15 @@ impl<'a, T: AbstractDomain + DomainInsertion + HasTop + Eq + From<String>> Conte
extern_symbol: &ExternSymbol, extern_symbol: &ExternSymbol,
) -> bool { ) -> bool {
if let Some(global_address) = source_string.get_absolute_value() { if let Some(global_address) = source_string.get_absolute_value() {
if let Ok(source_string) = self.runtime_memory_image.read_string_until_null_terminator( if let Ok(source_string) = self
&global_address .project
.try_to_bitvec() .runtime_memory_image
.expect("Could not translate interval address to bitvector."), .read_string_until_null_terminator(
) { &global_address
.try_to_bitvec()
.expect("Could not translate interval address to bitvector."),
)
{
if let Ok(source_return_string_map) = self if let Ok(source_return_string_map) = self
.map_source_string_parameters_to_return_arguments( .map_source_string_parameters_to_return_arguments(
pi_state, pi_state,
...@@ -158,7 +162,6 @@ impl<'a, T: AbstractDomain + DomainInsertion + HasTop + Eq + From<String>> Conte ...@@ -158,7 +162,6 @@ impl<'a, T: AbstractDomain + DomainInsertion + HasTop + Eq + From<String>> Conte
pi_state, pi_state,
extern_symbol, extern_symbol,
&self.format_string_index_map, &self.format_string_index_map,
self.runtime_memory_image,
) { ) {
let return_values: Vec<String> = let return_values: Vec<String> =
source_string.split(' ').map(|s| s.to_string()).collect(); source_string.split(' ').map(|s| s.to_string()).collect();
......
...@@ -25,7 +25,7 @@ impl<'a, T: AbstractDomain + DomainInsertion + HasTop + Eq + From<String>> Conte ...@@ -25,7 +25,7 @@ impl<'a, T: AbstractDomain + DomainInsertion + HasTop + Eq + From<String>> Conte
if let Some(return_arg) = extern_symbol.parameters.first() { if let Some(return_arg) = extern_symbol.parameters.first() {
if let Some(pi_state) = state.get_pointer_inference_state() { if let Some(pi_state) = state.get_pointer_inference_state() {
if let Ok(return_pointer) = if let Ok(return_pointer) =
pi_state.eval_parameter_arg(return_arg, self.runtime_memory_image) pi_state.eval_parameter_arg(return_arg, &self.project.runtime_memory_image)
{ {
if !return_pointer.get_relative_values().is_empty() { if !return_pointer.get_relative_values().is_empty() {
let format_string_index = self let format_string_index = self
...@@ -63,7 +63,7 @@ impl<'a, T: AbstractDomain + DomainInsertion + HasTop + Eq + From<String>> Conte ...@@ -63,7 +63,7 @@ impl<'a, T: AbstractDomain + DomainInsertion + HasTop + Eq + From<String>> Conte
pi_state, pi_state,
extern_symbol, extern_symbol,
format_string_index, format_string_index,
self.runtime_memory_image, &self.project.runtime_memory_image,
) { ) {
let returned_abstract_domain = self.create_string_domain_for_sprintf_snprintf( let returned_abstract_domain = self.create_string_domain_for_sprintf_snprintf(
pi_state, pi_state,
...@@ -105,7 +105,6 @@ impl<'a, T: AbstractDomain + DomainInsertion + HasTop + Eq + From<String>> Conte ...@@ -105,7 +105,6 @@ impl<'a, T: AbstractDomain + DomainInsertion + HasTop + Eq + From<String>> Conte
pi_state, pi_state,
extern_symbol, extern_symbol,
&self.format_string_index_map, &self.format_string_index_map,
self.runtime_memory_image,
) { ) {
Ok(var_args) => { Ok(var_args) => {
if var_args.is_empty() { if var_args.is_empty() {
...@@ -258,7 +257,7 @@ impl<'a, T: AbstractDomain + DomainInsertion + HasTop + Eq + From<String>> Conte ...@@ -258,7 +257,7 @@ impl<'a, T: AbstractDomain + DomainInsertion + HasTop + Eq + From<String>> Conte
pi_state: &PointerInferenceState, pi_state: &PointerInferenceState,
state: &State<T>, state: &State<T>,
) -> T { ) -> T {
if let Ok(data) = pi_state.eval_parameter_arg(arg, self.runtime_memory_image) { if let Ok(data) = pi_state.eval_parameter_arg(arg, &self.project.runtime_memory_image) {
let constant_domain: Option<T> = self.fetch_constant_domain_if_available(&data, arg); let constant_domain: Option<T> = self.fetch_constant_domain_if_available(&data, arg);
if let Some(generated_domain) = Context::<T>::fetch_subdomains_if_available( if let Some(generated_domain) = Context::<T>::fetch_subdomains_if_available(
&data, &data,
......
...@@ -17,7 +17,7 @@ impl<'a, T: AbstractDomain + DomainInsertion + HasTop + Eq + From<String>> Conte ...@@ -17,7 +17,7 @@ impl<'a, T: AbstractDomain + DomainInsertion + HasTop + Eq + From<String>> Conte
if let Some(pi_state) = state.get_pointer_inference_state() { if let Some(pi_state) = state.get_pointer_inference_state() {
if let Some(return_arg) = extern_symbol.parameters.first() { if let Some(return_arg) = extern_symbol.parameters.first() {
if let Ok(return_pointer) = if let Ok(return_pointer) =
pi_state.eval_parameter_arg(return_arg, self.runtime_memory_image) pi_state.eval_parameter_arg(return_arg, &self.project.runtime_memory_image)
{ {
if !return_pointer.get_relative_values().is_empty() { if !return_pointer.get_relative_values().is_empty() {
let target_domain = let target_domain =
...@@ -64,7 +64,7 @@ impl<'a, T: AbstractDomain + DomainInsertion + HasTop + Eq + From<String>> Conte ...@@ -64,7 +64,7 @@ impl<'a, T: AbstractDomain + DomainInsertion + HasTop + Eq + From<String>> Conte
let mut input_domain = T::create_top_value_domain(); let mut input_domain = T::create_top_value_domain();
if let Some(input_arg) = extern_symbol.parameters.get(1) { if let Some(input_arg) = extern_symbol.parameters.get(1) {
if let Ok(input_value) = if let Ok(input_value) =
pi_state.eval_parameter_arg(input_arg, self.runtime_memory_image) pi_state.eval_parameter_arg(input_arg, &self.project.runtime_memory_image)
{ {
// Check whether the second input string is in read only memory or on stack/heap. // Check whether the second input string is in read only memory or on stack/heap.
if !input_value.get_relative_values().is_empty() { if !input_value.get_relative_values().is_empty() {
...@@ -78,6 +78,7 @@ impl<'a, T: AbstractDomain + DomainInsertion + HasTop + Eq + From<String>> Conte ...@@ -78,6 +78,7 @@ impl<'a, T: AbstractDomain + DomainInsertion + HasTop + Eq + From<String>> Conte
if let Some(value) = input_value.get_absolute_value() { if let Some(value) = input_value.get_absolute_value() {
if let Ok(global_address) = value.try_to_bitvec() { if let Ok(global_address) = value.try_to_bitvec() {
if let Ok(input_string) = self if let Ok(input_string) = self
.project
.runtime_memory_image .runtime_memory_image
.read_string_until_null_terminator(&global_address) .read_string_until_null_terminator(&global_address)
{ {
......
...@@ -61,7 +61,6 @@ impl<'a, T: AbstractDomain + DomainInsertion + HasTop + Eq + From<String> + Debu ...@@ -61,7 +61,6 @@ impl<'a, T: AbstractDomain + DomainInsertion + HasTop + Eq + From<String> + Debu
mock_string_symbol_map(&pi_context.project), mock_string_symbol_map(&pi_context.project),
mock_format_index_map(), mock_format_index_map(),
&pi_results, &pi_results,
&pi_context.runtime_memory_image,
); );
let state_before_call: State<T> = State::mock_with_given_pi_state( let state_before_call: State<T> = State::mock_with_given_pi_state(
......
...@@ -6,7 +6,6 @@ impl<'a, T: AbstractDomain + DomainInsertion + HasTop + Eq + From<String>> Conte ...@@ -6,7 +6,6 @@ impl<'a, T: AbstractDomain + DomainInsertion + HasTop + Eq + From<String>> Conte
string_symbols: HashMap<Tid, &'a ExternSymbol>, string_symbols: HashMap<Tid, &'a ExternSymbol>,
format_string_index: HashMap<String, usize>, format_string_index: HashMap<String, usize>,
pointer_inference_results: &'a PointerInferenceComputation<'a>, pointer_inference_results: &'a PointerInferenceComputation<'a>,
runtime_memory_image: &'a RuntimeMemoryImage,
) -> Self { ) -> Self {
let mut extern_symbol_map = HashMap::new(); let mut extern_symbol_map = HashMap::new();
for (tid, symbol) in project.program.term.extern_symbols.iter() { for (tid, symbol) in project.program.term.extern_symbols.iter() {
...@@ -35,7 +34,6 @@ impl<'a, T: AbstractDomain + DomainInsertion + HasTop + Eq + From<String>> Conte ...@@ -35,7 +34,6 @@ impl<'a, T: AbstractDomain + DomainInsertion + HasTop + Eq + From<String>> Conte
Context { Context {
project, project,
runtime_memory_image,
pointer_inference_results, pointer_inference_results,
string_symbol_map: string_symbols, string_symbol_map: string_symbols,
extern_symbol_map, extern_symbol_map,
......
...@@ -46,7 +46,7 @@ impl<'a, T: AbstractDomain + DomainInsertion + HasTop + Eq + From<String>> ...@@ -46,7 +46,7 @@ impl<'a, T: AbstractDomain + DomainInsertion + HasTop + Eq + From<String>>
new_state.handle_assign_and_load( new_state.handle_assign_and_load(
output, output,
input, input,
self.runtime_memory_image, &self.project.runtime_memory_image,
&self.block_first_def_set, &self.block_first_def_set,
true, true,
); );
...@@ -58,7 +58,7 @@ impl<'a, T: AbstractDomain + DomainInsertion + HasTop + Eq + From<String>> ...@@ -58,7 +58,7 @@ impl<'a, T: AbstractDomain + DomainInsertion + HasTop + Eq + From<String>>
new_state.handle_assign_and_load( new_state.handle_assign_and_load(
output, output,
input, input,
self.runtime_memory_image, &self.project.runtime_memory_image,
&self.block_first_def_set, &self.block_first_def_set,
false, false,
); );
...@@ -66,7 +66,7 @@ impl<'a, T: AbstractDomain + DomainInsertion + HasTop + Eq + From<String>> ...@@ -66,7 +66,7 @@ impl<'a, T: AbstractDomain + DomainInsertion + HasTop + Eq + From<String>>
Def::Store { address, value } => new_state.handle_store( Def::Store { address, value } => new_state.handle_store(
address, address,
value, value,
self.runtime_memory_image, &self.project.runtime_memory_image,
&self.block_first_def_set, &self.block_first_def_set,
), ),
} }
......
...@@ -13,7 +13,6 @@ use crate::{ ...@@ -13,7 +13,6 @@ use crate::{
}, },
}, },
intermediate_representation::{Bitvector, Blk, ByteSize, ExternSymbol, Jmp, Tid, Variable}, intermediate_representation::{Bitvector, Blk, ByteSize, ExternSymbol, Jmp, Tid, Variable},
utils::binary::RuntimeMemoryImage,
}; };
#[test] #[test]
...@@ -23,7 +22,6 @@ fn test_update_def() { ...@@ -23,7 +22,6 @@ fn test_update_def() {
vec![(memcpy_symbol.clone(), vec![true])], vec![(memcpy_symbol.clone(), vec![true])],
"func", "func",
); );
let mem_image = RuntimeMemoryImage::mock();
let mut pi_results = PointerInferenceComputation::mock(&project); let mut pi_results = PointerInferenceComputation::mock(&project);
pi_results.compute(false); pi_results.compute(false);
...@@ -62,7 +60,7 @@ fn test_update_def() { ...@@ -62,7 +60,7 @@ fn test_update_def() {
let _ = setup.pi_state_before_symbol_call.store_value( let _ = setup.pi_state_before_symbol_call.store_value(
&pointer_to_pointer, &pointer_to_pointer,
&loaded_pointer, &loaded_pointer,
&mem_image, &project.runtime_memory_image,
); );
let r2_reg = Variable { let r2_reg = Variable {
......
...@@ -10,7 +10,6 @@ use crate::{ ...@@ -10,7 +10,6 @@ use crate::{
abstract_domain::{AbstractDomain, DomainInsertion, HasTop}, abstract_domain::{AbstractDomain, DomainInsertion, HasTop},
intermediate_representation::Project, intermediate_representation::Project,
prelude::*, prelude::*,
utils::binary::RuntimeMemoryImage,
}; };
use self::state::State; use self::state::State;
...@@ -49,17 +48,11 @@ impl<'a, T: AbstractDomain + DomainInsertion + HasTop + Eq + From<String>> ...@@ -49,17 +48,11 @@ impl<'a, T: AbstractDomain + DomainInsertion + HasTop + Eq + From<String>>
/// Generate a new string abstraction computation for a project. /// Generate a new string abstraction computation for a project.
pub fn new( pub fn new(
project: &'a Project, project: &'a Project,
runtime_memory_image: &'a RuntimeMemoryImage,
control_flow_graph: &'a Graph<'a>, control_flow_graph: &'a Graph<'a>,
pointer_inference_results: &'a PointerInferenceComputation<'a>, pointer_inference_results: &'a PointerInferenceComputation<'a>,
config: Config, config: Config,
) -> StringAbstraction<'a, T> { ) -> StringAbstraction<'a, T> {
let context = Context::new( let context = Context::new(project, pointer_inference_results, config);
project,
runtime_memory_image,
pointer_inference_results,
config,
);
let mut sub_to_entry_blocks_map = HashMap::new(); let mut sub_to_entry_blocks_map = HashMap::new();
for sub in project.program.term.subs.values() { for sub in project.program.term.subs.values() {
...@@ -132,18 +125,12 @@ impl<'a, T: AbstractDomain + DomainInsertion + HasTop + Eq + From<String>> ...@@ -132,18 +125,12 @@ impl<'a, T: AbstractDomain + DomainInsertion + HasTop + Eq + From<String>>
/// Compute the string abstraction and return its results. /// Compute the string abstraction and return its results.
pub fn run<'a, T: AbstractDomain + HasTop + Eq + From<String> + DomainInsertion>( pub fn run<'a, T: AbstractDomain + HasTop + Eq + From<String> + DomainInsertion>(
project: &'a Project, project: &'a Project,
runtime_memory_image: &'a RuntimeMemoryImage,
control_flow_graph: &'a Graph<'a>, control_flow_graph: &'a Graph<'a>,
pointer_inference: &'a PointerInferenceComputation<'a>, pointer_inference: &'a PointerInferenceComputation<'a>,
config: Config, config: Config,
) -> StringAbstraction<'a, T> { ) -> StringAbstraction<'a, T> {
let mut string_abstraction = StringAbstraction::new( let mut string_abstraction =
project, StringAbstraction::new(project, control_flow_graph, pointer_inference, config);
runtime_memory_image,
control_flow_graph,
pointer_inference,
config,
);
string_abstraction.compute(); string_abstraction.compute();
......
...@@ -9,14 +9,13 @@ use itertools::Itertools; ...@@ -9,14 +9,13 @@ use itertools::Itertools;
use petgraph::graph::NodeIndex; use petgraph::graph::NodeIndex;
use crate::abstract_domain::{DataDomain, DomainInsertion, HasTop, TryToBitvec}; use crate::abstract_domain::{DataDomain, DomainInsertion, HasTop, TryToBitvec};
use crate::intermediate_representation::{ExternSymbol, Project}; use crate::intermediate_representation::{ExternSymbol, Project, RuntimeMemoryImage};
use crate::{abstract_domain::IntervalDomain, prelude::*}; use crate::{abstract_domain::IntervalDomain, prelude::*};
use crate::{ use crate::{
abstract_domain::{AbstractDomain, AbstractIdentifier}, abstract_domain::{AbstractDomain, AbstractIdentifier},
analysis::pointer_inference::PointerInference as PointerInferenceComputation, analysis::pointer_inference::PointerInference as PointerInferenceComputation,
analysis::pointer_inference::State as PointerInferenceState, analysis::pointer_inference::State as PointerInferenceState,
intermediate_representation::{Expression, Sub, Variable}, intermediate_representation::{Expression, Sub, Variable},
utils::binary::RuntimeMemoryImage,
}; };
/// Contains all information known about the state of a program at a specific point of time. /// Contains all information known about the state of a program at a specific point of time.
......
...@@ -31,8 +31,8 @@ use crate::analysis::interprocedural_fixpoint_generic::NodeValue; ...@@ -31,8 +31,8 @@ use crate::analysis::interprocedural_fixpoint_generic::NodeValue;
use crate::analysis::pointer_inference::PointerInference; use crate::analysis::pointer_inference::PointerInference;
use crate::intermediate_representation::ExternSymbol; use crate::intermediate_representation::ExternSymbol;
use crate::intermediate_representation::Jmp; use crate::intermediate_representation::Jmp;
use crate::intermediate_representation::RuntimeMemoryImage;
use crate::prelude::*; use crate::prelude::*;
use crate::utils::binary::RuntimeMemoryImage;
use crate::utils::log::CweWarning; use crate::utils::log::CweWarning;
use crate::utils::log::LogMessage; use crate::utils::log::LogMessage;
use crate::CweModule; use crate::CweModule;
...@@ -91,7 +91,7 @@ pub fn check_cwe( ...@@ -91,7 +91,7 @@ pub fn check_cwe(
symbol, symbol,
&format_string_index, &format_string_index,
pointer_inference_results, pointer_inference_results,
analysis_results.runtime_memory_image, &analysis_results.project.runtime_memory_image,
); );
if matches!( if matches!(
...@@ -219,7 +219,6 @@ pub mod tests { ...@@ -219,7 +219,6 @@ pub mod tests {
#[test] #[test]
fn test_locate_format_string() { fn test_locate_format_string() {
let sprintf_symbol = ExternSymbol::mock_string(); let sprintf_symbol = ExternSymbol::mock_string();
let runtime_memory_image = RuntimeMemoryImage::mock();
let project = mock_project(); let project = mock_project();
let graph = crate::analysis::graph::get_program_cfg(&project.program, HashSet::new()); let graph = crate::analysis::graph::get_program_cfg(&project.program, HashSet::new());
let mut pi_results = PointerInferenceComputation::mock(&project); let mut pi_results = PointerInferenceComputation::mock(&project);
...@@ -241,7 +240,7 @@ pub mod tests { ...@@ -241,7 +240,7 @@ pub mod tests {
&sprintf_symbol, &sprintf_symbol,
&format_string_index, &format_string_index,
&pi_results, &pi_results,
&runtime_memory_image, &project.runtime_memory_image,
), ),
StringLocation::GlobalReadable StringLocation::GlobalReadable
); );
......
...@@ -24,7 +24,6 @@ use crate::abstract_domain::TryToBitvec; ...@@ -24,7 +24,6 @@ use crate::abstract_domain::TryToBitvec;
use crate::analysis::pointer_inference::State; use crate::analysis::pointer_inference::State;
use crate::intermediate_representation::*; use crate::intermediate_representation::*;
use crate::prelude::*; use crate::prelude::*;
use crate::utils::binary::RuntimeMemoryImage;
use crate::utils::log::{CweWarning, LogMessage}; use crate::utils::log::{CweWarning, LogMessage};
use crate::utils::symbol_utils::{get_callsites, get_symbol_map}; use crate::utils::symbol_utils::{get_callsites, get_symbol_map};
use crate::CweModule; use crate::CweModule;
...@@ -45,24 +44,20 @@ pub struct Config { ...@@ -45,24 +44,20 @@ pub struct Config {
/// Compute the program state at the end of the given basic block /// Compute the program state at the end of the given basic block
/// assuming nothing is known about the state at the start of the block. /// assuming nothing is known about the state at the start of the block.
fn compute_block_end_state( fn compute_block_end_state(project: &Project, block: &Term<Blk>) -> State {
project: &Project,
global_memory: &RuntimeMemoryImage,
block: &Term<Blk>,
) -> State {
let stack_register = &project.stack_pointer_register; let stack_register = &project.stack_pointer_register;
let mut state = State::new(stack_register, block.tid.clone()); let mut state = State::new(stack_register, block.tid.clone());
for def in block.term.defs.iter() { for def in block.term.defs.iter() {
match &def.term { match &def.term {
Def::Store { address, value } => { Def::Store { address, value } => {
let _ = state.handle_store(address, value, global_memory); let _ = state.handle_store(address, value, &project.runtime_memory_image);
} }
Def::Assign { var, value } => { Def::Assign { var, value } => {
let _ = state.handle_register_assign(var, value); let _ = state.handle_register_assign(var, value);
} }
Def::Load { var, address } => { Def::Load { var, address } => {
let _ = state.handle_load(var, address, global_memory); let _ = state.handle_load(var, address, &project.runtime_memory_image);
} }
} }
} }
...@@ -72,14 +67,13 @@ fn compute_block_end_state( ...@@ -72,14 +67,13 @@ fn compute_block_end_state(
/// Check whether a parameter value of the call to `symbol` has value `sizeof(void*)`. /// Check whether a parameter value of the call to `symbol` has value `sizeof(void*)`.
fn check_for_pointer_sized_arg( fn check_for_pointer_sized_arg(
project: &Project, project: &Project,
global_memory: &RuntimeMemoryImage,
block: &Term<Blk>, block: &Term<Blk>,
symbol: &ExternSymbol, symbol: &ExternSymbol,
) -> bool { ) -> bool {
let pointer_size = project.stack_pointer_register.size; let pointer_size = project.stack_pointer_register.size;
let state = compute_block_end_state(project, global_memory, block); let state = compute_block_end_state(project, block);
for parameter in symbol.parameters.iter() { for parameter in symbol.parameters.iter() {
if let Ok(param) = state.eval_parameter_arg(parameter, global_memory) { if let Ok(param) = state.eval_parameter_arg(parameter, &project.runtime_memory_image) {
if let Ok(param_value) = param.try_to_bitvec() { if let Ok(param_value) = param.try_to_bitvec() {
if Ok(u64::from(pointer_size)) == param_value.try_to_u64() { if Ok(u64::from(pointer_size)) == param_value.try_to_u64() {
return true; return true;
...@@ -120,12 +114,7 @@ pub fn check_cwe( ...@@ -120,12 +114,7 @@ pub fn check_cwe(
let symbol_map = get_symbol_map(project, &config.symbols); let symbol_map = get_symbol_map(project, &config.symbols);
for sub in project.program.term.subs.values() { for sub in project.program.term.subs.values() {
for (block, jmp, symbol) in get_callsites(sub, &symbol_map) { for (block, jmp, symbol) in get_callsites(sub, &symbol_map) {
if check_for_pointer_sized_arg( if check_for_pointer_sized_arg(project, block, symbol) {
project,
analysis_results.runtime_memory_image,
block,
symbol,
) {
cwe_warnings.push(generate_cwe_warning(jmp, symbol)) cwe_warnings.push(generate_cwe_warning(jmp, symbol))
} }
} }
......
...@@ -85,12 +85,7 @@ pub fn check_cwe( ...@@ -85,12 +85,7 @@ pub fn check_cwe(
let config: Config = serde_json::from_value(cwe_params.clone()).unwrap(); let config: Config = serde_json::from_value(cwe_params.clone()).unwrap();
let symbol_map = crate::utils::symbol_utils::get_symbol_map(project, &config.symbols[..]); let symbol_map = crate::utils::symbol_utils::get_symbol_map(project, &config.symbols[..]);
let general_context = Context::new( let general_context = Context::new(project, pointer_inference_results, cwe_sender);
project,
analysis_results.runtime_memory_image,
pointer_inference_results,
cwe_sender,
);
for edge in general_context.get_graph().edge_references() { for edge in general_context.get_graph().edge_references() {
if let Edge::ExternCallStub(jmp) = edge.weight() { if let Edge::ExternCallStub(jmp) = edge.weight() {
......
...@@ -8,7 +8,6 @@ use crate::analysis::interprocedural_fixpoint_generic::NodeValue; ...@@ -8,7 +8,6 @@ use crate::analysis::interprocedural_fixpoint_generic::NodeValue;
use crate::analysis::pointer_inference::PointerInference as PointerInferenceComputation; use crate::analysis::pointer_inference::PointerInference as PointerInferenceComputation;
use crate::analysis::pointer_inference::State as PointerInferenceState; use crate::analysis::pointer_inference::State as PointerInferenceState;
use crate::intermediate_representation::*; use crate::intermediate_representation::*;
use crate::utils::binary::RuntimeMemoryImage;
use crate::utils::log::CweWarning; use crate::utils::log::CweWarning;
use petgraph::graph::NodeIndex; use petgraph::graph::NodeIndex;
use petgraph::visit::IntoNodeReferences; use petgraph::visit::IntoNodeReferences;
...@@ -26,8 +25,6 @@ use std::sync::Arc; ...@@ -26,8 +25,6 @@ use std::sync::Arc;
pub struct Context<'a> { pub struct Context<'a> {
/// A pointer to the corresponding project struct. /// A pointer to the corresponding project struct.
project: &'a Project, project: &'a Project,
/// A pointer to the representation of the runtime memory image.
runtime_memory_image: &'a RuntimeMemoryImage,
/// A pointer to the results of the pointer inference analysis. /// A pointer to the results of the pointer inference analysis.
/// They are used to determine the targets of pointers to memory, /// They are used to determine the targets of pointers to memory,
/// which in turn is used to keep track of taint on the stack or on the heap. /// which in turn is used to keep track of taint on the stack or on the heap.
...@@ -64,7 +61,6 @@ impl<'a> Context<'a> { ...@@ -64,7 +61,6 @@ impl<'a> Context<'a> {
/// since this function can be expensive! /// since this function can be expensive!
pub fn new( pub fn new(
project: &'a Project, project: &'a Project,
runtime_memory_image: &'a RuntimeMemoryImage,
pointer_inference_results: &'a PointerInferenceComputation<'a>, pointer_inference_results: &'a PointerInferenceComputation<'a>,
cwe_collector: crossbeam_channel::Sender<CweWarning>, cwe_collector: crossbeam_channel::Sender<CweWarning>,
) -> Self { ) -> Self {
...@@ -92,7 +88,6 @@ impl<'a> Context<'a> { ...@@ -92,7 +88,6 @@ impl<'a> Context<'a> {
} }
Context { Context {
project, project,
runtime_memory_image,
pointer_inference_results, pointer_inference_results,
block_start_node_map: Arc::new(block_start_node_map), block_start_node_map: Arc::new(block_start_node_map),
extern_symbol_map: Arc::new(extern_symbol_map), extern_symbol_map: Arc::new(extern_symbol_map),
...@@ -203,8 +198,8 @@ impl<'a> Context<'a> { ...@@ -203,8 +198,8 @@ impl<'a> Context<'a> {
{ {
return true; return true;
} }
if let Ok(stack_param) = if let Ok(stack_param) = pi_state
pi_state.eval_parameter_arg(parameter, self.runtime_memory_image) .eval_parameter_arg(parameter, &self.project.runtime_memory_image)
{ {
if state.check_if_address_points_to_taint(stack_param, pi_state) { if state.check_if_address_points_to_taint(stack_param, pi_state) {
return true; return true;
...@@ -417,16 +412,14 @@ impl<'a> crate::analysis::forward_interprocedural_fixpoint::Context<'a> for Cont ...@@ -417,16 +412,14 @@ impl<'a> crate::analysis::forward_interprocedural_fixpoint::Context<'a> for Cont
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::*; use super::*;
use crate::utils::binary::RuntimeMemoryImage;
impl<'a> Context<'a> { impl<'a> Context<'a> {
pub fn mock( pub fn mock(
project: &'a Project, project: &'a Project,
runtime_memory_image: &'a RuntimeMemoryImage,
pi_results: &'a PointerInferenceComputation<'a>, pi_results: &'a PointerInferenceComputation<'a>,
) -> Context<'a> { ) -> Context<'a> {
let (cwe_sender, _) = crossbeam_channel::unbounded(); let (cwe_sender, _) = crossbeam_channel::unbounded();
let mut context = Context::new(project, runtime_memory_image, pi_results, cwe_sender); let mut context = Context::new(project, pi_results, cwe_sender);
let taint_source = Box::new(Term { let taint_source = Box::new(Term {
tid: Tid::new("taint_source"), tid: Tid::new("taint_source"),
term: Jmp::Call { term: Jmp::Call {
...@@ -445,9 +438,8 @@ mod tests { ...@@ -445,9 +438,8 @@ mod tests {
#[test] #[test]
fn check_parameter_arg_for_taint() { fn check_parameter_arg_for_taint() {
let project = Project::mock_x64(); let project = Project::mock_x64();
let runtime_memory_image = RuntimeMemoryImage::mock();
let pi_results = PointerInferenceComputation::mock(&project); let pi_results = PointerInferenceComputation::mock(&project);
let context = Context::mock(&project, &runtime_memory_image, &pi_results); let context = Context::mock(&project, &pi_results);
let (mut state, _pi_state) = State::mock_with_pi_state(); let (mut state, _pi_state) = State::mock_with_pi_state();
assert_eq!( assert_eq!(
...@@ -476,9 +468,8 @@ mod tests { ...@@ -476,9 +468,8 @@ mod tests {
#[test] #[test]
fn handle_generic_call() { fn handle_generic_call() {
let project = Project::mock_x64(); let project = Project::mock_x64();
let runtime_memory_image = RuntimeMemoryImage::mock();
let pi_results = PointerInferenceComputation::mock(&project); let pi_results = PointerInferenceComputation::mock(&project);
let context = Context::mock(&project, &runtime_memory_image, &pi_results); let context = Context::mock(&project, &pi_results);
let mut state = State::mock(); let mut state = State::mock();
assert!(context assert!(context
...@@ -497,9 +488,8 @@ mod tests { ...@@ -497,9 +488,8 @@ mod tests {
#[test] #[test]
fn update_def() { fn update_def() {
let project = Project::mock_x64(); let project = Project::mock_x64();
let runtime_memory_image = RuntimeMemoryImage::mock();
let pi_results = PointerInferenceComputation::mock(&project); let pi_results = PointerInferenceComputation::mock(&project);
let context = Context::mock(&project, &runtime_memory_image, &pi_results); let context = Context::mock(&project, &pi_results);
let (mut state, pi_state) = State::mock_with_pi_state(); let (mut state, pi_state) = State::mock_with_pi_state();
state.set_pointer_inference_state(Some(pi_state)); state.set_pointer_inference_state(Some(pi_state));
...@@ -550,9 +540,8 @@ mod tests { ...@@ -550,9 +540,8 @@ mod tests {
#[test] #[test]
fn update_jump() { fn update_jump() {
let project = Project::mock_x64(); let project = Project::mock_x64();
let runtime_memory_image = RuntimeMemoryImage::mock();
let pi_results = PointerInferenceComputation::mock(&project); let pi_results = PointerInferenceComputation::mock(&project);
let context = Context::mock(&project, &runtime_memory_image, &pi_results); let context = Context::mock(&project, &pi_results);
let (state, _pi_state) = State::mock_with_pi_state(); let (state, _pi_state) = State::mock_with_pi_state();
let jump = Term { let jump = Term {
......
...@@ -26,7 +26,6 @@ use crate::abstract_domain::TryToBitvec; ...@@ -26,7 +26,6 @@ use crate::abstract_domain::TryToBitvec;
use crate::analysis::pointer_inference::State; use crate::analysis::pointer_inference::State;
use crate::intermediate_representation::*; use crate::intermediate_representation::*;
use crate::prelude::*; use crate::prelude::*;
use crate::utils::binary::RuntimeMemoryImage;
use crate::utils::log::{CweWarning, LogMessage}; use crate::utils::log::{CweWarning, LogMessage};
use crate::utils::symbol_utils::{get_callsites, get_symbol_map}; use crate::utils::symbol_utils::{get_callsites, get_symbol_map};
use crate::CweModule; use crate::CweModule;
...@@ -50,7 +49,6 @@ fn get_umask_permission_arg( ...@@ -50,7 +49,6 @@ fn get_umask_permission_arg(
block: &Term<Blk>, block: &Term<Blk>,
umask_symbol: &ExternSymbol, umask_symbol: &ExternSymbol,
project: &Project, project: &Project,
global_memory: &RuntimeMemoryImage,
) -> Result<u64, Error> { ) -> Result<u64, Error> {
let stack_register = &project.stack_pointer_register; let stack_register = &project.stack_pointer_register;
let mut state = State::new(stack_register, block.tid.clone()); let mut state = State::new(stack_register, block.tid.clone());
...@@ -58,19 +56,19 @@ fn get_umask_permission_arg( ...@@ -58,19 +56,19 @@ fn get_umask_permission_arg(
for def in block.term.defs.iter() { for def in block.term.defs.iter() {
match &def.term { match &def.term {
Def::Store { address, value } => { Def::Store { address, value } => {
let _ = state.handle_store(address, value, global_memory); let _ = state.handle_store(address, value, &project.runtime_memory_image);
} }
Def::Assign { var, value } => { Def::Assign { var, value } => {
let _ = state.handle_register_assign(var, value); let _ = state.handle_register_assign(var, value);
} }
Def::Load { var, address } => { Def::Load { var, address } => {
let _ = state.handle_load(var, address, global_memory); let _ = state.handle_load(var, address, &project.runtime_memory_image);
} }
} }
} }
let parameter = umask_symbol.get_unique_parameter()?; let parameter = umask_symbol.get_unique_parameter()?;
let param_value = state.eval_parameter_arg(parameter, global_memory)?; let param_value = state.eval_parameter_arg(parameter, &project.runtime_memory_image)?;
if let Ok(umask_arg) = param_value.try_to_bitvec() { if let Ok(umask_arg) = param_value.try_to_bitvec() {
Ok(umask_arg.try_to_u64()?) Ok(umask_arg.try_to_u64()?)
} else { } else {
...@@ -115,12 +113,7 @@ pub fn check_cwe( ...@@ -115,12 +113,7 @@ pub fn check_cwe(
if !umask_symbol_map.is_empty() { if !umask_symbol_map.is_empty() {
for sub in project.program.term.subs.values() { for sub in project.program.term.subs.values() {
for (block, jmp, umask_symbol) in get_callsites(sub, &umask_symbol_map) { for (block, jmp, umask_symbol) in get_callsites(sub, &umask_symbol_map) {
match get_umask_permission_arg( match get_umask_permission_arg(block, umask_symbol, project) {
block,
umask_symbol,
project,
analysis_results.runtime_memory_image,
) {
Ok(permission_const) => { Ok(permission_const) => {
if is_chmod_style_arg(permission_const) { if is_chmod_style_arg(permission_const) {
cwes.push(generate_cwe_warning(sub, jmp, permission_const)); cwes.push(generate_cwe_warning(sub, jmp, permission_const));
......
...@@ -45,9 +45,9 @@ use crate::intermediate_representation::Arg; ...@@ -45,9 +45,9 @@ use crate::intermediate_representation::Arg;
use crate::intermediate_representation::Expression; use crate::intermediate_representation::Expression;
use crate::intermediate_representation::ExternSymbol; use crate::intermediate_representation::ExternSymbol;
use crate::intermediate_representation::Jmp; use crate::intermediate_representation::Jmp;
use crate::intermediate_representation::RuntimeMemoryImage;
use crate::intermediate_representation::Sub; use crate::intermediate_representation::Sub;
use crate::prelude::*; use crate::prelude::*;
use crate::utils::binary::RuntimeMemoryImage;
use crate::utils::log::CweWarning; use crate::utils::log::CweWarning;
use crate::utils::log::LogMessage; use crate::utils::log::LogMessage;
...@@ -117,7 +117,10 @@ pub fn check_cwe( ...@@ -117,7 +117,10 @@ pub fn check_cwe(
&jmp.tid, &jmp.tid,
&cwe_sender, &cwe_sender,
&log_sender, &log_sender,
string_abstraction.get_context().runtime_memory_image, &string_abstraction
.get_context()
.project
.runtime_memory_image,
) )
} }
} }
......
...@@ -30,6 +30,8 @@ mod program; ...@@ -30,6 +30,8 @@ mod program;
pub use program::*; pub use program::*;
mod project; mod project;
pub use project::*; pub use project::*;
mod runtime_memory_image;
pub use runtime_memory_image::*;
/// An unsigned number of bytes. /// An unsigned number of bytes.
/// ///
......
use super::*; use super::*;
use crate::utils::log::LogMessage;
use std::collections::{BTreeMap, BTreeSet, HashMap, HashSet}; use std::collections::{BTreeMap, BTreeSet, HashMap, HashSet};
mod block_duplication_normalization; mod block_duplication_normalization;
use crate::utils::log::LogMessage;
use block_duplication_normalization::*; use block_duplication_normalization::*;
/// The `Project` struct is the main data structure representing a binary. /// The `Project` struct is the main data structure representing a binary.
...@@ -24,6 +23,8 @@ pub struct Project { ...@@ -24,6 +23,8 @@ pub struct Project {
pub register_set: BTreeSet<Variable>, pub register_set: BTreeSet<Variable>,
/// Contains the properties of C data types. (e.g. size) /// Contains the properties of C data types. (e.g. size)
pub datatype_properties: DatatypeProperties, pub datatype_properties: DatatypeProperties,
/// Represents the memory after loading the binary.
pub runtime_memory_image: RuntimeMemoryImage,
} }
impl Project { impl Project {
...@@ -319,6 +320,7 @@ mod tests { ...@@ -319,6 +320,7 @@ mod tests {
calling_conventions, calling_conventions,
register_set: integer_register.iter().cloned().collect(), register_set: integer_register.iter().cloned().collect(),
datatype_properties: DatatypeProperties::mock_x64(), datatype_properties: DatatypeProperties::mock_x64(),
runtime_memory_image: RuntimeMemoryImage::mock(),
} }
} }
...@@ -357,6 +359,7 @@ mod tests { ...@@ -357,6 +359,7 @@ mod tests {
)]), )]),
register_set: integer_register.collect(), register_set: integer_register.collect(),
datatype_properties: DatatypeProperties::mock_arm32(), datatype_properties: DatatypeProperties::mock_arm32(),
runtime_memory_image: RuntimeMemoryImage::mock(),
} }
} }
} }
......
...@@ -74,8 +74,8 @@ use analysis::function_signature::FunctionSignature; ...@@ -74,8 +74,8 @@ use analysis::function_signature::FunctionSignature;
use analysis::graph::Graph; use analysis::graph::Graph;
use analysis::pointer_inference::PointerInference; use analysis::pointer_inference::PointerInference;
use analysis::string_abstraction::StringAbstraction; use analysis::string_abstraction::StringAbstraction;
use intermediate_representation::Project; use intermediate_representation::Project;
use utils::binary::RuntimeMemoryImage;
use utils::log::{CweWarning, LogMessage}; use utils::log::{CweWarning, LogMessage};
mod prelude { mod prelude {
...@@ -140,8 +140,6 @@ pub fn get_modules() -> Vec<&'static CweModule> { ...@@ -140,8 +140,6 @@ pub fn get_modules() -> Vec<&'static CweModule> {
pub struct AnalysisResults<'a> { pub struct AnalysisResults<'a> {
/// The content of the binary file /// The content of the binary file
pub binary: &'a [u8], pub binary: &'a [u8],
/// A representation of the runtime memory image of the binary.
pub runtime_memory_image: &'a RuntimeMemoryImage,
/// The computed control flow graph of the program. /// The computed control flow graph of the program.
pub control_flow_graph: &'a Graph<'a>, pub control_flow_graph: &'a Graph<'a>,
/// A pointer to the project struct /// A pointer to the project struct
...@@ -158,13 +156,11 @@ impl<'a> AnalysisResults<'a> { ...@@ -158,13 +156,11 @@ impl<'a> AnalysisResults<'a> {
/// Create a new `AnalysisResults` struct with only the project itself known. /// Create a new `AnalysisResults` struct with only the project itself known.
pub fn new( pub fn new(
binary: &'a [u8], binary: &'a [u8],
runtime_memory_image: &'a RuntimeMemoryImage,
control_flow_graph: &'a Graph<'a>, control_flow_graph: &'a Graph<'a>,
project: &'a Project, project: &'a Project,
) -> AnalysisResults<'a> { ) -> AnalysisResults<'a> {
AnalysisResults { AnalysisResults {
binary, binary,
runtime_memory_image,
control_flow_graph, control_flow_graph,
project, project,
function_signatures: None, function_signatures: None,
...@@ -231,7 +227,6 @@ impl<'a> AnalysisResults<'a> { ...@@ -231,7 +227,6 @@ impl<'a> AnalysisResults<'a> {
) -> StringAbstraction<BricksDomain> { ) -> StringAbstraction<BricksDomain> {
crate::analysis::string_abstraction::run( crate::analysis::string_abstraction::run(
self.project, self.project,
self.runtime_memory_image,
self.control_flow_graph, self.control_flow_graph,
pi_results.unwrap(), pi_results.unwrap(),
serde_json::from_value(config.clone()).unwrap(), serde_json::from_value(config.clone()).unwrap(),
...@@ -264,11 +259,8 @@ mod tests { ...@@ -264,11 +259,8 @@ mod tests {
HashSet::from_iter(project.program.term.extern_symbols.keys().cloned()); HashSet::from_iter(project.program.term.extern_symbols.keys().cloned());
let graph = Box::new(get_program_cfg(&project.program, extern_subs)); let graph = Box::new(get_program_cfg(&project.program, extern_subs));
let graph: &'a Graph = Box::leak(graph); let graph: &'a Graph = Box::leak(graph);
let runtime_mem_image = Box::new(RuntimeMemoryImage::mock());
let runtime_mem_image: &'a RuntimeMemoryImage = Box::leak(runtime_mem_image);
let binary: &'a Vec<u8> = Box::leak(Box::new(Vec::new())); let binary: &'a Vec<u8> = Box::leak(Box::new(Vec::new()));
let analysis_results = AnalysisResults::new(binary, graph, project);
let analysis_results = AnalysisResults::new(binary, runtime_mem_image, graph, project);
let (fn_sigs, _) = analysis_results.compute_function_signatures(); let (fn_sigs, _) = analysis_results.compute_function_signatures();
let fn_sigs: &'a BTreeMap<_, _> = Box::leak(Box::new(fn_sigs)); let fn_sigs: &'a BTreeMap<_, _> = Box::leak(Box::new(fn_sigs));
let analysis_results = analysis_results.with_function_signatures(Some(fn_sigs)); let analysis_results = analysis_results.with_function_signatures(Some(fn_sigs));
......
...@@ -13,6 +13,7 @@ use crate::intermediate_representation::ExternSymbol as IrExternSymbol; ...@@ -13,6 +13,7 @@ use crate::intermediate_representation::ExternSymbol as IrExternSymbol;
use crate::intermediate_representation::Jmp as IrJmp; use crate::intermediate_representation::Jmp as IrJmp;
use crate::intermediate_representation::Program as IrProgram; use crate::intermediate_representation::Program as IrProgram;
use crate::intermediate_representation::Project as IrProject; use crate::intermediate_representation::Project as IrProject;
use crate::intermediate_representation::RuntimeMemoryImage;
use crate::intermediate_representation::Sub as IrSub; use crate::intermediate_representation::Sub as IrSub;
use crate::intermediate_representation::Variable as IrVariable; use crate::intermediate_representation::Variable as IrVariable;
use crate::prelude::*; use crate::prelude::*;
...@@ -870,6 +871,7 @@ impl Project { ...@@ -870,6 +871,7 @@ impl Project {
calling_conventions, calling_conventions,
register_set, register_set,
datatype_properties: self.datatype_properties.clone(), datatype_properties: self.datatype_properties.clone(),
runtime_memory_image: RuntimeMemoryImage::empty(true),
} }
} }
} }
......
//! Handles argument detection by parsing format string arguments during a function call. (e.g. sprintf) //! Handles argument detection by parsing format string arguments during a function call. (e.g. sprintf)
use super::binary::RuntimeMemoryImage;
use crate::prelude::*; use crate::prelude::*;
use crate::{ use crate::{
abstract_domain::{IntervalDomain, TryToBitvec}, abstract_domain::{IntervalDomain, TryToBitvec},
...@@ -105,7 +104,6 @@ pub fn get_variable_parameters( ...@@ -105,7 +104,6 @@ pub fn get_variable_parameters(
pi_state: &PointerInferenceState, pi_state: &PointerInferenceState,
extern_symbol: &ExternSymbol, extern_symbol: &ExternSymbol,
format_string_index_map: &HashMap<String, usize>, format_string_index_map: &HashMap<String, usize>,
runtime_memory_image: &RuntimeMemoryImage,
) -> Result<Vec<Arg>, Error> { ) -> Result<Vec<Arg>, Error> {
let format_string_index = match format_string_index_map.get(&extern_symbol.name) { let format_string_index = match format_string_index_map.get(&extern_symbol.name) {
Some(index) => *index, Some(index) => *index,
...@@ -116,7 +114,7 @@ pub fn get_variable_parameters( ...@@ -116,7 +114,7 @@ pub fn get_variable_parameters(
pi_state, pi_state,
extern_symbol, extern_symbol,
format_string_index, format_string_index,
runtime_memory_image, &project.runtime_memory_image,
); );
if let Ok(format_string) = format_string_results.as_ref() { if let Ok(format_string) = format_string_results.as_ref() {
......
...@@ -9,7 +9,6 @@ fn mock_pi_state() -> PointerInferenceState { ...@@ -9,7 +9,6 @@ fn mock_pi_state() -> PointerInferenceState {
#[test] #[test]
/// Tests extraction of format string parameters '/dev/sd%c%d' and 'cat %s'. /// Tests extraction of format string parameters '/dev/sd%c%d' and 'cat %s'.
fn test_get_variable_parameters() { fn test_get_variable_parameters() {
let mem_image = RuntimeMemoryImage::mock();
let mut pi_state = mock_pi_state(); let mut pi_state = mock_pi_state();
let sprintf_symbol = ExternSymbol::mock_string(); let sprintf_symbol = ExternSymbol::mock_string();
let mut format_string_index_map: HashMap<String, usize> = HashMap::new(); let mut format_string_index_map: HashMap<String, usize> = HashMap::new();
...@@ -38,7 +37,6 @@ fn test_get_variable_parameters() { ...@@ -38,7 +37,6 @@ fn test_get_variable_parameters() {
&pi_state, &pi_state,
&sprintf_symbol, &sprintf_symbol,
&format_string_index_map, &format_string_index_map,
&mem_image,
) )
.unwrap() .unwrap()
); );
...@@ -61,7 +59,6 @@ fn test_get_variable_parameters() { ...@@ -61,7 +59,6 @@ fn test_get_variable_parameters() {
&pi_state, &pi_state,
&sprintf_symbol, &sprintf_symbol,
&format_string_index_map, &format_string_index_map,
&mem_image,
) )
.unwrap() .unwrap()
); );
......
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