Unverified Commit d135a25e by Enkelmann Committed by GitHub

support more allocation and deallocation functions (#414)

parent 1b0f0b48
......@@ -89,6 +89,15 @@
]
]
},
"CWE416": {
"deallocation_symbols": [
"free",
"realloc",
"reallocarray",
"operator.delete",
"operator.delete[]"
]
},
"CWE426": {
"_comment": "functions that change/drop privileges",
"symbols": [
......@@ -237,8 +246,11 @@
"malloc",
"calloc",
"realloc",
"reallocarray",
"xmalloc",
"strdup"
"strdup",
"operator.new",
"operator.new[]"
]
},
"StringAbstraction": {
......
......@@ -34,7 +34,7 @@ pub struct Context<'a> {
/// A map that maps abstract identifiers representing the values of parameters at callsites
/// to the corresponding value (in the context of the caller) according to the pointer inference analysis.
pub param_replacement_map: HashMap<AbstractIdentifier, Data>,
/// A map that maps the TIDs of calls to allocatingfunctions (like malloc, realloc and calloc)
/// A map that maps the TIDs of calls to allocating functions (like malloc, realloc and calloc)
/// to the value representing the size of the allocated memory object according to the pointer inference analysis.
pub malloc_tid_to_object_size_map: HashMap<Tid, Data>,
/// A map that maps the TIDs of jump instructions to the function TID of the caller.
......@@ -238,14 +238,14 @@ fn compute_size_values_of_malloc_calls(analysis_results: &AnalysisResults) -> Ha
/// Compute the size value of a call to a malloc-like function according to the pointer inference and return it.
/// Returns `None` if the called symbol is not an allocating function or the size computation for the symbol is not yet implemented.
///
/// Currently this function computes the size values for the symbols `malloc`, `realloc` and `calloc`.
/// Currently this function computes the size values for the symbols `malloc`, `realloc`, `reallocarray`, `calloc` and the C++-`new` operator.
fn compute_size_value_of_malloc_like_call(
jmp_tid: &Tid,
called_symbol: &ExternSymbol,
pointer_inference: &PointerInference,
) -> Option<Data> {
match called_symbol.name.as_str() {
"malloc" => {
"malloc" | "operator.new" | "operator.new[]" => {
let size_param = &called_symbol.parameters[0];
match pointer_inference.eval_parameter_arg_at_call(jmp_tid, size_param) {
Some(size_value) => Some(size_value),
......@@ -259,6 +259,19 @@ fn compute_size_value_of_malloc_like_call(
None => Some(Data::new_top(size_param.bytesize())),
}
}
"reallocarray" => {
let count_param = &called_symbol.parameters[1];
let size_param = &called_symbol.parameters[2];
match (
pointer_inference.eval_parameter_arg_at_call(jmp_tid, count_param),
pointer_inference.eval_parameter_arg_at_call(jmp_tid, size_param),
) {
(Some(count_value), Some(size_value)) => {
Some(count_value.bin_op(BinOpType::IntMult, &size_value))
}
_ => Some(Data::new_top(size_param.bytesize())),
}
}
"calloc" => {
let count_param = &called_symbol.parameters[0];
let size_param = &called_symbol.parameters[1];
......
......@@ -12,12 +12,16 @@ use crate::prelude::*;
use crate::utils::log::CweWarning;
use crate::utils::log::LogMessage;
use std::collections::BTreeMap;
use std::collections::BTreeSet;
/// The context struct for the fixpoint algorithm that contains references to the analysis results
/// of other analyses used in this analysis.
pub struct Context<'a> {
/// A pointer to the project struct.
pub project: &'a Project,
/// The names of extern functions that deallocate memory.
/// These functions will create dangling pointers during the analysis.
pub deallocation_symbols: BTreeSet<String>,
/// A pointer to the control flow graph.
pub graph: &'a Graph<'a>,
/// A pointer to the results of the pointer inference analysis.
......@@ -38,6 +42,7 @@ impl<'a> Context<'a> {
analysis_results: &'b AnalysisResults<'a>,
cwe_warning_collector: crossbeam_channel::Sender<WarningContext>,
log_collector: crossbeam_channel::Sender<LogMessage>,
deallocation_symbols: BTreeSet<String>,
) -> Context<'a>
where
'a: 'b,
......@@ -54,6 +59,7 @@ impl<'a> Context<'a> {
};
Context {
project: analysis_results.project,
deallocation_symbols,
graph: analysis_results.control_flow_graph,
pointer_inference: analysis_results.pointer_inference.unwrap(),
function_signatures: analysis_results.function_signatures.unwrap(),
......@@ -312,7 +318,9 @@ impl<'a> crate::analysis::forward_interprocedural_fixpoint::Context<'a> for Cont
_ => None,
} {
match extern_symbol.name.as_str() {
"free" => self.handle_call_to_free(&mut state, &call.tid, extern_symbol),
dealloc_sym if self.deallocation_symbols.contains(dealloc_sym) => {
self.handle_call_to_free(&mut state, &call.tid, extern_symbol)
}
extern_symbol_name => {
if let Some(warning_causes) = self.collect_cwe_warnings_of_call_params(
&mut state,
......
......@@ -17,12 +17,23 @@
//! To prevent duplicate CWE warnings with the same root cause
//! the check also keeps track of objects for which a CWE warning was already generated.
//!
//! ### Symbols configurable in config.json
//!
//! The `deallocation_symbols` are the names of extern functions that deallocate memory.
//! The check always assumes that the first parameter of such a function is the memory object to be freed.
//! The check also assumes that memory is always freed by such a call,
//! which can lead to false positive warnings for functions like `realloc`, where the memory object may not be freed by the call.
//!
//! ## False Positives
//!
//! - Since the analysis is not path-sensitive, infeasible paths may lead to false positives.
//! - Any analysis imprecision of the pointer inference analysis
//! that leads to assuming that a pointer can target more memory objects that it actually can target
//! may lead to false positive CWE warnings in this check.
//! - For extern functions that may or may not release memory,
//! the check will produce false positives if the original pointer is used after calling the function.
//! For example, `realloc` may return NULL, in which case it will not free memory and the original pointer remains valid.
//! But the check will flag any access to the original pointer as a potential CWE, regardless of the return value of `realloc`.
//!
//! ## False Negatives
//!
......@@ -30,8 +41,7 @@
//! Subsequently, CWEs corresponding to arrays of memory objects are not detected.
//! - Memory objects not tracked by the Pointer Inference analysis or pointer targets missed by the Pointer Inference
//! may lead to missed CWEs in this check.
//! - The analysis currently only tracks pointers to objects that were freed by a call to `free`.
//! If a memory object is freed by another external function then this may lead to false negatives in this check.
//! - Pointers freed by other operations than calls to the deallocation symbols contained in the config.json will be missed by the analysis.
use std::collections::BTreeSet;
use std::collections::HashMap;
......@@ -55,6 +65,14 @@ pub static CWE_MODULE: CweModule = CweModule {
run: check_cwe,
};
/// The configuration struct
#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Hash, Clone)]
pub struct Config {
/// The names of symbols that free memory (e.g. the "free" function of C).
/// The analysis always assumes that the memory object to be freed is the first parameter of the function.
deallocation_symbols: Vec<String>,
}
mod context;
use context::Context;
mod state;
......@@ -68,11 +86,18 @@ use state::State;
/// Returns collected log messages and CWE warnings.
pub fn check_cwe(
analysis_results: &AnalysisResults,
_config: &serde_json::Value,
config_json: &serde_json::Value,
) -> (Vec<LogMessage>, Vec<CweWarning>) {
let config: Config = serde_json::from_value(config_json.clone()).unwrap();
let deallocation_symbols = config.deallocation_symbols.iter().cloned().collect();
let (cwe_warning_sender, cwe_warning_receiver) = crossbeam_channel::unbounded();
let (log_sender, log_receiver) = crossbeam_channel::unbounded();
let context = Context::new(analysis_results, cwe_warning_sender, log_sender);
let context = Context::new(
analysis_results,
cwe_warning_sender,
log_sender,
deallocation_symbols,
);
let mut fixpoint_computation =
crate::analysis::forward_interprocedural_fixpoint::create_computation(context, None);
......
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