Skip to content

Commit

Permalink
Fix root filesystem exceptions on Linux (#52)
Browse files Browse the repository at this point in the history
This fixes an issue with filesystem exceptions on Linux where allowing
access to `/` would prevent creating the directory to put the old root
with `pivot_root`.

Instead, the old root is now mounted on top of the new root, removing
the necessity to create a separate directory for it. By immediately
unmounting the root, the old root then gets discarded and the new root
is accessible.
  • Loading branch information
cd-work authored Oct 12, 2023
1 parent 5d9b3d3 commit 9f1aacc
Show file tree
Hide file tree
Showing 2 changed files with 8 additions and 17 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,10 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).

- (Linux) Report invalid paths when adding exceptions

### Fixed

- (Linux) Root filesystem exceptions failing sandbox creation

## [0.4.0] - 2023-10-09

### Added
Expand Down
21 changes: 4 additions & 17 deletions src/linux/namespaces.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,15 +16,6 @@ use crate::error::Result;
/// Path for mount namespace's new root.
const NEW_ROOT: &str = "/tmp/birdcage-root";

/// Old root mount point inside the new root.
///
/// This should not conflict with any files or directories which might be
/// present in a root directory, since it will be placed in the new root.
///
/// However this is only present within the new bind mount, so it will not be
/// persisted and cannot conflict with previous mount namespace sandboxes.
const OLD_ROOT_DIR: &str = "birdcage-old-root";

/// Isolate process using Linux namespaces.
///
/// If successful, this will always clear the abstract namespace.
Expand Down Expand Up @@ -63,7 +54,6 @@ fn create_mount_namespace(bind_mounts: HashMap<PathBuf, MountFlags>) -> Result<(

// Get target paths for new and old root.
let new_root = PathBuf::from(NEW_ROOT);
let put_old = new_root.join(OLD_ROOT_DIR);

// Ensure new root is available as an empty directory.
if !new_root.exists() {
Expand All @@ -72,7 +62,6 @@ fn create_mount_namespace(bind_mounts: HashMap<PathBuf, MountFlags>) -> Result<(

// Create C-friendly versions for our paths.
let new_root_c = CString::new(new_root.as_os_str().as_bytes()).unwrap();
let put_old_c = CString::new(put_old.as_os_str().as_bytes()).unwrap();

// Create tmpfs mount for the new root, allowing pivot and ensuring directories
// aren't created outside the sandbox.
Expand Down Expand Up @@ -117,13 +106,11 @@ fn create_mount_namespace(bind_mounts: HashMap<PathBuf, MountFlags>) -> Result<(
fs::create_dir_all(&new_proc)?;
bind_mount(&old_proc_c, &new_proc_c, MountFlags::empty()).unwrap();

// Pivot root to `new_root`, placing the old root in `put_old`.
fs::create_dir_all(put_old)?;
pivot_root(&new_root_c, &put_old_c)?;
// Pivot root to `new_root`, placing the old root at the same location.
pivot_root(&new_root_c, &new_root_c)?;

// Remove the old root mount.
let new_old = PathBuf::from("/").join(OLD_ROOT_DIR);
let new_old_c = CString::new(new_old.as_os_str().as_bytes()).unwrap();
// Remove old root mounted at /, leaving only the new root at the same location.
let new_old_c = CString::new("/").unwrap();
umount(&new_old_c)?;

// Prevent child mount namespaces from accessing this namespace's mounts.
Expand Down

0 comments on commit 9f1aacc

Please sign in to comment.