Unverified Commit 02864348 by Enkelmann Committed by GitHub

provide control flow graph independently of pointer inference analysis (#146)

parent 5b09cb15
use cwe_checker_rs::analysis::graph;
use cwe_checker_rs::utils::binary::RuntimeMemoryImage;
use cwe_checker_rs::utils::log::print_all_messages;
use cwe_checker_rs::utils::{get_ghidra_plugin_path, read_config_file};
......@@ -155,11 +156,24 @@ fn run_with_ghidra(args: CmdlineArgs) {
// so that other analyses do not have to adjust their addresses.
runtime_memory_image.add_global_memory_offset(project.program.term.address_base_offset);
}
// Generate the control flow graph of the program
let extern_sub_tids = project
.program
.term
.extern_symbols
.iter()
.map(|symbol| symbol.tid.clone())
.collect();
let control_flow_graph = graph::get_program_cfg(&project.program, extern_sub_tids);
let mut analysis_results = AnalysisResults::new(&binary, &runtime_memory_image, &project);
let analysis_results = AnalysisResults::new(
&binary,
&runtime_memory_image,
&control_flow_graph,
&project,
);
let modules_depending_on_pointer_inference =
vec!["CWE78", "CWE243", "CWE367", "CWE476", "Memory"];
let modules_depending_on_pointer_inference = vec!["CWE78", "CWE476", "Memory"];
let pointer_inference_results = if modules
.iter()
.any(|module| modules_depending_on_pointer_inference.contains(&module.name))
......@@ -168,7 +182,8 @@ fn run_with_ghidra(args: CmdlineArgs) {
} else {
None
};
analysis_results = analysis_results.set_pointer_inference(pointer_inference_results.as_ref());
let analysis_results =
analysis_results.set_pointer_inference(pointer_inference_results.as_ref());
// Print debug and then return.
// Right now there is only one debug printing function.
......@@ -177,6 +192,7 @@ fn run_with_ghidra(args: CmdlineArgs) {
cwe_checker_rs::analysis::pointer_inference::run(
&project,
&runtime_memory_image,
&control_flow_graph,
serde_json::from_value(config["Memory"].clone()).unwrap(),
true,
);
......
......@@ -4,7 +4,7 @@ use crate::intermediate_representation::*;
use crate::prelude::*;
use crate::utils::log::*;
use crate::{abstract_domain::*, utils::binary::RuntimeMemoryImage};
use std::collections::{BTreeMap, BTreeSet, HashSet};
use std::collections::{BTreeMap, BTreeSet};
use super::state::State;
use super::{Config, Data, VERSION};
......@@ -18,7 +18,7 @@ mod trait_impls;
/// The struct also implements the `interprocedural_fixpoint::Context` trait to enable the fixpoint computation.
pub struct Context<'a> {
/// The program control flow graph on which the fixpoint will be computed
pub graph: Graph<'a>,
pub graph: &'a Graph<'a>,
/// A reference to the `Project` object representing the binary
pub project: &'a Project,
/// The runtime memory image for reading global read-only variables.
......@@ -44,6 +44,7 @@ impl<'a> Context<'a> {
pub fn new(
project: &'a Project,
runtime_memory_image: &'a RuntimeMemoryImage,
control_flow_graph: &'a Graph<'a>,
config: Config,
log_collector: crossbeam_channel::Sender<LogThreadMsg>,
) -> Context<'a> {
......@@ -51,17 +52,8 @@ impl<'a> Context<'a> {
for symbol in project.program.term.extern_symbols.iter() {
extern_symbol_map.insert(symbol.tid.clone(), symbol);
}
let extern_symbol_tid_set: HashSet<Tid> = project
.program
.term
.extern_symbols
.iter()
.map(|symb| symb.tid.clone())
.collect();
let graph =
crate::analysis::graph::get_program_cfg(&project.program, extern_symbol_tid_set);
Context {
graph,
graph: control_flow_graph,
project,
runtime_memory_image,
extern_symbol_map,
......
use super::*;
use std::collections::HashSet;
fn bv(value: i64) -> BitvectorDomain {
BitvectorDomain::Value(Bitvector::from_i64(value))
......@@ -106,8 +107,9 @@ fn context_problem_implementation() {
let (project, config) = mock_project();
let runtime_memory_image = RuntimeMemoryImage::mock();
let graph = crate::analysis::graph::get_program_cfg(&project.program, HashSet::new());
let (log_sender, _log_receiver) = crossbeam_channel::unbounded();
let context = Context::new(&project, &runtime_memory_image, config, log_sender);
let context = Context::new(&project, &runtime_memory_image, &graph, config, log_sender);
let mut state = State::new(&register("RSP"), Tid::new("main"));
let def = Term {
......@@ -283,9 +285,10 @@ fn update_return() {
use crate::analysis::pointer_inference::object::ObjectType;
use crate::analysis::pointer_inference::Data;
let (project, config) = mock_project();
let graph = crate::analysis::graph::get_program_cfg(&project.program, HashSet::new());
let runtime_memory_image = RuntimeMemoryImage::mock();
let (log_sender, _log_receiver) = crossbeam_channel::unbounded();
let context = Context::new(&project, &runtime_memory_image, config, log_sender);
let context = Context::new(&project, &runtime_memory_image, &graph, config, log_sender);
let state_before_return = State::new(&register("RSP"), Tid::new("callee"));
let mut state_before_return = context
.update_def(
......
......@@ -74,10 +74,17 @@ impl<'a> PointerInference<'a> {
pub fn new(
project: &'a Project,
runtime_memory_image: &'a RuntimeMemoryImage,
control_flow_graph: &'a Graph<'a>,
config: Config,
log_sender: crossbeam_channel::Sender<LogThreadMsg>,
) -> PointerInference<'a> {
let context = Context::new(project, runtime_memory_image, config, log_sender.clone());
let context = Context::new(
project,
runtime_memory_image,
control_flow_graph,
config,
log_sender.clone(),
);
let mut entry_sub_to_entry_blocks_map = HashMap::new();
let subs: HashMap<Tid, &Term<Sub>> = project
......@@ -405,6 +412,7 @@ pub fn extract_pi_analysis_results(
pub fn run<'a>(
project: &'a Project,
runtime_memory_image: &'a RuntimeMemoryImage,
control_flow_graph: &'a Graph<'a>,
config: Config,
print_debug: bool,
) -> PointerInference<'a> {
......@@ -413,6 +421,7 @@ pub fn run<'a>(
let mut computation = PointerInference::new(
project,
runtime_memory_image,
control_flow_graph,
config,
logging_thread.get_msg_sender(),
);
......@@ -474,13 +483,14 @@ mod tests {
pub fn mock(
project: &'a Project,
mem_image: &'a RuntimeMemoryImage,
graph: &'a Graph,
) -> PointerInference<'a> {
let config = Config {
allocation_symbols: vec!["malloc".to_string()],
deallocation_symbols: vec!["free".to_string()],
};
let (log_sender, _) = crossbeam_channel::unbounded();
PointerInference::new(project, mem_image, config, log_sender)
PointerInference::new(project, mem_image, graph, config, log_sender)
}
}
}
......@@ -116,7 +116,7 @@ pub fn check_cwe(
cwe_params: &serde_json::Value,
) -> (Vec<LogMessage>, Vec<CweWarning>) {
let project = analysis_results.project;
let graph = analysis_results.pointer_inference.unwrap().get_graph();
let graph = analysis_results.control_flow_graph;
let config: Config = serde_json::from_value(cwe_params.clone()).unwrap();
let priviledge_dropping_tids: Vec<Tid> = config
......
......@@ -72,7 +72,7 @@ pub fn check_cwe(
) -> (Vec<LogMessage>, Vec<CweWarning>) {
let config: Config = serde_json::from_value(cwe_params.clone()).unwrap();
let project = analysis_results.project;
let graph = analysis_results.pointer_inference.unwrap().get_graph();
let graph = analysis_results.control_flow_graph;
let mut cwe_warnings = Vec::new();
let symbol_map: HashMap<&str, Tid> = project
......
......@@ -426,6 +426,7 @@ impl<'a> crate::analysis::forward_interprocedural_fixpoint::Context<'a> for Cont
mod tests {
use super::*;
use crate::utils::binary::RuntimeMemoryImage;
use std::collections::HashSet;
impl<'a> Context<'a> {
pub fn mock(
......@@ -454,7 +455,8 @@ mod tests {
fn check_parameter_arg_for_taint() {
let project = Project::mock_empty();
let runtime_memory_image = RuntimeMemoryImage::mock();
let pi_results = PointerInferenceComputation::mock(&project, &runtime_memory_image);
let graph = crate::analysis::graph::get_program_cfg(&project.program, HashSet::new());
let pi_results = PointerInferenceComputation::mock(&project, &runtime_memory_image, &graph);
let context = Context::mock(&project, &runtime_memory_image, &pi_results);
let (mut state, _pi_state) = State::mock_with_pi_state();
......@@ -477,7 +479,8 @@ mod tests {
fn handle_generic_call() {
let project = Project::mock_empty();
let runtime_memory_image = RuntimeMemoryImage::mock();
let pi_results = PointerInferenceComputation::mock(&project, &runtime_memory_image);
let graph = crate::analysis::graph::get_program_cfg(&project.program, HashSet::new());
let pi_results = PointerInferenceComputation::mock(&project, &runtime_memory_image, &graph);
let context = Context::mock(&project, &runtime_memory_image, &pi_results);
let mut state = State::mock();
......@@ -498,7 +501,8 @@ mod tests {
fn update_def() {
let project = Project::mock_empty();
let runtime_memory_image = RuntimeMemoryImage::mock();
let pi_results = PointerInferenceComputation::mock(&project, &runtime_memory_image);
let graph = crate::analysis::graph::get_program_cfg(&project.program, HashSet::new());
let pi_results = PointerInferenceComputation::mock(&project, &runtime_memory_image, &graph);
let context = Context::mock(&project, &runtime_memory_image, &pi_results);
let (mut state, pi_state) = State::mock_with_pi_state();
state.set_pointer_inference_state(Some(pi_state));
......@@ -551,7 +555,8 @@ mod tests {
fn update_jump() {
let project = Project::mock_empty();
let runtime_memory_image = RuntimeMemoryImage::mock();
let pi_results = PointerInferenceComputation::mock(&project, &runtime_memory_image);
let graph = crate::analysis::graph::get_program_cfg(&project.program, HashSet::new());
let pi_results = PointerInferenceComputation::mock(&project, &runtime_memory_image, &graph);
let context = Context::mock(&project, &runtime_memory_image, &pi_results);
let (state, _pi_state) = State::mock_with_pi_state();
......
......@@ -7,6 +7,7 @@ Parts of the cwe_checker that are written in Rust.
#[macro_use]
extern crate ocaml;
use crate::analysis::graph::Graph;
use crate::analysis::pointer_inference::PointerInference;
use crate::intermediate_representation::Project;
use crate::utils::binary::RuntimeMemoryImage;
......@@ -79,6 +80,8 @@ pub struct AnalysisResults<'a> {
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.
pub control_flow_graph: &'a Graph<'a>,
/// A pointer to the project struct
pub project: &'a Project,
/// The result of the pointer inference analysis if already computed.
......@@ -90,11 +93,13 @@ impl<'a> AnalysisResults<'a> {
pub fn new(
binary: &'a [u8],
runtime_memory_image: &'a RuntimeMemoryImage,
control_flow_graph: &'a Graph<'a>,
project: &'a Project,
) -> AnalysisResults<'a> {
AnalysisResults {
binary,
runtime_memory_image,
control_flow_graph,
project,
pointer_inference: None,
}
......@@ -102,10 +107,11 @@ impl<'a> AnalysisResults<'a> {
/// Compute the pointer inference analysis.
/// The result gets returned, but not saved to the `AnalysisResults` struct itself.
pub fn compute_pointer_inference(&self, config: &serde_json::Value) -> PointerInference<'a> {
pub fn compute_pointer_inference(&'a self, config: &serde_json::Value) -> PointerInference<'a> {
crate::analysis::pointer_inference::run(
self.project,
self.runtime_memory_image,
self.control_flow_graph,
serde_json::from_value(config.clone()).unwrap(),
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