diff --git a/integration/canonicalize.rs b/integration/canonicalize.rs index 8c9bb26..3ea01b0 100644 --- a/integration/canonicalize.rs +++ b/integration/canonicalize.rs @@ -1,10 +1,11 @@ use std::fs; +use std::path::PathBuf; use birdcage::{Birdcage, Exception, Sandbox}; use crate::TestSetup; -pub fn setup() -> TestSetup { +pub fn setup(_tempdir: PathBuf) -> TestSetup { let mut sandbox = Birdcage::new(); sandbox.add_exception(Exception::Read("./".into())).unwrap(); diff --git a/integration/consistent_id_mappings.rs b/integration/consistent_id_mappings.rs index 5b77326..fd677e6 100644 --- a/integration/consistent_id_mappings.rs +++ b/integration/consistent_id_mappings.rs @@ -1,3 +1,4 @@ +use std::path::PathBuf; use birdcage::{Birdcage, Sandbox}; use serde::{Deserialize, Serialize}; @@ -11,7 +12,7 @@ struct TestData { egid: u32, } -pub fn setup() -> TestSetup { +pub fn setup(_tempdir: PathBuf) -> TestSetup { let uid = unsafe { libc::getuid() }; let gid = unsafe { libc::getgid() }; let euid = unsafe { libc::geteuid() }; diff --git a/integration/delete_before_lockdown.rs b/integration/delete_before_lockdown.rs index f0ad37b..751a91f 100644 --- a/integration/delete_before_lockdown.rs +++ b/integration/delete_before_lockdown.rs @@ -1,10 +1,11 @@ +use std::path::PathBuf; use birdcage::{Birdcage, Exception, Sandbox}; use tempfile::NamedTempFile; use crate::TestSetup; -pub fn setup() -> TestSetup { +pub fn setup(_tempdir: PathBuf) -> TestSetup { // Create temporary file. let tempfile = NamedTempFile::new().unwrap(); diff --git a/integration/env.rs b/integration/env.rs index 80e0bfa..b9a4670 100644 --- a/integration/env.rs +++ b/integration/env.rs @@ -1,10 +1,11 @@ +use std::path::PathBuf; use std::env; use birdcage::{Birdcage, Exception, Sandbox}; use crate::TestSetup; -pub fn setup() -> TestSetup { +pub fn setup(_tempdir: PathBuf) -> TestSetup { // Setup our environment variables env::set_var("PUBLIC", "GOOD"); env::set_var("PRIVATE", "BAD"); diff --git a/integration/exec.rs b/integration/exec.rs index 1557360..e551764 100644 --- a/integration/exec.rs +++ b/integration/exec.rs @@ -1,3 +1,4 @@ +use std::path::PathBuf; use std::fs; use std::process::Command; @@ -5,7 +6,7 @@ use birdcage::{Birdcage, Exception, Sandbox}; use crate::TestSetup; -pub fn setup() -> TestSetup { +pub fn setup(_tempdir: PathBuf) -> TestSetup { let mut sandbox = Birdcage::new(); sandbox.add_exception(Exception::ExecuteAndRead("/usr/bin/true".into())).unwrap(); diff --git a/integration/exec_symlinked_dir.rs b/integration/exec_symlinked_dir.rs index 2f141b3..c7ab4b2 100644 --- a/integration/exec_symlinked_dir.rs +++ b/integration/exec_symlinked_dir.rs @@ -12,9 +12,8 @@ struct TestData { symlink_dir: PathBuf, } -pub fn setup() -> TestSetup { +pub fn setup(tempdir: PathBuf) -> TestSetup { // Create symlinked executable dir. - let tempdir = tempfile::tempdir().unwrap().into_path(); let symlink_dir = tempdir.join("bin"); unixfs::symlink("/usr/bin", &symlink_dir).unwrap(); diff --git a/integration/exec_symlinked_dirs_exec.rs b/integration/exec_symlinked_dirs_exec.rs index d4e9c6b..1f6c94a 100644 --- a/integration/exec_symlinked_dirs_exec.rs +++ b/integration/exec_symlinked_dirs_exec.rs @@ -12,9 +12,8 @@ struct TestData { symlink_dir_exec: PathBuf, } -pub fn setup() -> TestSetup { +pub fn setup(tempdir: PathBuf) -> TestSetup { // Create symlinked executable dir. - let tempdir = tempfile::tempdir().unwrap().into_path(); let symlink_dir = tempdir.join("bin"); let symlink_dir_exec = symlink_dir.join("true"); unixfs::symlink("/usr/bin", &symlink_dir).unwrap(); diff --git a/integration/exec_symlinked_file.rs b/integration/exec_symlinked_file.rs index 75960a0..676cc83 100644 --- a/integration/exec_symlinked_file.rs +++ b/integration/exec_symlinked_file.rs @@ -13,9 +13,8 @@ struct TestData { symlink_exec: PathBuf, } -pub fn setup() -> TestSetup { +pub fn setup(tempdir: PathBuf) -> TestSetup { // Create symlinked executable. - let tempdir = tempfile::tempdir().unwrap().into_path(); let exec_dir = tempdir.join("bin"); fs::create_dir(&exec_dir).unwrap(); let symlink_exec = exec_dir.join("true"); diff --git a/integration/fs.rs b/integration/fs.rs index 70e90ac..6dffa36 100644 --- a/integration/fs.rs +++ b/integration/fs.rs @@ -3,7 +3,6 @@ use std::path::PathBuf; use birdcage::{Birdcage, Exception, Sandbox}; use serde::{Deserialize, Serialize}; -use tempfile::NamedTempFile; use crate::TestSetup; @@ -15,11 +14,11 @@ struct TestData { private_path: PathBuf, } -pub fn setup() -> TestSetup { +pub fn setup(tempdir: PathBuf) -> TestSetup { // Setup our test files. - let private_path = NamedTempFile::new().unwrap().into_temp_path().keep().unwrap(); + let private_path = tempdir.join("private"); fs::write(&private_path, FILE_CONTENT.as_bytes()).unwrap(); - let public_path = NamedTempFile::new().unwrap().into_temp_path().keep().unwrap(); + let public_path = tempdir.join("public"); fs::write(&public_path, FILE_CONTENT.as_bytes()).unwrap(); // Setup sandbox exceptions. diff --git a/integration/fs_broken_symlink.rs b/integration/fs_broken_symlink.rs index 7981dba..9fd514e 100644 --- a/integration/fs_broken_symlink.rs +++ b/integration/fs_broken_symlink.rs @@ -1,11 +1,10 @@ -use std::fs; +use std::fs::{self, File}; use std::os::unix::fs as unixfs; use std::path::PathBuf; use birdcage::error::Error; use birdcage::{Birdcage, Exception, Sandbox}; use serde::{Deserialize, Serialize}; -use tempfile::NamedTempFile; use crate::TestSetup; @@ -14,14 +13,18 @@ struct TestData { symlink: PathBuf, } -pub fn setup() -> TestSetup { - // Setup a symlink without target. - let tempfile = NamedTempFile::new().unwrap(); - let tempfile_path = tempfile.path().to_path_buf(); - let symlink_str = tempfile_path.to_string_lossy() + "_tmpfile"; +pub fn setup(tempdir: PathBuf) -> TestSetup { + // Create a target for the symlink. + let tempfile_path = tempdir.join("broken_target"); + File::create(&tempfile_path).unwrap(); + + // Setup a symlink to the target file. + let symlink_str = tempfile_path.to_string_lossy() + "_symlink"; let symlink = PathBuf::from(symlink_str.as_ref()); - unixfs::symlink(&tempfile, &symlink).unwrap(); - drop(tempfile); + unixfs::symlink(&tempfile_path, &symlink).unwrap(); + + // Remove the target, breaking the symlink. + fs::remove_file(&tempfile_path).unwrap(); assert!(!tempfile_path.exists()); // Sandbox exception fails with invalid path error. diff --git a/integration/fs_null.rs b/integration/fs_null.rs index 07a7db4..040d59a 100644 --- a/integration/fs_null.rs +++ b/integration/fs_null.rs @@ -1,10 +1,11 @@ +use std::path::PathBuf; use std::fs; use birdcage::{Birdcage, Exception, Sandbox}; use crate::TestSetup; -pub fn setup() -> TestSetup { +pub fn setup(_tempdir: PathBuf) -> TestSetup { // Activate our sandbox. let mut sandbox = Birdcage::new(); sandbox.add_exception(Exception::WriteAndRead("/dev/null".into())).unwrap(); diff --git a/integration/fs_readonly.rs b/integration/fs_readonly.rs index fecc4ab..e7e3e10 100644 --- a/integration/fs_readonly.rs +++ b/integration/fs_readonly.rs @@ -3,7 +3,6 @@ use std::path::PathBuf; use birdcage::{Birdcage, Exception, Sandbox}; use serde::{Deserialize, Serialize}; -use tempfile::NamedTempFile; use crate::TestSetup; @@ -14,9 +13,9 @@ struct TestData { file: PathBuf, } -pub fn setup() -> TestSetup { +pub fn setup(tempdir: PathBuf) -> TestSetup { // Setup the test file. - let file = NamedTempFile::new().unwrap().into_temp_path().keep().unwrap(); + let file = tempdir.join("fs_readonly"); fs::write(&file, FILE_CONTENT.as_bytes()).unwrap(); // Activate our sandbox. diff --git a/integration/fs_restrict_child.rs b/integration/fs_restrict_child.rs index d5811f2..516f9c3 100644 --- a/integration/fs_restrict_child.rs +++ b/integration/fs_restrict_child.rs @@ -14,9 +14,8 @@ struct TestData { tempdir: PathBuf, } -pub fn setup() -> TestSetup { +pub fn setup(tempdir: PathBuf) -> TestSetup { // Setup our test tree. - let tempdir = tempfile::tempdir().unwrap().into_path(); let tempfile = tempdir.join("target-file"); fs::write(&tempfile, FILE_CONTENT.as_bytes()).unwrap(); diff --git a/integration/fs_symlink.rs b/integration/fs_symlink.rs index 034fb68..23408eb 100644 --- a/integration/fs_symlink.rs +++ b/integration/fs_symlink.rs @@ -4,7 +4,6 @@ use std::path::PathBuf; use birdcage::{Birdcage, Exception, Sandbox}; use serde::{Deserialize, Serialize}; -use tempfile::NamedTempFile; use crate::TestSetup; @@ -16,11 +15,11 @@ struct TestData { public: PathBuf, } -pub fn setup() -> TestSetup { +pub fn setup(tempdir: PathBuf) -> TestSetup { // Setup our test files. - let private_path = NamedTempFile::new().unwrap().into_temp_path().keep().unwrap(); + let private_path = tempdir.join("private"); fs::write(&private_path, FILE_CONTENT.as_bytes()).unwrap(); - let public_path = NamedTempFile::new().unwrap().into_temp_path().keep().unwrap(); + let public_path = tempdir.join("public"); fs::write(&public_path, FILE_CONTENT.as_bytes()).unwrap(); // Create symlinks for the files. diff --git a/integration/fs_symlink_dir.rs b/integration/fs_symlink_dir.rs index 5ec06f4..7b35a12 100644 --- a/integration/fs_symlink_dir.rs +++ b/integration/fs_symlink_dir.rs @@ -4,7 +4,6 @@ use std::path::PathBuf; use birdcage::{Birdcage, Exception, Sandbox}; use serde::{Deserialize, Serialize}; -use tempfile::TempDir; use crate::TestSetup; @@ -12,22 +11,22 @@ const FILE_CONTENT: &str = "expected content"; #[derive(Serialize, Deserialize)] struct TestData { - symlink_path: PathBuf, + symlink: PathBuf, } -pub fn setup() -> TestSetup { +pub fn setup(tempdir: PathBuf) -> TestSetup { // Setup our test directory. - let tempdir = TempDir::new().unwrap().into_path(); - let symlink_str = tempdir.to_string_lossy() + "_tmpfile"; - let symlink_path = PathBuf::from(symlink_str.as_ref()); - unixfs::symlink(&tempdir, &symlink_path).unwrap(); + let symlink_target = tempdir.join("target"); + fs::create_dir(symlink_target).unwrap(); + let symlink = tempdir.join("symlink"); + unixfs::symlink(&tempdir, &symlink).unwrap(); // Activate our sandbox. let mut sandbox = Birdcage::new(); - sandbox.add_exception(Exception::WriteAndRead(symlink_path.clone())).unwrap(); + sandbox.add_exception(Exception::WriteAndRead(symlink.clone())).unwrap(); // Serialize test data. - let data = TestData { symlink_path }; + let data = TestData { symlink }; let data = serde_json::to_string(&data).unwrap(); TestSetup { sandbox, data } @@ -38,7 +37,7 @@ pub fn validate(data: String) { let data: TestData = serde_json::from_str(&data).unwrap(); // Try to create a file in the symlinked directory. - let path = data.symlink_path.join("tmpfile"); + let path = data.symlink.join("tmpfile"); fs::write(&path, FILE_CONTENT.as_bytes()).unwrap(); let content = fs::read_to_string(&path).unwrap(); assert_eq!(content, FILE_CONTENT); diff --git a/integration/fs_symlink_dir_separate_perms.rs b/integration/fs_symlink_dir_separate_perms.rs index b33eb5f..98fa79c 100644 --- a/integration/fs_symlink_dir_separate_perms.rs +++ b/integration/fs_symlink_dir_separate_perms.rs @@ -4,7 +4,6 @@ use std::path::PathBuf; use birdcage::{Birdcage, Exception, Sandbox}; use serde::{Deserialize, Serialize}; -use tempfile::TempDir; use crate::TestSetup; @@ -15,9 +14,8 @@ struct TestData { symlink_src: PathBuf, } -pub fn setup() -> TestSetup { +pub fn setup(tempdir: PathBuf) -> TestSetup { // Setup our test directories. - let tempdir = TempDir::new().unwrap().into_path(); let symlink_src = tempdir.join("src"); fs::create_dir(&symlink_src).unwrap(); let symlink_dst = tempdir.join("dst"); diff --git a/integration/fs_write_also_read.rs b/integration/fs_write_also_read.rs index 00e46ad..4d53443 100644 --- a/integration/fs_write_also_read.rs +++ b/integration/fs_write_also_read.rs @@ -1,9 +1,8 @@ -use std::fs; +use std::fs::{self, File}; use std::path::PathBuf; use birdcage::{Birdcage, Exception, Sandbox}; use serde::{Deserialize, Serialize}; -use tempfile::NamedTempFile; use crate::TestSetup; @@ -11,19 +10,20 @@ const FILE_CONTENT: &str = "expected content"; #[derive(Serialize, Deserialize)] struct TestData { - file: PathBuf, + path: PathBuf, } -pub fn setup() -> TestSetup { +pub fn setup(tempdir: PathBuf) -> TestSetup { // Setup our test files. - let file = NamedTempFile::new().unwrap().into_temp_path().keep().unwrap(); + let path = tempdir.join("fs_write_also_read"); + File::create(&path).unwrap(); // Activate our sandbox. let mut sandbox = Birdcage::new(); - sandbox.add_exception(Exception::WriteAndRead(file.clone())).unwrap(); + sandbox.add_exception(Exception::WriteAndRead(path.clone())).unwrap(); // Serialize test data. - let data = TestData { file }; + let data = TestData { path }; let data = serde_json::to_string(&data).unwrap(); TestSetup { sandbox, data } @@ -34,9 +34,9 @@ pub fn validate(data: String) { let data: TestData = serde_json::from_str(&data).unwrap(); // Write access is allowed. - fs::write(&data.file, FILE_CONTENT.as_bytes()).unwrap(); + fs::write(&data.path, FILE_CONTENT.as_bytes()).unwrap(); // Read access is allowed. - let content = fs::read_to_string(data.file).unwrap(); + let content = fs::read_to_string(data.path).unwrap(); assert_eq!(content, FILE_CONTENT); } diff --git a/integration/full_env.rs b/integration/full_env.rs index 3347895..a9372e0 100644 --- a/integration/full_env.rs +++ b/integration/full_env.rs @@ -1,10 +1,11 @@ +use std::path::PathBuf; use std::env; use birdcage::{Birdcage, Exception, Sandbox}; use crate::TestSetup; -pub fn setup() -> TestSetup { +pub fn setup(_tempdir: PathBuf) -> TestSetup { // Setup our environment variables env::set_var("PUBLIC", "GOOD"); diff --git a/integration/full_sandbox.rs b/integration/full_sandbox.rs index 286b19d..b83038c 100644 --- a/integration/full_sandbox.rs +++ b/integration/full_sandbox.rs @@ -5,7 +5,6 @@ use std::{env, fs}; use birdcage::{Birdcage, Sandbox}; use serde::{Deserialize, Serialize}; -use tempfile::NamedTempFile; use crate::TestSetup; @@ -14,11 +13,11 @@ struct TestData { path: PathBuf, } -pub fn setup() -> TestSetup { +pub fn setup(tempdir: PathBuf) -> TestSetup { const FILE_CONTENT: &str = "expected content"; // Create testfile. - let path = NamedTempFile::new().unwrap().into_temp_path().keep().unwrap(); + let path = tempdir.join("full_sandbox"); // Ensure non-sandboxed write works. fs::write(&path, FILE_CONTENT.as_bytes()).unwrap(); diff --git a/integration/harness.rs b/integration/harness.rs index 69388bb..4a40405 100644 --- a/integration/harness.rs +++ b/integration/harness.rs @@ -1,3 +1,4 @@ +use std::path::PathBuf; use std::process::{self, Command, Stdio}; use birdcage::{Birdcage, Exception, Sandbox}; @@ -57,9 +58,13 @@ fn main() { }; // Run setup or test validation. - match args.next() { - Some(test_data) => test.2(test_data), - None => run_setup(&test_name, &test.1), + let arg = args.next().unwrap(); + match arg.as_str() { + "--setup" => { + let tempdir = args.next().unwrap(); + run_setup(&test_name, tempdir, &test.1); + }, + _ => test.2(arg), } } @@ -71,18 +76,22 @@ fn spawn_tests() { // Spawn child processes for all tests. let current_exe = std::env::current_exe().unwrap(); - let children: Vec<_> = TESTS - .iter() - .map(|(cmd, ..)| { - let child = - Command::new(¤t_exe).args([cmd]).stderr(Stdio::piped()).spawn().unwrap(); - (cmd, child) - }) - .collect(); + let mut children = Vec::new(); + for (cmd, ..) in TESTS { + let tempdir = tempfile::tempdir().unwrap(); + let child = Command::new(¤t_exe) + .arg(cmd) + .arg("--setup") + .arg(tempdir.path()) + .stderr(Stdio::piped()) + .spawn() + .unwrap(); + children.push((cmd, child, tempdir)); + } // Check results for each test. let mut passed = 0; - for (name, child) in children { + for (name, child, tempdir) in children { let output = match child.wait_with_output() { Ok(output) => output, Err(err) => { @@ -104,6 +113,9 @@ fn spawn_tests() { eprintln!("test {TEST_DIR}/{name}.rs ... \x1b[32mok\x1b[0m"); passed += 1; } + + // Cleanup tempdir. + tempdir.close().unwrap(); } // Print total results. @@ -118,9 +130,9 @@ fn spawn_tests() { } /// Run test's setup step and spawn validation child. -fn run_setup(test_name: &str, setup: &fn() -> TestSetup) { +fn run_setup(test_name: &str, tempdir: String, setup: &fn(PathBuf) -> TestSetup) { // Run test setup. - let mut test_setup = setup(); + let mut test_setup = setup(PathBuf::from(tempdir)); // Add exceptions to allow self-execution. let current_exe = std::env::current_exe().unwrap(); @@ -150,7 +162,7 @@ macro_rules! test_mods { mod $mod; )* - const TESTS: &[(&str, fn() -> $crate::TestSetup, fn(String))] = &[$( + const TESTS: &[(&str, fn(std::path::PathBuf) -> $crate::TestSetup, fn(String))] = &[$( $( #[$cfg] )? (stringify!($mod), $mod :: setup, $mod :: validate), )*]; diff --git a/integration/missing_exception.rs b/integration/missing_exception.rs index a0ce814..bee797d 100644 --- a/integration/missing_exception.rs +++ b/integration/missing_exception.rs @@ -5,7 +5,7 @@ use birdcage::{Birdcage, Exception, Sandbox}; use crate::TestSetup; -pub fn setup() -> TestSetup { +pub fn setup(_tempdir: PathBuf) -> TestSetup { let mut sandbox = Birdcage::new(); // Add a path that doesn't exist. diff --git a/integration/net.rs b/integration/net.rs index 19516e7..4b925e0 100644 --- a/integration/net.rs +++ b/integration/net.rs @@ -1,10 +1,11 @@ +use std::path::PathBuf; use std::net::TcpStream; use birdcage::{Birdcage, Exception, Sandbox}; use crate::TestSetup; -pub fn setup() -> TestSetup { +pub fn setup(_tempdir: PathBuf) -> TestSetup { // Setup sandbox exceptions. let mut sandbox = Birdcage::new(); sandbox.add_exception(Exception::Networking).unwrap(); diff --git a/integration/seccomp.rs b/integration/seccomp.rs index 32d209e..3e3d78d 100644 --- a/integration/seccomp.rs +++ b/integration/seccomp.rs @@ -1,10 +1,11 @@ +use std::path::PathBuf; use std::ffi::CString; use birdcage::{Birdcage, Sandbox}; use crate::TestSetup; -pub fn setup() -> TestSetup { +pub fn setup(_tempdir: PathBuf) -> TestSetup { TestSetup { sandbox: Birdcage::new(), data: String::new() } } diff --git a/src/lib.rs b/src/lib.rs index 2c8695e..d30a575 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -10,13 +10,9 @@ //! use std::process::Command; //! //! use birdcage::{Birdcage, Exception, Sandbox}; -//! use tempfile::NamedTempFile; -//! -//! // Setup our test file. -//! let file = NamedTempFile::new().unwrap(); //! //! // Reads without sandbox work. -//! fs::read_to_string(file.path()).unwrap(); +//! fs::read_to_string("./Cargo.toml").unwrap(); //! //! // Allow access to our test executable. //! let mut sandbox = Birdcage::new(); @@ -26,7 +22,7 @@ //! //! // Initialize the sandbox; by default everything is prohibited. //! let mut command = Command::new("/bin/cat"); -//! command.arg(file.path()); +//! command.arg("./Cargo.toml"); //! let mut child = sandbox.spawn(command).unwrap(); //! //! // Reads with sandbox should fail.