-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: introduced module taint_checker WIP
- Loading branch information
Showing
21 changed files
with
822 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -16,4 +16,7 @@ target/ | |
# Idea | ||
.idea/ | ||
|
||
# VScode | ||
.vscode/ | ||
|
||
Cargo.lock |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
[workspace] | ||
|
||
[[package]] | ||
name = "sample" | ||
publish = false | ||
|
||
[[package]] | ||
name = "untrusted_value_taint_checker" | ||
publish = false |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
[toolchain] | ||
channel = "nightly-2024-06-11" | ||
components = [ | ||
"rust-src", | ||
"rustc-dev", | ||
"llvm-tools-preview", | ||
"rustfmt", | ||
"rust-analyzer-preview" | ||
] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
[package] | ||
name = "untrusted_value_taint_checker" | ||
version = "0.1.0" | ||
edition = "2021" | ||
|
||
[dependencies] | ||
untrusted_value = { version = "0.3.1", path = "../untrusted_value"} | ||
anyhow = "1.0.86" | ||
config = "0.14.0" | ||
tracing-subscriber = { version = "0.3.18" , features = ["env-filter"]} | ||
tracing = "0" | ||
serde_json = "1.0.120" | ||
tempfile = "3.10.1" | ||
serde = { version = "1.0.204", features = ["derive"] } | ||
#owo-colors = { version = "4", features = ["supports-colors"] } | ||
#cargo_metadata = "0.18.1" | ||
#bpaf = { version = "0.9.12", features = ["bpaf_derive", "autocomplete"] } | ||
|
||
[package.metadata.rust-analyzer] | ||
rustc_private = true | ||
|
||
[build-dependencies] | ||
serde = { version = "1.0.204", features = ["derive"] } | ||
serde_json = "1.0.120" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
TODO | ||
|
||
Some code parts inspired/copied from https://github.com/LiHRaM/taint/tree/master licensed unter MIT (licese notice can be found in opensource/LICENSE-LiHRam-taint) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,114 @@ | ||
use std::{fs, process::Command}; | ||
|
||
use serde::Deserialize; | ||
|
||
#[derive(Debug, Clone, Deserialize)] | ||
pub struct TaintModuleJson { | ||
pub taint_module_name: String, | ||
pub description: String, | ||
pub content: Vec<TaintModuleLibraryJson>, | ||
} | ||
|
||
#[derive(Debug, Clone, Deserialize)] | ||
pub struct TaintModuleLibraryJson { | ||
pub module_prefix: String, | ||
pub taint_sources: Vec<TaintSourceJson>, | ||
} | ||
|
||
#[derive(Debug, Clone, Deserialize)] | ||
pub struct TaintSourceJson { | ||
pub functions: Vec<String>, | ||
pub description: String, | ||
} | ||
|
||
#[allow(clippy::useless_format)] | ||
fn main() { | ||
println!("cargo::rerun-if-changed=src/analysis/taint_source/"); | ||
|
||
// list files in taint_source directory | ||
let taint_source_dir = std::path::Path::new("src/analysis/taint_source/"); | ||
let taint_source_files = | ||
std::fs::read_dir(taint_source_dir).expect("Cannot read taint_source directory"); | ||
|
||
let mut taint_modules = Vec::new(); | ||
|
||
for file in taint_source_files { | ||
let file = file.expect("Cannot read directory entry"); | ||
let file = file.path(); | ||
if file.extension() != Some("json".as_ref()) { | ||
continue; | ||
} | ||
let file = fs::File::open(file).expect("Cannot open file"); | ||
|
||
let taint_module: TaintModuleJson = | ||
serde_json::from_reader(file).expect("Cannot parse JSON"); | ||
taint_modules.push(taint_module); | ||
} | ||
|
||
let mut generated_code = String::new(); | ||
|
||
generated_code.push_str(&format!("vec![\n")); | ||
let mut number = 0; | ||
for module in taint_modules { | ||
generated_code.push_str(&format!(" TaintSourceDefinition {{\n")); | ||
generated_code.push_str(&format!( | ||
" taint_module_name: \"{}\",\n", | ||
module.taint_module_name | ||
)); | ||
generated_code.push_str(&format!( | ||
" taint_module_description: \"{}\",\n", | ||
module.description | ||
)); | ||
generated_code.push_str(&format!(" sources: vec![\n")); | ||
for library in module.content { | ||
let prefix = if library.module_prefix.is_empty() { | ||
"".to_owned() | ||
} else { | ||
format!("{}::", library.module_prefix) | ||
}; | ||
|
||
for source in library.taint_sources { | ||
generated_code.push_str(&format!(" TaintSource {{\n")); | ||
generated_code.push_str(&format!( | ||
" description: \"{}\",\n", | ||
source.description | ||
)); | ||
generated_code.push_str(&format!(" functions: vec![\n")); | ||
|
||
for function in source.functions { | ||
generated_code.push_str(&format!( | ||
" \"{}{}\",\n", | ||
prefix, function | ||
)); | ||
} | ||
|
||
generated_code.push_str(&format!(" ],}},\n")); | ||
} | ||
} | ||
generated_code.push_str(&format!(" ],}},\n")); | ||
number += 1; | ||
} | ||
generated_code.push_str(&format!(" ]")); | ||
|
||
let template = std::fs::read_to_string(std::path::Path::new( | ||
"src/analysis/taint_source/generated.tpl", | ||
)) | ||
.expect("Cannot read template"); | ||
let out_text = template | ||
.replace("<GENERATE>", &generated_code) | ||
.replace("<LEN>", format!("{number}").as_str()); | ||
|
||
let out_file = std::path::Path::new("src/analysis/taint_source/generated.rs"); | ||
fs::write(out_file, out_text).expect("Cannot write generated code"); | ||
|
||
// run cargo fmt | ||
let cmd = Command::new("rustfmt").arg(out_file).spawn(); | ||
|
||
let _ = cmd.map(|mut cmd| { | ||
cmd.wait().map(|exit| { | ||
if !exit.success() { | ||
panic!("Rustfmt returned non-zero exit code.") | ||
} | ||
}) | ||
}); | ||
} |
19 changes: 19 additions & 0 deletions
19
untrusted_value_taint_checker/opensource/LICENSE-LiHRam-taint
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
MIT License | ||
|
||
Permission is hereby granted, free of charge, to any person obtaining a copy | ||
of this software and associated documentation files (the "Software"), to deal | ||
in the Software without restriction, including without limitation the rights | ||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
copies of the Software, and to permit persons to whom the Software is | ||
furnished to do so, subject to the following conditions: | ||
|
||
The above copyright notice and this permission notice shall be included in all | ||
copies or substantial portions of the Software. | ||
|
||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||
SOFTWARE. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
[package] | ||
name = "sample" | ||
version = "0.1.0" | ||
edition = "2021" | ||
|
||
[dependencies] | ||
untrusted_value = { version = "0", path = "../../untrusted_value" } |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
use untrusted_value::UntrustedValue; | ||
|
||
#[no_mangle] | ||
fn works() { | ||
let insecure_env = std::env::var("TEST"); | ||
|
||
// do some stuff in between | ||
println!("waiting..."); | ||
std::thread::sleep(std::time::Duration::from_secs(10)); | ||
|
||
let secure_env = UntrustedValue::from(insecure_env); | ||
|
||
println!("{:?}", secure_env.use_untrusted_value()) | ||
} | ||
|
||
#[no_mangle] | ||
fn fails() { | ||
let insecure_env = std::env::var("TEST"); | ||
|
||
println!("{:?}", insecure_env) | ||
Check failure on line 20 in untrusted_value_taint_checker/sample/src/main.rs
|
||
} | ||
|
||
fn main() { | ||
works(); | ||
fails(); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
use std::path::PathBuf; | ||
|
||
use config::Map; | ||
use serde::{Deserialize, Serialize}; | ||
|
||
#[derive(Deserialize, Serialize, Debug, Clone)] | ||
pub struct BuildPlan { | ||
pub invocations: Vec<BuildInvocation>, | ||
pub inputs: Vec<PathBuf>, | ||
} | ||
|
||
#[derive(Deserialize, Serialize, Debug, Clone)] | ||
pub enum CompileMode { | ||
#[serde(rename = "run-custom-build")] | ||
RunCustomBuild, | ||
#[serde(rename = "build")] | ||
Build, | ||
} | ||
|
||
#[derive(Deserialize, Serialize, Debug, Clone)] | ||
pub struct BuildInvocation { | ||
pub package_name: String, | ||
pub package_version: String, | ||
pub target_kind: Vec<String>, | ||
pub kind: Option<String>, | ||
pub compile_mode: CompileMode, | ||
pub outputs: Vec<PathBuf>, | ||
pub links: Map<String, String>, | ||
pub program: PathBuf, | ||
pub args: Vec<String>, | ||
pub env: Map<String, String>, | ||
pub cwd: PathBuf, | ||
} |
113 changes: 113 additions & 0 deletions
113
untrusted_value_taint_checker/src/analysis/callbacks.rs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,113 @@ | ||
extern crate rustc_ast; | ||
extern crate rustc_driver; | ||
extern crate rustc_errors; | ||
extern crate rustc_hir; | ||
extern crate rustc_interface; | ||
extern crate rustc_middle; | ||
extern crate rustc_session; | ||
extern crate rustc_span; | ||
|
||
use rustc_driver::Compilation; | ||
use rustc_hir::intravisit::Visitor; | ||
use rustc_middle::ty::TyCtxt; | ||
use tracing::{event, span, Level}; | ||
|
||
pub struct TaintCompilerCallbacks { | ||
pub package_name: String, | ||
pub package_version: String, | ||
pub internal_interface_functions: Vec<FunctionInfo>, | ||
} | ||
|
||
impl TaintCompilerCallbacks { | ||
pub fn cast_to_dyn(&mut self) -> &mut (dyn rustc_driver::Callbacks + Send) { | ||
self | ||
} | ||
} | ||
|
||
impl rustc_driver::Callbacks for TaintCompilerCallbacks { | ||
/// All the work we do happens after analysis, so that we can make assumptions about the validity of the MIR. | ||
fn after_analysis<'tcx>( | ||
&mut self, | ||
compiler: &rustc_interface::interface::Compiler, | ||
queries: &'tcx rustc_interface::Queries<'tcx>, | ||
) -> Compilation { | ||
compiler.sess.dcx().abort_if_errors(); | ||
enter_with_fn(queries, self, mir_analysis); | ||
compiler.sess.dcx().abort_if_errors(); | ||
Compilation::Continue | ||
} | ||
} | ||
|
||
fn enter_with_fn<'tcx, TyCtxtFn>( | ||
queries: &'tcx rustc_interface::Queries<'tcx>, | ||
callback_data: &mut TaintCompilerCallbacks, | ||
enter_fn: TyCtxtFn, | ||
) where | ||
TyCtxtFn: Fn(TyCtxt, &mut TaintCompilerCallbacks), | ||
{ | ||
queries | ||
.global_ctxt() | ||
.unwrap() | ||
.enter(move |context| enter_fn(context, callback_data)); | ||
} | ||
|
||
pub struct FunctionInfo { | ||
pub function_name: String, | ||
pub body_id: rustc_hir::BodyId, | ||
pub local_def_id: rustc_hir::def_id::LocalDefId, | ||
pub span: rustc_span::Span, | ||
} | ||
|
||
struct CrateVisitor<'a, 'tcx> { | ||
pub tcx: &'a TyCtxt<'tcx>, | ||
internal_functions: Vec<FunctionInfo>, | ||
} | ||
|
||
impl<'a, 'tcx> CrateVisitor<'a, 'tcx> { | ||
pub fn new(tcx: &'a TyCtxt<'tcx>) -> Self { | ||
Self { | ||
tcx, | ||
internal_functions: Vec::default(), | ||
} | ||
} | ||
} | ||
|
||
impl<'v, 'a, 'tcx> Visitor<'v> for CrateVisitor<'a, 'tcx> { | ||
fn visit_fn( | ||
&mut self, | ||
_kind: rustc_hir::intravisit::FnKind<'v>, | ||
_decl: &'v rustc_hir::FnDecl<'v>, | ||
body_id: rustc_hir::BodyId, | ||
span: rustc_span::Span, | ||
local_def_id: rustc_hir::def_id::LocalDefId, | ||
) -> Self::Result { | ||
let function_name = self.tcx.def_path_str(local_def_id); | ||
self.internal_functions.push(FunctionInfo { | ||
body_id, | ||
span, | ||
local_def_id, | ||
function_name, | ||
}); | ||
} | ||
} | ||
|
||
pub fn mir_analysis(tcx: TyCtxt, callback_data: &mut TaintCompilerCallbacks) { | ||
// let mut finder = TaintAttributeFinder::new(tcx); | ||
|
||
let span = span!(Level::TRACE, "Public interface analysis"); | ||
let _enter = span.enter(); | ||
|
||
let mut hir_analysis = CrateVisitor::new(&tcx); | ||
tcx.hir().visit_all_item_likes_in_crate(&mut hir_analysis); | ||
|
||
for finfo in &hir_analysis.internal_functions { | ||
event!( | ||
Level::TRACE, | ||
function_name = finfo.function_name, | ||
source_code = format!("{:?}", finfo.span) | ||
); | ||
} | ||
|
||
callback_data.internal_interface_functions = | ||
std::mem::take(&mut hir_analysis.internal_functions); | ||
} |
Oops, something went wrong.