/*! This module implements a check for CWE-782: Exposed IOCTL with Insufficient Access Control. See <https://cwe.mitre.org/data/definitions/782.html> for a detailed description. How the check works: * Calls to ioctl() get flagged as CWE hits. False Positives: * We cannot check whether the call contains sufficient access control. False Negatives: * There are other ways to expose I/O control without access control. */ use crate::prelude::*; use std::collections::HashMap; use crate::{ intermediate_representation::{Program, Sub, Term, Tid}, utils::{ log::{CweWarning, LogMessage}, symbol_utils::{find_symbol, get_calls_to_symbols}, }, }; const VERSION: &str = "0.1"; pub static CWE_MODULE: crate::CweModule = crate::CweModule { name: "CWE782", version: VERSION, run: check_cwe, }; /// check whether the ioctl symbol is called by any subroutine. If so, generate the cwe warning. pub fn handle_sub(sub: &Term<Sub>, symbol: &HashMap<&Tid, &str>) -> Vec<CweWarning> { let calls: Vec<(&str, &Tid, &str)> = get_calls_to_symbols(sub, &symbol); if !calls.is_empty() { return generate_cwe_warning(&calls); } vec![] } /// generate the cwe warning for CWE 782 pub fn generate_cwe_warning(calls: &[(&str, &Tid, &str)]) -> Vec<CweWarning> { let mut cwe_warnings: Vec<CweWarning> = Vec::new(); for (sub_name, jmp_tid, _) in calls.iter() { let address: &String = &jmp_tid.address; let description = format!( "(Exposed IOCTL with Insufficient Access Control) Program uses ioctl at {} ({}). Be sure to double check the program and the corresponding driver.", sub_name, address ); let cwe_warning = CweWarning::new( String::from(CWE_MODULE.name), String::from(CWE_MODULE.version), description, ) .addresses(vec![address.clone()]) .tids(vec![format!("{}", jmp_tid)]) .symbols(vec![String::from(*sub_name)]); cwe_warnings.push(cwe_warning); } cwe_warnings } pub fn check_cwe( analysis_results: &AnalysisResults, _cwe_params: &serde_json::Value, ) -> (Vec<LogMessage>, Vec<CweWarning>) { let project = analysis_results.project; let prog: &Term<Program> = &project.program; let mut warnings: Vec<CweWarning> = Vec::new(); if let Some((tid, name)) = find_symbol(prog, "ioctl") { let symbol: &HashMap<&Tid, &str> = &[(tid, name)].iter().cloned().collect(); prog.term .subs .iter() .for_each(|sub| warnings.append(&mut handle_sub(sub, symbol))); } (vec![], warnings) }