Skip to content

Commit

Permalink
Fix intermediate symlink directories
Browse files Browse the repository at this point in the history
  • Loading branch information
cd-work committed Oct 26, 2023
1 parent 6b220da commit 4dedcc2
Show file tree
Hide file tree
Showing 3 changed files with 60 additions and 8 deletions.
5 changes: 5 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,11 @@ name = "exec"
path = "tests/exec.rs"
harness = false

[[test]]
name = "exec_symlinked"
path = "tests/exec_symlinked.rs"
harness = false

[[test]]
name = "fs"
path = "tests/fs.rs"
Expand Down
22 changes: 14 additions & 8 deletions src/linux/namespaces.rs
Original file line number Diff line number Diff line change
Expand Up @@ -74,15 +74,23 @@ fn create_mount_namespace(bind_mounts: HashMap<PathBuf, MountAttrFlags>) -> Resu
let mut symlinks = Vec::new();
let mut bind_mounts = bind_mounts
.into_iter()
.filter_map(|(path, exception)| {
let canonicalized = path.canonicalize().ok()?;
.filter_map(|(path, exception)| match path.read_link() {
// Handle paths where final component is a symbolic link.
Ok(target) => {
let canonicalized = path.canonicalize().ok()?;

// Store original symlink path to create it if necessary.
if let Ok(target) = path.read_link() {
// Store original symlink path to create it if necessary.
symlinks.push((path, target));
}

Some((canonicalized, exception))
Some((canonicalized, exception))
},
// Handle paths where final component is a file or directory.
Err(_) => {
// Ensure path is absolute, without following symlinks.
let absolute = absolute(&path).ok()?;
let normalized = normalize_path(&absolute);
Some((normalized, exception))
},
})
.collect::<Vec<_>>();

Expand Down Expand Up @@ -194,8 +202,6 @@ fn copy_tree(src: impl AsRef<Path>, dst: impl AsRef<Path>) -> Result<()> {
src_sub = src_sub.join(component);
dst = dst.join(component);

// TODO: symlink_metadata().is_ok()?
//
// Skip nodes that already exist.
if dst.exists() {
continue;
Expand Down
41 changes: 41 additions & 0 deletions tests/exec_symlinked.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
use std::fs;
use std::os::unix::fs as unixfs;
use std::path::PathBuf;
use std::process::Command;

use birdcage::{Birdcage, Exception, Sandbox};

fn main() {
// 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");
unixfs::symlink("/usr/bin/true", &symlink_exec).unwrap();

// Create symlinked dir with non-symlinked executable.
let truer_path = exec_dir.join("truer");
fs::copy("/usr/bin/true", &truer_path).unwrap();
let symlink_dir = tempdir.join("symbin");
let symlink_dir_exec = symlink_dir.join("truer");
unixfs::symlink(&exec_dir, &symlink_dir).unwrap();

let mut birdcage = Birdcage::new();
birdcage.add_exception(Exception::ExecuteAndRead(symlink_dir_exec.clone())).unwrap();
birdcage.add_exception(Exception::ExecuteAndRead(symlink_exec.clone())).unwrap();
if PathBuf::from("/lib64").exists() {
birdcage.add_exception(Exception::ExecuteAndRead("/lib64".into())).unwrap();
}
if PathBuf::from("/lib").exists() {
birdcage.add_exception(Exception::ExecuteAndRead("/lib".into())).unwrap();
}
birdcage.lock().unwrap();

// Ensure symlinked executable works.
let cmd = Command::new(symlink_exec).status().unwrap();
assert!(cmd.success());

// Ensure symlinked dir's executable works.
let cmd = Command::new(symlink_dir_exec).status().unwrap();
assert!(cmd.success());
}

0 comments on commit 4dedcc2

Please sign in to comment.