From be109858ea0676f46e8c4b5100d8cf9e17740bd3 Mon Sep 17 00:00:00 2001 From: Christian Duerr Date: Sat, 14 Oct 2023 00:07:33 +0200 Subject: [PATCH 1/4] WIP: Fix mounting special files --- Cargo.toml | 15 +++++++++++++++ tests/fs_null.rs | 13 +++++++++++++ tests/fs_symlink.rs | 37 +++++++++++++++++++++++++++++++++++++ tests/fs_symlink_dir.rs | 27 +++++++++++++++++++++++++++ 4 files changed, 92 insertions(+) create mode 100644 tests/fs_null.rs create mode 100644 tests/fs_symlink.rs create mode 100644 tests/fs_symlink_dir.rs diff --git a/Cargo.toml b/Cargo.toml index a06c159..7cd500e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -39,6 +39,21 @@ name = "fs_write_also_read" path = "tests/fs_write_also_read.rs" harness = false +[[test]] +name = "fs_symlink" +path = "tests/fs_symlink.rs" +harness = false + +[[test]] +name = "fs_symlink_dir" +path = "tests/fs_symlink_dir.rs" +harness = false + +[[test]] +name = "fs_null" +path = "tests/fs_null.rs" +harness = false + [[test]] name = "full_env" path = "tests/full_env.rs" diff --git a/tests/fs_null.rs b/tests/fs_null.rs new file mode 100644 index 0000000..2a49dbf --- /dev/null +++ b/tests/fs_null.rs @@ -0,0 +1,13 @@ +use std::fs; + +use birdcage::{Birdcage, Exception, Sandbox}; + +fn main() { + // Activate our sandbox. + let mut birdcage = Birdcage::new(); + birdcage.add_exception(Exception::WriteAndRead("/dev/null".into())).unwrap(); + birdcage.lock().unwrap(); + + // Writing to `/dev/null` is allowed. + fs::write("/dev/null", "blub").unwrap(); +} diff --git a/tests/fs_symlink.rs b/tests/fs_symlink.rs new file mode 100644 index 0000000..784ea59 --- /dev/null +++ b/tests/fs_symlink.rs @@ -0,0 +1,37 @@ +use std::fs; +use std::os::unix::fs as unixfs; +use std::path::PathBuf; + +use birdcage::{Birdcage, Exception, Sandbox}; +use tempfile::NamedTempFile; + +fn main() { + const FILE_CONTENT: &str = "expected content"; + + // Setup our test files. + let private_path = NamedTempFile::new().unwrap(); + fs::write(&private_path, FILE_CONTENT.as_bytes()).unwrap(); + let public_path = NamedTempFile::new().unwrap(); + fs::write(&public_path, FILE_CONTENT.as_bytes()).unwrap(); + + // Create symlinks for the files. + let private_str = private_path.path().to_string_lossy() + "_tmpfile"; + let private = PathBuf::from(private_str.as_ref()); + let public_str = public_path.path().to_string_lossy() + "_tmpfile"; + let public = PathBuf::from(public_str.as_ref()); + unixfs::symlink(&private_path, &private).unwrap(); + unixfs::symlink(&public_path, &public).unwrap(); + + // Activate our sandbox. + let mut birdcage = Birdcage::new(); + birdcage.add_exception(Exception::Read(public.clone())).unwrap(); + birdcage.lock().unwrap(); + + // Access to the public file is allowed. + let content = fs::read_to_string(&public).unwrap(); + assert_eq!(content, FILE_CONTENT); + + // Access to the private file is prohibited. + let result = fs::read_to_string(&private); + assert!(result.is_err()); +} diff --git a/tests/fs_symlink_dir.rs b/tests/fs_symlink_dir.rs new file mode 100644 index 0000000..7b873cb --- /dev/null +++ b/tests/fs_symlink_dir.rs @@ -0,0 +1,27 @@ +use std::fs; +use std::os::unix::fs as unixfs; +use std::path::PathBuf; + +use birdcage::{Birdcage, Exception, Sandbox}; +use tempfile::TempDir; + +fn main() { + const FILE_CONTENT: &str = "expected content"; + + // Setup our test directory. + let tempdir = TempDir::new().unwrap(); + let symlink_str = tempdir.path().to_string_lossy() + "_tmpfile"; + let symlink_path = PathBuf::from(symlink_str.as_ref()); + unixfs::symlink(&tempdir, &symlink_path).unwrap(); + + // Activate our sandbox. + let mut birdcage = Birdcage::new(); + birdcage.add_exception(Exception::WriteAndRead(symlink_path.clone())).unwrap(); + birdcage.lock().unwrap(); + + // Try to create a file in the symlinked directory. + let path = symlink_path.join("tmpfile"); + fs::write(&path, FILE_CONTENT.as_bytes()).unwrap(); + let content = fs::read_to_string(&path).unwrap(); + assert_eq!(content, FILE_CONTENT); +} From 88ce98f99c85bf4221b3ad4197d75b974cdb2009 Mon Sep 17 00:00:00 2001 From: Christian Duerr Date: Mon, 16 Oct 2023 14:22:14 +0200 Subject: [PATCH 2/4] Fix exceptions for special files This fixes sandboxing exceptions for special files on Linux. Previously birdcage would explicitly panic. --- src/linux/namespaces.rs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/linux/namespaces.rs b/src/linux/namespaces.rs index ef73a5f..d01b7b3 100644 --- a/src/linux/namespaces.rs +++ b/src/linux/namespaces.rs @@ -151,12 +151,10 @@ fn copy_tree(src: impl AsRef, dst: impl AsRef) -> Result<()> { // Create target file/directory. let metadata = src_sub.metadata()?; - if metadata.is_file() { - File::create(&dst)?; - } else if metadata.is_dir() { + if metadata.is_dir() { fs::create_dir(&dst)?; } else { - unreachable!("metadata call failed to follow symlink"); + File::create(&dst)?; } // Copy permissions. From 74349ddb6fc3bf68a587daed6257581fe1612932 Mon Sep 17 00:00:00 2001 From: Christian Duerr Date: Mon, 16 Oct 2023 23:32:36 +0200 Subject: [PATCH 3/4] Add changelog entry --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4765e43..f3bf52f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,6 +17,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). - (Linux) Root filesystem exceptions failing sandbox creation - (Linux) Sandbox not enforcing readonly/noexec restrictions +- (Linux) Exceptions for special files (i.e. /dev/null) ## [0.4.0] - 2023-10-09 From d0843dffe41438d0286396bf213840ced140ccca Mon Sep 17 00:00:00 2001 From: Christian Duerr Date: Mon, 16 Oct 2023 23:47:35 +0200 Subject: [PATCH 4/4] Add test for broken symlinks --- Cargo.toml | 5 +++++ tests/fs_broken_symlink.rs | 30 ++++++++++++++++++++++++++++++ 2 files changed, 35 insertions(+) create mode 100644 tests/fs_broken_symlink.rs diff --git a/Cargo.toml b/Cargo.toml index 7cd500e..0b07bf6 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -49,6 +49,11 @@ name = "fs_symlink_dir" path = "tests/fs_symlink_dir.rs" harness = false +[[test]] +name = "fs_broken_symlink" +path = "tests/fs_broken_symlink.rs" +harness = false + [[test]] name = "fs_null" path = "tests/fs_null.rs" diff --git a/tests/fs_broken_symlink.rs b/tests/fs_broken_symlink.rs new file mode 100644 index 0000000..e8d8bce --- /dev/null +++ b/tests/fs_broken_symlink.rs @@ -0,0 +1,30 @@ +use std::fs; +use std::os::unix::fs as unixfs; +use std::path::PathBuf; + +use birdcage::error::Error; +use birdcage::{Birdcage, Exception, Sandbox}; +use tempfile::NamedTempFile; + +fn main() { + // 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"; + let symlink = PathBuf::from(symlink_str.as_ref()); + unixfs::symlink(&tempfile, &symlink).unwrap(); + drop(tempfile); + assert!(!tempfile_path.exists()); + + // Sandbox exception fails with invalid path error. + let mut birdcage = Birdcage::new(); + let result = birdcage.add_exception(Exception::Read(symlink.clone())); + assert!(matches!(result, Err(Error::InvalidPath(_)))); + birdcage.lock().unwrap(); + + // Read/Write results in error. + let result = fs::read_to_string(&symlink); + assert!(result.is_err()); + let result = fs::write(&symlink, "bob"); + assert!(result.is_err()); +}