Unverified Commit 83593fac by Melvin Klimke Committed by GitHub

Runtime optimizations for CWE 78 check (#154)

parent 43b56cd3
...@@ -40,7 +40,7 @@ ...@@ -40,7 +40,7 @@
//! - Missing Taints due to lost track of pointer targets //! - Missing Taints due to lost track of pointer targets
//! - Non tracked function parameters cause incomplete taints that could miss possible dangerous inputs //! - Non tracked function parameters cause incomplete taints that could miss possible dangerous inputs
use std::collections::HashMap; use std::collections::{HashMap, HashSet};
use crate::{ use crate::{
analysis::{ analysis::{
...@@ -48,13 +48,16 @@ use crate::{ ...@@ -48,13 +48,16 @@ use crate::{
graph::{self, Edge, Node}, graph::{self, Edge, Node},
interprocedural_fixpoint_generic::NodeValue, interprocedural_fixpoint_generic::NodeValue,
}, },
intermediate_representation::{Jmp, Project, Sub}, intermediate_representation::{ExternSymbol, Jmp, Project, Sub},
prelude::*, prelude::*,
utils::log::{CweWarning, LogMessage}, utils::log::{CweWarning, LogMessage},
AnalysisResults, CweModule, AnalysisResults, CweModule,
}; };
use petgraph::{graph::NodeIndex, visit::EdgeRef}; use petgraph::{
graph::NodeIndex,
visit::{EdgeRef, IntoNodeReferences},
};
mod state; mod state;
use state::*; use state::*;
...@@ -89,21 +92,25 @@ pub fn check_cwe( ...@@ -89,21 +92,25 @@ pub fn check_cwe(
let project = analysis_results.project; let project = analysis_results.project;
let pointer_inference_results = analysis_results.pointer_inference.unwrap(); let pointer_inference_results = analysis_results.pointer_inference.unwrap();
let mut cwe_78_graph = analysis_results.control_flow_graph.clone();
cwe_78_graph.reverse();
let (cwe_sender, cwe_receiver) = crossbeam_channel::unbounded(); let (cwe_sender, cwe_receiver) = crossbeam_channel::unbounded();
let config: Config = serde_json::from_value(cwe_params.clone()).unwrap(); let config: Config = serde_json::from_value(cwe_params.clone()).unwrap();
let system_symbols = let system_symbols =
crate::utils::symbol_utils::get_symbol_map(project, &config.system_symbols[..]); crate::utils::symbol_utils::get_symbol_map(project, &config.system_symbols[..]);
let string_symbols =
crate::utils::symbol_utils::get_symbol_map(project, &config.string_symbols[..]); let symbol_maps: SymbolMaps = SymbolMaps::new(project, &config);
let user_input_symbols = let block_maps = BlockMaps::new(analysis_results);
crate::utils::symbol_utils::get_symbol_map(project, &config.user_input_symbols[..]);
let general_context = Context::new( let general_context = Context::new(
project, project,
analysis_results.runtime_memory_image, analysis_results.runtime_memory_image,
&pointer_inference_results, std::sync::Arc::new(cwe_78_graph),
string_symbols, pointer_inference_results,
user_input_symbols, std::sync::Arc::new(symbol_maps),
std::sync::Arc::new(block_maps),
cwe_sender, cwe_sender,
); );
...@@ -203,3 +210,89 @@ fn get_entry_sub_to_entry_node_map( ...@@ -203,3 +210,89 @@ fn get_entry_sub_to_entry_node_map(
}) })
.collect() .collect()
} }
/// - string_symbols:
/// - Maps the TID of an extern string related symbol to the corresponding extern symbol struct.
/// - user_input_symbols:
/// - Maps the TID of an extern symbol that take input from the user to the corresponding extern symbol struct.
/// - extern_symbol_map:
/// - Maps the TID of an extern symbol to the extern symbol struct.
pub struct SymbolMaps<'a> {
string_symbol_map: HashMap<Tid, &'a ExternSymbol>,
user_input_symbol_map: HashMap<Tid, &'a ExternSymbol>,
extern_symbol_map: HashMap<Tid, &'a ExternSymbol>,
}
impl<'a> SymbolMaps<'a> {
/// Creates a new instance of the symbol maps struct.
pub fn new(project: &'a Project, config: &Config) -> Self {
let mut extern_symbol_map = HashMap::new();
for symbol in project.program.term.extern_symbols.iter() {
extern_symbol_map.insert(symbol.tid.clone(), symbol);
}
SymbolMaps {
string_symbol_map: crate::utils::symbol_utils::get_symbol_map(
project,
&config.string_symbols[..],
),
user_input_symbol_map: crate::utils::symbol_utils::get_symbol_map(
project,
&config.user_input_symbols[..],
),
extern_symbol_map,
}
}
}
/// - block_first_def_set:
/// - A set containing a given [`Def`] as the first `Def` of the block.
/// The keys are of the form `(Def-TID, Current-Sub-TID)`
/// to distinguish the nodes for blocks contained in more than one function.
/// - block_start_last_def_map:
/// - A map to get the node index of the `BlkStart` node containing a given [`Def`] as the last `Def` of the block.
/// The keys are of the form `(Def-TID, Current-Sub-TID)`
/// to distinguish the nodes for blocks contained in more than one function.
/// - jmp_to_blk_end_node_map:
/// - A map to get the node index of the `BlkEnd` node containing a given [`Jmp`].
/// The keys are of the form `(Jmp-TID, Current-Sub-TID)`
/// to distinguish the nodes for blocks contained in more than one function.
pub struct BlockMaps {
block_first_def_set: HashSet<(Tid, Tid)>,
block_start_last_def_map: HashMap<(Tid, Tid), NodeIndex>,
jmp_to_blk_end_node_map: HashMap<(Tid, Tid), NodeIndex>,
}
impl BlockMaps {
/// Creates a new instance of the block maps struct using the analysis results.
pub fn new(analysis_results: &AnalysisResults) -> Self {
let mut block_first_def_set = HashSet::new();
let mut block_start_last_def_map = HashMap::new();
let mut jmp_to_blk_end_node_map = HashMap::new();
for (node_id, node) in analysis_results.control_flow_graph.node_references() {
match node {
Node::BlkStart(block, sub) => match block.term.defs.len() {
0 => (),
num_of_defs => {
let first_def = block.term.defs.get(0).unwrap();
let last_def = block.term.defs.get(num_of_defs - 1).unwrap();
block_first_def_set.insert((first_def.tid.clone(), sub.tid.clone()));
block_start_last_def_map
.insert((last_def.tid.clone(), sub.tid.clone()), node_id);
}
},
Node::BlkEnd(block, sub) => {
for jmp in block.term.jmps.iter() {
jmp_to_blk_end_node_map.insert((jmp.tid.clone(), sub.tid.clone()), node_id);
}
}
_ => (),
}
}
BlockMaps {
block_first_def_set,
block_start_last_def_map,
jmp_to_blk_end_node_map,
}
}
}
use petgraph::visit::IntoNodeReferences;
use super::*; use super::*;
use crate::analysis::backward_interprocedural_fixpoint::Context as BackwardContext; use crate::analysis::{backward_interprocedural_fixpoint::Context as BackwardContext, graph::Node};
use crate::{ use crate::{
abstract_domain::{DataDomain, PointerDomain, SizedDomain}, abstract_domain::{DataDomain, PointerDomain, SizedDomain},
analysis::pointer_inference::{Data, State as PointerInferenceState, ValueDomain}, analysis::pointer_inference::{Data, State as PointerInferenceState, ValueDomain},
...@@ -111,12 +113,57 @@ impl<'a> Context<'a> { ...@@ -111,12 +113,57 @@ impl<'a> Context<'a> {
mem_image: &'a RuntimeMemoryImage, mem_image: &'a RuntimeMemoryImage,
) -> Self { ) -> Self {
let (cwe_sender, _) = crossbeam_channel::unbounded(); let (cwe_sender, _) = crossbeam_channel::unbounded();
let mut graph = pi_results.get_graph().clone();
graph.reverse();
let mut extern_symbol_map = HashMap::new();
for symbol in project.program.term.extern_symbols.iter() {
extern_symbol_map.insert(symbol.tid.clone(), symbol);
}
let mut block_first_def_set: HashSet<(Tid, Tid)> = HashSet::new();
let mut block_start_last_def_map = HashMap::new();
let mut jmp_to_blk_end_node_map = HashMap::new();
for (node_id, node) in graph.node_references() {
match node {
Node::BlkStart(block, sub) => match block.term.defs.len() {
0 => (),
num_of_defs => {
let first_def = block.term.defs.get(0).unwrap();
let last_def = block.term.defs.get(num_of_defs - 1).unwrap();
block_first_def_set.insert((first_def.tid.clone(), sub.tid.clone()));
block_start_last_def_map
.insert((last_def.tid.clone(), sub.tid.clone()), node_id);
}
},
Node::BlkEnd(block, sub) => {
for jmp in block.term.jmps.iter() {
jmp_to_blk_end_node_map.insert((jmp.tid.clone(), sub.tid.clone()), node_id);
}
}
_ => (),
}
}
let block_maps: BlockMaps = BlockMaps {
block_first_def_set,
block_start_last_def_map,
jmp_to_blk_end_node_map,
};
let symbol_maps: SymbolMaps = SymbolMaps {
string_symbol_map: string_symbols,
user_input_symbol_map: HashMap::new(),
extern_symbol_map,
};
Context::new( Context::new(
project, project,
mem_image, mem_image,
std::sync::Arc::new(graph),
pi_results, pi_results,
string_symbols, std::sync::Arc::new(symbol_maps),
HashMap::new(), std::sync::Arc::new(block_maps),
cwe_sender, cwe_sender,
) )
} }
...@@ -164,6 +211,7 @@ fn tainting_string_function_parameters() { ...@@ -164,6 +211,7 @@ fn tainting_string_function_parameters() {
let context = Context::mock(&setup.project, HashMap::new(), &pi_results, &mem_image); let context = Context::mock(&setup.project, HashMap::new(), &pi_results, &mem_image);
let node_id = context let node_id = context
.block_maps
.jmp_to_blk_end_node_map .jmp_to_blk_end_node_map
.get(&(Tid::new("call_string"), Tid::new("func"))) .get(&(Tid::new("call_string"), Tid::new("func")))
.unwrap(); .unwrap();
...@@ -253,6 +301,7 @@ fn tainting_generic_function_parameters_and_removing_non_callee_saved() { ...@@ -253,6 +301,7 @@ fn tainting_generic_function_parameters_and_removing_non_callee_saved() {
string_syms.insert(Tid::new("sprintf"), &setup.string_sym); string_syms.insert(Tid::new("sprintf"), &setup.string_sym);
let context = Context::mock(&setup.project, string_syms, &pi_results, &mem_image); let context = Context::mock(&setup.project, string_syms, &pi_results, &mem_image);
let node_id = context let node_id = context
.block_maps
.jmp_to_blk_end_node_map .jmp_to_blk_end_node_map
.get(&(Tid::new("call_string"), Tid::new("func"))) .get(&(Tid::new("call_string"), Tid::new("func")))
.unwrap(); .unwrap();
...@@ -327,6 +376,7 @@ fn tainting_stack_parameters() { ...@@ -327,6 +376,7 @@ fn tainting_stack_parameters() {
let context = Context::mock(&setup.project, HashMap::new(), &pi_results, &mem_image); let context = Context::mock(&setup.project, HashMap::new(), &pi_results, &mem_image);
let call_source_node = context let call_source_node = context
.block_maps
.jmp_to_blk_end_node_map .jmp_to_blk_end_node_map
.get(&(Tid::new("call_string"), Tid::new("func"))) .get(&(Tid::new("call_string"), Tid::new("func")))
.unwrap(); .unwrap();
...@@ -366,6 +416,7 @@ fn tainting_parameters() { ...@@ -366,6 +416,7 @@ fn tainting_parameters() {
let context = Context::mock(&setup.project, HashMap::new(), &pi_results, &mem_image); let context = Context::mock(&setup.project, HashMap::new(), &pi_results, &mem_image);
let call_source_node = context let call_source_node = context
.block_maps
.jmp_to_blk_end_node_map .jmp_to_blk_end_node_map
.get(&(Tid::new("call_string"), Tid::new("func"))) .get(&(Tid::new("call_string"), Tid::new("func")))
.unwrap(); .unwrap();
...@@ -407,6 +458,7 @@ fn creating_pi_def_map() { ...@@ -407,6 +458,7 @@ fn creating_pi_def_map() {
let context = Context::mock(&setup.project, HashMap::new(), &pi_results, &mem_image); let context = Context::mock(&setup.project, HashMap::new(), &pi_results, &mem_image);
let current_sub = setup.project.program.term.subs.get(0).unwrap(); let current_sub = setup.project.program.term.subs.get(0).unwrap();
let start_node = context let start_node = context
.block_maps
.block_start_last_def_map .block_start_last_def_map
.get(&(def2.clone(), current_sub.tid.clone())) .get(&(def2.clone(), current_sub.tid.clone()))
.unwrap(); .unwrap();
...@@ -452,6 +504,7 @@ fn getting_blk_start_node_if_last_def() { ...@@ -452,6 +504,7 @@ fn getting_blk_start_node_if_last_def() {
setup.state.set_current_sub(current_sub); setup.state.set_current_sub(current_sub);
let start_node = context let start_node = context
.block_maps
.block_start_last_def_map .block_start_last_def_map
.get(&(def2.tid.clone(), current_sub.tid.clone())) .get(&(def2.tid.clone(), current_sub.tid.clone()))
.unwrap(); .unwrap();
...@@ -481,6 +534,7 @@ fn getting_source_node() { ...@@ -481,6 +534,7 @@ fn getting_source_node() {
setup.state.set_current_sub(current_sub); setup.state.set_current_sub(current_sub);
let blk_end_node_id = context let blk_end_node_id = context
.block_maps
.jmp_to_blk_end_node_map .jmp_to_blk_end_node_map
.get(&(call_tid.clone(), current_sub.tid.clone())) .get(&(call_tid.clone(), current_sub.tid.clone()))
.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