diff --git a/untrusted_value_taint_checker/Cargo.toml b/untrusted_value_taint_checker/Cargo.toml index 22ac658..a6549e9 100644 --- a/untrusted_value_taint_checker/Cargo.toml +++ b/untrusted_value_taint_checker/Cargo.toml @@ -14,6 +14,7 @@ tempfile = "3.10.1" serde = { version = "1.0.204", features = ["derive"] } semver = "1.0.23" petgraph = "0.6.5" +itertools = "0.13.0" #owo-colors = { version = "4", features = ["supports-colors"] } #cargo_metadata = "0.18.1" #bpaf = { version = "0.9.12", features = ["bpaf_derive", "autocomplete"] } diff --git a/untrusted_value_taint_checker/sample/src/main.rs b/untrusted_value_taint_checker/sample/src/main.rs index 7f0af30..ff181ea 100644 --- a/untrusted_value_taint_checker/sample/src/main.rs +++ b/untrusted_value_taint_checker/sample/src/main.rs @@ -20,6 +20,60 @@ fn fails() { println!("{:?}", insecure_env) } +#[no_mangle] +fn complicated_nonsense_function(mut arg: String) -> String { + // dont mind the horrible code, used to check the data flow algorithm ;) + + let count = arg.chars().filter(|c| *c == '.').count(); + + loop { + for i in 0..arg.len() { + if let Some(index) = arg.find(".") { + arg.remove(index); + arg.push('+'); + } + let ith = arg.chars().nth(i).unwrap(); + if ith == '#' { + return arg.to_lowercase(); + } else if ith == '-' { + arg = arg.to_uppercase(); + } else if ith == '_' { + arg = arg.to_lowercase(); + } + } + if !arg.contains(".") { + break; + } + } + + arg.repeat(count) +} + +#[no_mangle] +fn nested_function(mut input: usize) -> usize { + #[no_mangle] + fn inner_function(unsafe_arg: &mut usize) { + *unsafe_arg = 10; + } + + inner_function(&mut input); + + input +} + +struct ABC { + value: i32, +} +#[no_mangle] +fn test_rename(q: ABC) -> ABC { + let mut x = q; + let mut y = x; + y.value = 10; + let z = y; + + z +} + fn main() { works(); fails(); diff --git a/untrusted_value_taint_checker/src/analysis/callbacks.rs b/untrusted_value_taint_checker/src/analysis/callbacks.rs index 3be3c01..bcf5f76 100644 --- a/untrusted_value_taint_checker/src/analysis/callbacks.rs +++ b/untrusted_value_taint_checker/src/analysis/callbacks.rs @@ -1,12 +1,15 @@ use std::path::PathBuf; -use petgraph::dot::{Config, Dot}; +use crate::analysis::taint_source::TaintSource; +use petgraph::dot::Dot; use rustc_driver::Compilation; -use rustc_middle::{mir::{visit::Visitor as VisitorMir}, ty::{TyCtxt}}; +use rustc_middle::{mir::visit::Visitor as VisitorMir, ty::TyCtxt}; use tracing::{event, span, Level}; -use crate::analysis::taint_source::TaintSource; -use super::{hir::crate_function_finder::{CrateFunctionFinder, FunctionInfo}, mir::data_flow::DataFlowTaintTracker}; +use super::{ + hir::crate_function_finder::{CrateFunctionFinder, FunctionInfo}, + mir::data_flow::DataFlowTaintTracker, +}; pub struct TaintCompilerCallbacks<'tsrc> { pub package_name: String, @@ -66,18 +69,20 @@ pub fn mir_analysis(tcx: TyCtxt, callback_data: &mut TaintCompilerCallbacks) { ); } - for function in &functions { - let body = tcx.optimized_mir(function.local_def_id); - let mut tracker = DataFlowTaintTracker::new(tcx, body); + for function in &functions { + if callback_data.package_name == "sample" + || callback_data.package_name.starts_with("untrusted_value") + { + let body = tcx.optimized_mir(function.local_def_id); + let mut tracker = DataFlowTaintTracker::new(tcx, body); - println!("{}", function.function_name); - tracker.visit_body(body); - println!("\n\n\n"); - if callback_data.package_name == "sample" || callback_data.package_name.starts_with("untrusted_value") { + println!("{}", function.function_name); + tracker.visit_body(body); + println!("\n\n\n"); let dir_path = PathBuf::from("/tmp/taint/").join(&callback_data.package_name); std::fs::create_dir_all(&dir_path).expect("Failed to create directory"); let dot_file = dir_path.join(&function.function_name).with_extension("dot"); - let dot = Dot::with_config(&tracker.data_dependency_graph, &[Config::EdgeNoLabel]); + let dot = Dot::with_config(&tracker.data_dependency_graph, &[]); std::fs::write(&dot_file, format!("{:?}", dot)).expect("Failed to write dot file"); let pdf_file = dot_file.with_extension("pdf"); std::process::Command::new("dot") diff --git a/untrusted_value_taint_checker/src/analysis/hir/crate_function_finder.rs b/untrusted_value_taint_checker/src/analysis/hir/crate_function_finder.rs index 8985cc6..27c9ad3 100644 --- a/untrusted_value_taint_checker/src/analysis/hir/crate_function_finder.rs +++ b/untrusted_value_taint_checker/src/analysis/hir/crate_function_finder.rs @@ -1,6 +1,5 @@ -use rustc_middle::ty; use rustc_hir::intravisit::Visitor as HirVisitor; - +use rustc_middle::ty; pub struct FunctionInfo { pub function_name: String, diff --git a/untrusted_value_taint_checker/src/analysis/mir/data_flow.rs b/untrusted_value_taint_checker/src/analysis/mir/data_flow.rs index 8505e26..9fc50db 100644 --- a/untrusted_value_taint_checker/src/analysis/mir/data_flow.rs +++ b/untrusted_value_taint_checker/src/analysis/mir/data_flow.rs @@ -1,46 +1,84 @@ - use core::fmt; use std::fmt::{Debug, Formatter}; +use itertools::Itertools; use petgraph::graph::{DiGraph, NodeIndex}; -use rustc_index::bit_set::{GrowableBitSet}; +use rustc_index::bit_set::GrowableBitSet; +use rustc_middle::mir; +use rustc_middle::mir::visit::Visitor as VisitorMir; use rustc_middle::ty; use rustc_span::Span; -use rustc_middle::mir; -use rustc_middle::mir::{visit::Visitor as VisitorMir}; #[derive(PartialEq, Eq, Hash, Clone)] pub enum DependencyGraphNode<'tcx> { - Local { - dst: mir::Local - }, - FunctionCall { - function: ty::Ty<'tcx>, - }, + Local { dst: mir::Local }, + FunctionCall { function: ty::Ty<'tcx>, span: Span }, ReturnedToCaller, FunctionInput, Assembly { spans: Vec }, + ControlFlow, } impl<'tcx> Debug for DependencyGraphNode<'tcx> { fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { match self { DependencyGraphNode::Local { dst } => write!(f, "{}", dst.index()), - DependencyGraphNode::FunctionCall { function } => write!(f, "Call: {}", function.to_string()), + DependencyGraphNode::FunctionCall { function, span: _ } => { + write!(f, "Call: {}", function.to_string()) + } DependencyGraphNode::ReturnedToCaller => write!(f, "Return"), DependencyGraphNode::FunctionInput => write!(f, "Input"), DependencyGraphNode::Assembly { spans: _ } => write!(f, "Assembly"), + DependencyGraphNode::ControlFlow => write!(f, "ControlFlow"), } } } +#[derive(PartialEq, Eq, Hash, Clone, Copy, Debug)] +pub enum EdgeDataFlowType { + Move, + Used, +} + +#[derive(Clone)] +pub struct EdgeInstance { + pub span: Span, + pub data_flow_type: EdgeDataFlowType, +} + +impl Debug for EdgeInstance { + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + write!(f, "{:?}", self.data_flow_type) + } +} + +#[derive(Clone)] +pub struct GraphEdge { + pub instances: Vec, +} + +impl Debug for GraphEdge { + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + write!( + f, + "{}", + self.instances + .iter() + .unique_by(|x| x.data_flow_type) + .map(|x| format!("{:?}", x)) + .sorted() + .collect::>() + .join(", ") + ) + } +} + pub struct DataFlowTaintTracker<'tcx, 'a> { tcx: ty::TyCtxt<'tcx>, pub sanitized_locals: GrowableBitSet, - pub data_dependency_graph: DiGraph, Vec>, + pub data_dependency_graph: DiGraph, GraphEdge>, data_dependency_graph_index: config::Map, NodeIndex>, - pub locals_used_in_control_flow: GrowableBitSet, current_body: &'a mir::Body<'tcx>, } @@ -52,70 +90,96 @@ impl<'tcx, 'a> DataFlowTaintTracker<'tcx, 'a> { sanitized_locals: GrowableBitSet::new_empty(), data_dependency_graph: DiGraph::new(), data_dependency_graph_index: config::Map::new(), - locals_used_in_control_flow: GrowableBitSet::new_empty(), current_body: body, } } } impl<'tcx, 'a> DataFlowTaintTracker<'tcx, 'a> { - pub fn get_place_dependency(&self, place: &mir::Place, dependencies: &mut Vec) { - dependencies.push(place.local) + pub fn get_place_dependency( + &self, + place: &mir::Place, + dependencies: &mut Vec<(mir::Local, EdgeDataFlowType)>, + flow_type: EdgeDataFlowType, + ) { + dependencies.push((place.local, flow_type)) } - pub fn get_operand_dependency(&self, operand: &mir::Operand<'tcx>, dependencies: &mut Vec) { + pub fn get_operand_dependency( + &self, + operand: &mir::Operand<'tcx>, + dependencies: &mut Vec<(mir::Local, EdgeDataFlowType)>, + force_flow: Option, + ) { match operand { - mir::Operand::Copy(place) | mir::Operand::Move(place) => { - self.get_place_dependency(place, dependencies) - } - mir::Operand::Constant(_) => {}, + mir::Operand::Copy(place) => self.get_place_dependency( + place, + dependencies, + force_flow.unwrap_or(EdgeDataFlowType::Used), + ), + mir::Operand::Move(place) => self.get_place_dependency( + place, + dependencies, + force_flow.unwrap_or(EdgeDataFlowType::Move), + ), + mir::Operand::Constant(_) => {} } } - pub fn get_rvalue_dependency(&self, rvalue: &mir::Rvalue<'tcx>, dependencies: &mut Vec) { + pub fn get_rvalue_dependency( + &self, + rvalue: &mir::Rvalue<'tcx>, + dependencies: &mut Vec<(mir::Local, EdgeDataFlowType)>, + ) { match rvalue { mir::Rvalue::Use(op) => { - self.get_operand_dependency(op, dependencies); + self.get_operand_dependency(op, dependencies, None); } mir::Rvalue::Repeat(operand, _) => { - self.get_operand_dependency(operand, dependencies); + self.get_operand_dependency(operand, dependencies, Some(EdgeDataFlowType::Used)); } mir::Rvalue::Ref(_region, _kind, src) => { - self.get_place_dependency(src, dependencies); + self.get_place_dependency(src, dependencies, EdgeDataFlowType::Used); } - mir::Rvalue::ThreadLocalRef(_defid) => { } + mir::Rvalue::ThreadLocalRef(_defid) => {} mir::Rvalue::AddressOf(_mutability, place) => { - self.get_place_dependency(place, dependencies); - }, + self.get_place_dependency(place, dependencies, EdgeDataFlowType::Used); + } mir::Rvalue::Len(place) => { - self.get_place_dependency(place, dependencies); - }, + self.get_place_dependency(place, dependencies, EdgeDataFlowType::Used); + } mir::Rvalue::Cast(_kind, operand, _target) => { - self.get_operand_dependency(operand, dependencies); - }, + self.get_operand_dependency(operand, dependencies, None); + } mir::Rvalue::BinaryOp(_operation, box (op_a, op_b)) => { - self.get_operand_dependency(op_a, dependencies); - self.get_operand_dependency(op_b, dependencies); + self.get_operand_dependency(op_a, dependencies, Some(EdgeDataFlowType::Used)); + self.get_operand_dependency(op_b, dependencies, Some(EdgeDataFlowType::Used)); } - mir::Rvalue::NullaryOp(_operation, _ty) => { - - }, + mir::Rvalue::NullaryOp(_operation, _ty) => {} mir::Rvalue::UnaryOp(_operation, operand) => { - self.get_operand_dependency(operand, dependencies); - }, + self.get_operand_dependency(operand, dependencies, Some(EdgeDataFlowType::Used)); + } mir::Rvalue::Discriminant(place) => { - self.get_place_dependency(place, dependencies); + self.get_place_dependency(place, dependencies, EdgeDataFlowType::Used); } mir::Rvalue::Aggregate(box _kind, fields) => { - fields.iter().for_each(|op| self.get_operand_dependency(op, dependencies)); + fields + .iter() + .for_each(|op| self.get_operand_dependency(op, dependencies, None)); } mir::Rvalue::ShallowInitBox(operand, _ty) => { - self.get_operand_dependency(operand, dependencies); - }, + self.get_operand_dependency(operand, dependencies, None); + } mir::Rvalue::CopyForDeref(place) => { - self.get_place_dependency(place, dependencies); - }, + self.get_place_dependency(place, dependencies, EdgeDataFlowType::Used); + } }; } - pub fn add_data_dependency_edge(&mut self, from: DependencyGraphNode<'tcx>, to: DependencyGraphNode<'tcx>, span: Span) { + pub fn add_data_dependency_edge( + &mut self, + from: DependencyGraphNode<'tcx>, + to: DependencyGraphNode<'tcx>, + span: Span, + flow_type: EdgeDataFlowType, + ) { let from_idx = self.data_dependency_graph_index.get(&from); let from_idx = if let Some(idx) = from_idx { *idx @@ -134,17 +198,26 @@ impl<'tcx, 'a> DataFlowTaintTracker<'tcx, 'a> { idx }; + let new_edge = EdgeInstance { + span, + data_flow_type: flow_type, + }; if let Some(edge) = self.data_dependency_graph.find_edge(from_idx, to_idx) { - self.data_dependency_graph[edge].push(span); + self.data_dependency_graph[edge].instances.push(new_edge); } else { - self.data_dependency_graph.add_edge(from_idx, to_idx, vec![span]); + self.data_dependency_graph.add_edge( + from_idx, + to_idx, + GraphEdge { + instances: vec![new_edge], + }, + ); } } } impl<'tcx, 'a> VisitorMir<'tcx> for DataFlowTaintTracker<'tcx, 'a> { - fn visit_body(&mut self,body: &mir::Body<'tcx>,) { - + fn visit_body(&mut self, body: &mir::Body<'tcx>) { // identify sanitizers for (local, local_delc) in body.local_decls.iter_enumerated() { if let ty::TyKind::Adt(base, _generics) = local_delc.ty.kind() { @@ -155,138 +228,254 @@ impl<'tcx, 'a> VisitorMir<'tcx> for DataFlowTaintTracker<'tcx, 'a> { } } + for arg in 1..body.arg_count + 1 { + self.add_data_dependency_edge( + DependencyGraphNode::FunctionInput, + DependencyGraphNode::Local { dst: arg.into() }, + body.span, + EdgeDataFlowType::Move, + ); + } + self.super_body(body); } - fn visit_basic_block_data(&mut self,block:mir::BasicBlock,data: &mir::BasicBlockData<'tcx>,) { + fn visit_basic_block_data(&mut self, block: mir::BasicBlock, data: &mir::BasicBlockData<'tcx>) { println!("\n - Basic Block Data: {}", block.index()); self.super_basic_block_data(block, data); } - fn visit_local_decl(&mut self,local:mir::Local,local_decl: &mir::LocalDecl<'tcx>,) { + fn visit_local_decl(&mut self, local: mir::Local, local_decl: &mir::LocalDecl<'tcx>) { println!(" let {:?} = {:?}", local, local_decl.ty); self.super_local_decl(local, local_decl); } - fn visit_statement(&mut self,statement: &mir::Statement<'tcx>,location:mir::Location,) { + fn visit_statement(&mut self, statement: &mir::Statement<'tcx>, location: mir::Location) { println!(" Statement: {:?} @ {:?}", statement, location); - let mut dependencies: Vec = Vec::with_capacity(2); + let mut dependencies: Vec<(mir::Local, EdgeDataFlowType)> = Vec::with_capacity(2); match &statement.kind { mir::StatementKind::Assign(box (place, rvalue)) => { self.get_rvalue_dependency(&rvalue, &mut dependencies); - for dependency in dependencies.iter() { - self.add_data_dependency_edge(DependencyGraphNode::Local {dst: *dependency}, DependencyGraphNode::Local {dst: place.local}, statement.source_info.span); + for (dep, data_flow) in dependencies.iter() { + self.add_data_dependency_edge( + DependencyGraphNode::Local { dst: *dep }, + DependencyGraphNode::Local { dst: place.local }, + statement.source_info.span, + *data_flow, + ); } - }, - mir::StatementKind::Intrinsic(box mir::NonDivergingIntrinsic::CopyNonOverlapping(copy)) => { - if let mir::Operand::Copy(src) | mir::Operand::Move(src) = ©.src { - if let mir::Operand::Copy(dst) | mir::Operand::Move(dst) = ©.dst { - self.add_data_dependency_edge(DependencyGraphNode::Local {dst: src.local}, DependencyGraphNode::Local {dst: dst.local}, statement.source_info.span); + } + mir::StatementKind::Intrinsic(box mir::NonDivergingIntrinsic::CopyNonOverlapping( + copy, + )) => { + if let mir::Operand::Copy(dst) | mir::Operand::Move(dst) = ©.dst { + match ©.src { + mir::Operand::Copy(src) => { + self.add_data_dependency_edge( + DependencyGraphNode::Local { dst: src.local }, + DependencyGraphNode::Local { dst: dst.local }, + statement.source_info.span, + EdgeDataFlowType::Used, + ); + } + mir::Operand::Move(src) => { + self.add_data_dependency_edge( + DependencyGraphNode::Local { dst: src.local }, + DependencyGraphNode::Local { dst: dst.local }, + statement.source_info.span, + EdgeDataFlowType::Move, + ); + } + mir::Operand::Constant(_) => {} } } } mir::StatementKind::Deinit(_) => {} - mir::StatementKind::FakeRead(_) => {}, - mir::StatementKind::SetDiscriminant {..} => {}, - mir::StatementKind::StorageLive(_) => {}, - mir::StatementKind::StorageDead(_) => {}, - mir::StatementKind::Retag(_, _) => {}, - mir::StatementKind::PlaceMention(_) => {}, - mir::StatementKind::AscribeUserType(_, _) => {}, - mir::StatementKind::Coverage(_) => {}, + mir::StatementKind::FakeRead(_) => {} + mir::StatementKind::SetDiscriminant { .. } => {} + mir::StatementKind::StorageLive(_) => {} + mir::StatementKind::StorageDead(_) => {} + mir::StatementKind::Retag(_, _) => {} + mir::StatementKind::PlaceMention(_) => {} + mir::StatementKind::AscribeUserType(_, _) => {} + mir::StatementKind::Coverage(_) => {} mir::StatementKind::Intrinsic(box mir::NonDivergingIntrinsic::Assume(_)) => {} - mir::StatementKind::ConstEvalCounter => {}, - mir::StatementKind::Nop => {}, + mir::StatementKind::ConstEvalCounter => {} + mir::StatementKind::Nop => {} } self.super_statement(statement, location); - } - fn visit_assign(&mut self, place: &mir::Place<'tcx>, rvalue: &mir::Rvalue<'tcx>, location:mir::Location,) { + fn visit_assign( + &mut self, + place: &mir::Place<'tcx>, + rvalue: &mir::Rvalue<'tcx>, + location: mir::Location, + ) { println!(" {:?} <- {:?} @ {:?}", place, rvalue, location); self.super_assign(place, rvalue, location); } - fn visit_terminator(&mut self,terminator: &mir::Terminator<'tcx>,location:mir::Location,) { + fn visit_terminator(&mut self, terminator: &mir::Terminator<'tcx>, location: mir::Location) { println!(" stop {:?}", terminator.kind); - - let mut dependencies: Vec = Vec::with_capacity(2); + + let mut dependencies: Vec<(mir::Local, EdgeDataFlowType)> = Vec::with_capacity(2); match &terminator.kind { - mir::TerminatorKind::Goto {..} => {}, - mir::TerminatorKind::SwitchInt {discr, targets: _} => { - self.get_operand_dependency(&discr, &mut dependencies); - for dep in dependencies { - self.locals_used_in_control_flow.insert(dep); + mir::TerminatorKind::Goto { .. } => {} + mir::TerminatorKind::SwitchInt { discr, targets: _ } => { + self.get_operand_dependency(&discr, &mut dependencies, None); + for (dep, flow) in dependencies { + self.add_data_dependency_edge( + DependencyGraphNode::Local { dst: dep }, + DependencyGraphNode::ControlFlow, + terminator.source_info.span, + flow, + ); } - }, - mir::TerminatorKind::UnwindResume => {}, - mir::TerminatorKind::UnwindTerminate(_reason) => {}, + } + mir::TerminatorKind::UnwindResume => {} + mir::TerminatorKind::UnwindTerminate(_reason) => {} mir::TerminatorKind::Return => { self.add_data_dependency_edge( - DependencyGraphNode::Local { dst: mir::Local::ZERO }, - DependencyGraphNode::ReturnedToCaller, terminator.source_info.span); - }, - mir::TerminatorKind::Unreachable => {}, - mir::TerminatorKind::Drop { place: _, target: _, unwind: _, replace: _ } => {}, - mir::TerminatorKind::Call { func, args, destination, target: _, unwind: _, call_source: _, fn_span} => { + DependencyGraphNode::Local { + dst: mir::Local::ZERO, + }, + DependencyGraphNode::ReturnedToCaller, + terminator.source_info.span, + EdgeDataFlowType::Move, + ); + } + mir::TerminatorKind::Unreachable => {} + mir::TerminatorKind::Drop { + place: _, + target: _, + unwind: _, + replace: _, + } => {} + mir::TerminatorKind::Call { + func, + args, + destination, + target: _, + unwind: _, + call_source: _, + fn_span, + } => { for arg in args { - self.get_operand_dependency(&arg.node, &mut dependencies); + self.get_operand_dependency(&arg.node, &mut dependencies, None); } - let func_call = DependencyGraphNode::FunctionCall { function: func.ty(self.current_body, self.tcx) }; + let func_call = DependencyGraphNode::FunctionCall { + function: func.ty(self.current_body, self.tcx), + span: fn_span.to_owned(), + }; - for dep in dependencies { + for (dep, flow) in dependencies { self.add_data_dependency_edge( - DependencyGraphNode::Local { dst: dep }, - func_call.clone(), fn_span.to_owned()); + DependencyGraphNode::Local { dst: dep }, + func_call.clone(), + fn_span.to_owned(), + flow, + ); } self.add_data_dependency_edge( func_call, - DependencyGraphNode::Local { dst: destination.local }, fn_span.to_owned()); - }, - mir::TerminatorKind::TailCall {func, args, fn_span} => { + DependencyGraphNode::Local { + dst: destination.local, + }, + fn_span.to_owned(), + EdgeDataFlowType::Move, + ); + } + mir::TerminatorKind::TailCall { + func, + args, + fn_span, + } => { for arg in args { - self.get_operand_dependency(&arg.node, &mut dependencies); + self.get_operand_dependency(&arg.node, &mut dependencies, None); } - let func_call = DependencyGraphNode::FunctionCall { function: func.ty(self.current_body, self.tcx) }; + let func_call = DependencyGraphNode::FunctionCall { + function: func.ty(self.current_body, self.tcx), + span: fn_span.to_owned(), + }; - for dep in dependencies { + for (dep, flow) in dependencies { self.add_data_dependency_edge( - DependencyGraphNode::Local { dst: dep }, - func_call.clone(), fn_span.to_owned()); + DependencyGraphNode::Local { dst: dep }, + func_call.clone(), + fn_span.to_owned(), + flow, + ); } self.add_data_dependency_edge( func_call, - DependencyGraphNode::ReturnedToCaller, fn_span.to_owned()); - }, - mir::TerminatorKind::Assert { .. } => {/* maybe todo */}, - mir::TerminatorKind::Yield { value, resume: _, resume_arg, drop: _ } => { - self.get_operand_dependency(value, &mut dependencies); + DependencyGraphNode::ReturnedToCaller, + fn_span.to_owned(), + EdgeDataFlowType::Move, + ); + } + mir::TerminatorKind::Assert { .. } => { /* maybe todo */ } + mir::TerminatorKind::Yield { + value, + resume: _, + resume_arg, + drop: _, + } => { + self.get_operand_dependency(value, &mut dependencies, None); - for dep in dependencies { + for (dep, flow) in dependencies { self.add_data_dependency_edge( - DependencyGraphNode::Local { dst: dep }, - DependencyGraphNode::ReturnedToCaller, terminator.source_info.span); + DependencyGraphNode::Local { dst: dep }, + DependencyGraphNode::ReturnedToCaller, + terminator.source_info.span, + flow, + ); } - self.add_data_dependency_edge(DependencyGraphNode::FunctionInput, - DependencyGraphNode::Local { dst: resume_arg.local }, terminator.source_info.span); - }, - mir::TerminatorKind::CoroutineDrop => {}, - mir::TerminatorKind::FalseEdge {..} => {}, - mir::TerminatorKind::FalseUnwind { .. } => {}, - mir::TerminatorKind::InlineAsm {template: _, operands, options: _, line_spans, targets: _, unwind: _} => { + self.add_data_dependency_edge( + DependencyGraphNode::FunctionInput, + DependencyGraphNode::Local { + dst: resume_arg.local, + }, + terminator.source_info.span, + EdgeDataFlowType::Move, + ); + } + mir::TerminatorKind::CoroutineDrop => {} + mir::TerminatorKind::FalseEdge { .. } => {} + mir::TerminatorKind::FalseUnwind { .. } => {} + mir::TerminatorKind::InlineAsm { + template: _, + operands, + options: _, + line_spans, + targets: _, + unwind: _, + } => { let mut inputs = dependencies; let mut outputs = Vec::new(); for op in operands { match op { mir::InlineAsmOperand::In { reg: _, value } => { - self.get_operand_dependency(value, &mut inputs) + self.get_operand_dependency( + value, + &mut inputs, + Some(EdgeDataFlowType::Used), + ); } - mir::InlineAsmOperand::Out {reg: _, late: _, place} => { + mir::InlineAsmOperand::Out { + reg: _, + late: _, + place, + } => { if let Some(place) = place { - self.get_place_dependency(place, &mut outputs) + self.get_place_dependency( + place, + &mut outputs, + EdgeDataFlowType::Used, + ) } } mir::InlineAsmOperand::InOut { @@ -295,32 +484,52 @@ impl<'tcx, 'a> VisitorMir<'tcx> for DataFlowTaintTracker<'tcx, 'a> { in_value, out_place, } => { - self.get_operand_dependency(in_value, &mut inputs); + self.get_operand_dependency( + in_value, + &mut inputs, + Some(EdgeDataFlowType::Used), + ); if let Some(place) = out_place { - self.get_place_dependency(place, &mut outputs) + self.get_place_dependency( + place, + &mut outputs, + EdgeDataFlowType::Move, + ) } - }, - mir::InlineAsmOperand::Const {..} => {} - mir::InlineAsmOperand::SymFn {..} => {}, - mir::InlineAsmOperand::Label {..} => {}, - mir::InlineAsmOperand::SymStatic {..} => {}, + } + mir::InlineAsmOperand::Const { .. } => {} + mir::InlineAsmOperand::SymFn { .. } => {} + mir::InlineAsmOperand::Label { .. } => {} + mir::InlineAsmOperand::SymStatic { .. } => {} } } - let asm_block = DependencyGraphNode::Assembly { spans: line_spans.iter().map(Span::to_owned).collect() }; + let asm_block = DependencyGraphNode::Assembly { + spans: line_spans.iter().map(Span::to_owned).collect(), + }; - for dep in inputs { - self.add_data_dependency_edge(DependencyGraphNode::Local { dst: dep }, asm_block.clone(), terminator.source_info.span); + for (dep, flow) in inputs { + self.add_data_dependency_edge( + DependencyGraphNode::Local { dst: dep }, + asm_block.clone(), + terminator.source_info.span, + flow, + ); } - for dep in outputs { - self.add_data_dependency_edge(asm_block.clone(), DependencyGraphNode::Local { dst: dep }, terminator.source_info.span); + for (dep, flow) in outputs { + self.add_data_dependency_edge( + asm_block.clone(), + DependencyGraphNode::Local { dst: dep }, + terminator.source_info.span, + flow, + ); } - }, + } } self.super_terminator(terminator, location); } - fn visit_operand(&mut self,operand: &mir::Operand<'tcx>,location:mir::Location,) { + fn visit_operand(&mut self, operand: &mir::Operand<'tcx>, location: mir::Location) { println!(" op {:?}", operand); self.super_operand(operand, location); } diff --git a/untrusted_value_taint_checker/src/analysis/mir/data_flow_checker.rs b/untrusted_value_taint_checker/src/analysis/mir/data_flow_checker.rs new file mode 100644 index 0000000..7d144e5 --- /dev/null +++ b/untrusted_value_taint_checker/src/analysis/mir/data_flow_checker.rs @@ -0,0 +1,13 @@ +use petgraph::graph::DiGraph; +use rustc_middle::mir; + +use crate::analysis::taint_problem::TaintProblem; + +use super::data_flow::DependencyGraphNode; + +pub fn check_data_flow<'tsrc, 'tcx>( + _sanitized_locals: Vec, + _data_dependency_graph: DiGraph, Vec>, +) -> Vec> { + Vec::new() +} diff --git a/untrusted_value_taint_checker/src/analysis/taint_problem.rs b/untrusted_value_taint_checker/src/analysis/taint_problem.rs new file mode 100644 index 0000000..7e12570 --- /dev/null +++ b/untrusted_value_taint_checker/src/analysis/taint_problem.rs @@ -0,0 +1,8 @@ +use rustc_span::Span; + +use super::taint_source::TaintSource; + +pub struct TaintProblem<'tsrc> { + _taint_source: &'tsrc TaintSource<'static>, + _used_at: Span, +} diff --git a/untrusted_value_taint_checker/src/cargo.rs b/untrusted_value_taint_checker/src/cargo.rs index 3dace6c..6e060ba 100644 --- a/untrusted_value_taint_checker/src/cargo.rs +++ b/untrusted_value_taint_checker/src/cargo.rs @@ -1,4 +1,5 @@ use crate::analysis::build_plan::{CompileMode, TargetKind}; +use crate::analysis::taint_source::{get_taint_sources_definitions, TaintSource}; use crate::{ analysis::{ build_plan::{BuildPlan, Invocation}, @@ -13,7 +14,6 @@ use std::{ env, fs, process::{Command, Stdio}, }; -use crate::analysis::taint_source::{get_taint_sources_definitions, TaintSource}; pub fn execute_build_plan(mut build_plan: BuildPlan) -> anyhow::Result<()> { let taint_sources = get_taint_sources_definitions(); @@ -38,11 +38,10 @@ pub fn execute_build_plan(mut build_plan: BuildPlan) -> anyhow::Result<()> { let links = current.links.clone(); - - match current.compile_mode { CompileMode::Build => { - let results = execute_build_invocation_mir_analysis(current, &actual_used_taint_sources)?; + let results = + execute_build_invocation_mir_analysis(current, &actual_used_taint_sources)?; println!( " - Found {} functions", @@ -236,7 +235,7 @@ fn execute_build_invocation_original_rustc(invocation: &Invocation) -> anyhow::R fn execute_build_invocation_mir_analysis<'tsrc>( invocation: &Invocation, - taint_sources: &'tsrc Vec> + taint_sources: &'tsrc Vec>, ) -> anyhow::Result> { // print args let mut args = invocation.args.clone(); diff --git a/untrusted_value_taint_checker/src/lib.rs b/untrusted_value_taint_checker/src/lib.rs index ff33fb0..5ad2fe5 100644 --- a/untrusted_value_taint_checker/src/lib.rs +++ b/untrusted_value_taint_checker/src/lib.rs @@ -5,11 +5,11 @@ extern crate rustc_ast; extern crate rustc_driver; extern crate rustc_errors; extern crate rustc_hir; +extern crate rustc_index; extern crate rustc_interface; extern crate rustc_middle; extern crate rustc_session; extern crate rustc_span; -extern crate rustc_index; pub mod cargo; pub mod rustc; @@ -18,6 +18,7 @@ pub mod analysis { pub mod build_plan; pub mod callbacks; pub mod invocation_environment; + pub mod taint_problem; pub mod taint_source; pub mod hir { @@ -25,5 +26,6 @@ pub mod analysis { } pub mod mir { pub mod data_flow; + pub mod data_flow_checker; } }