Skip to content

Commit

Permalink
add-test-linux_rootfs_propagation
Browse files Browse the repository at this point in the history
Signed-off-by: Yusuke Sakurai <[email protected]>
  • Loading branch information
saku3 committed Jan 2, 2025
1 parent 792f359 commit c87a97e
Show file tree
Hide file tree
Showing 8 changed files with 218 additions and 1 deletion.
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 3 additions & 0 deletions tests/contest/contest/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ use crate::tests::process_rlimits::get_process_rlimits_test;
use crate::tests::process_user::get_process_user_test;
use crate::tests::readonly_paths::get_ro_paths_test;
use crate::tests::root_readonly_true::get_root_readonly_test;
use crate::tests::rootfs_propagation::get_rootfs_propagation_test;
use crate::tests::scheduler::get_scheduler_test;
use crate::tests::seccomp::get_seccomp_test;
use crate::tests::seccomp_notify::get_seccomp_notify_test;
Expand Down Expand Up @@ -127,6 +128,7 @@ fn main() -> Result<()> {
let no_pivot = get_no_pivot_test();
let process_oom_score_adj = get_process_oom_score_adj_test();
let fd_control = get_fd_control_test();
let rootfs_propagation = get_rootfs_propagation_test();

tm.add_test_group(Box::new(cl));
tm.add_test_group(Box::new(cc));
Expand Down Expand Up @@ -157,6 +159,7 @@ fn main() -> Result<()> {
tm.add_test_group(Box::new(no_pivot));
tm.add_test_group(Box::new(process_oom_score_adj));
tm.add_test_group(Box::new(fd_control));
tm.add_test_group(Box::new(rootfs_propagation));

tm.add_test_group(Box::new(io_priority_test));
tm.add_cleanup(Box::new(cgroups::cleanup_v1));
Expand Down
1 change: 1 addition & 0 deletions tests/contest/contest/src/tests/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ pub mod process_rlimits;
pub mod process_user;
pub mod readonly_paths;
pub mod root_readonly_true;
pub mod rootfs_propagation;
pub mod scheduler;
pub mod seccomp;
pub mod seccomp_notify;
Expand Down
2 changes: 2 additions & 0 deletions tests/contest/contest/src/tests/rootfs_propagation/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
mod rootfs_propagation_test;
pub use rootfs_propagation_test::get_rootfs_propagation_test;
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
use anyhow::{Context, Ok, Result};
use oci_spec::runtime::{
Capability, LinuxBuilder, LinuxCapabilitiesBuilder, LinuxSeccompBuilder, ProcessBuilder,
RootBuilder, Spec, SpecBuilder,
};
use test_framework::{test_result, Test, TestGroup, TestResult};

use crate::utils::test_inside_container;
use crate::utils::test_utils::CreateOptions;

fn create_spec(propagation: String) -> Result<Spec> {
let root = RootBuilder::default()
.readonly(false)
.build()
.context("failed to build root")?;

let capabilities = LinuxCapabilitiesBuilder::default()
.bounding([Capability::SysAdmin])
.effective([Capability::SysAdmin])
.inheritable([Capability::SysAdmin])
.permitted([Capability::SysAdmin])
.ambient([Capability::SysAdmin])
.build()
.context("failed to build linux capabilities")?;

let process = ProcessBuilder::default()
.args(vec![
"runtimetest".to_string(),
"rootfs_propagation".to_string(),
])
.capabilities(capabilities)
.build()
.context("failed to build process")?;

let seccomp = LinuxSeccompBuilder::default()
.build()
.context("failed to build seccomp")?;

let linux = LinuxBuilder::default()
.rootfs_propagation(propagation)
.seccomp(seccomp)
.build()
.context("failed to build linux spec")?;

let spec = SpecBuilder::default()
.root(root)
.linux(linux)
.process(process)
.build()
.context("failed to build spec")?;

Ok(spec)
}

fn rootfs_propagation_shared_test() -> TestResult {
let spec = test_result!(create_spec("shared".to_string()));
test_inside_container(spec, &CreateOptions::default(), &|_| Ok(()))
}

fn rootfs_propagation_slave_test() -> TestResult {
let spec = test_result!(create_spec("slave".to_string()));
test_inside_container(spec, &CreateOptions::default(), &|_| Ok(()))
}

fn rootfs_propagation_private_test() -> TestResult {
let spec = test_result!(create_spec("private".to_string()));
test_inside_container(spec, &CreateOptions::default(), &|_| Ok(()))
}

fn rootfs_propagation_unbindable_test() -> TestResult {
let spec = test_result!(create_spec("unbindable".to_string()));
test_inside_container(spec, &CreateOptions::default(), &|_| Ok(()))
}

pub fn get_rootfs_propagation_test() -> TestGroup {
let mut rootfs_propagation_test_group = TestGroup::new("rootfs_propagation");

let rootfs_propagation_shared_test = Test::new(
"rootfs_propagation_shared_test",
Box::new(rootfs_propagation_shared_test),
);
let rootfs_propagation_slave_test = Test::new(
"rootfs_propagation_slave_test",
Box::new(rootfs_propagation_slave_test),
);
let rootfs_propagation_private_test = Test::new(
"rootfs_propagation_private_test",
Box::new(rootfs_propagation_private_test),
);
let rootfs_propagation_unbindable_test = Test::new(
"rootfs_propagation_unbindable_test",
Box::new(rootfs_propagation_unbindable_test),
);
rootfs_propagation_test_group.add(vec![
Box::new(rootfs_propagation_shared_test),
Box::new(rootfs_propagation_slave_test),
Box::new(rootfs_propagation_private_test),
Box::new(rootfs_propagation_unbindable_test),
]);

rootfs_propagation_test_group
}
1 change: 1 addition & 0 deletions tests/contest/runtimetest/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,4 @@ nix = "0.28.0"
anyhow = "1.0"
libc = "0.2.169" # TODO (YJDoc2) upgrade to latest
nc = "0.9.5"
tempfile = "3"
1 change: 1 addition & 0 deletions tests/contest/runtimetest/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ fn main() {
"no_pivot" => tests::validate_rootfs(),
"process_oom_score_adj" => tests::validate_process_oom_score_adj(&spec),
"fd_control" => tests::validate_fd_control(&spec),
"rootfs_propagation" => tests::validate_rootfs_propagation(&spec),
_ => eprintln!("error due to unexpected execute test name: {execute_test}"),
}
}
108 changes: 107 additions & 1 deletion tests/contest/runtimetest/src/tests.rs
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
use std::env;
use std::ffi::OsStr;
use std::fs::{self, read_dir};
use std::fs::{self, read_dir, File};
use std::os::linux::fs::MetadataExt;
use std::os::unix::fs::{FileTypeExt, PermissionsExt};
use std::path::Path;

use anyhow::{bail, Result};
use nix::errno::Errno;
use nix::libc;
use nix::mount::{mount, MsFlags};
use nix::sys::resource::{getrlimit, Resource};
use nix::sys::stat::{umask, Mode};
use nix::sys::utsname;
Expand All @@ -16,6 +17,7 @@ use oci_spec::runtime::IOPriorityClass::{self, IoprioClassBe, IoprioClassIdle, I
use oci_spec::runtime::{
LinuxDevice, LinuxDeviceType, LinuxSchedulerPolicy, PosixRlimit, PosixRlimitType, Spec,
};
use tempfile::Builder;

use crate::utils::{
self, test_dir_read_access, test_dir_write_access, test_read_access, test_write_access,
Expand Down Expand Up @@ -820,3 +822,107 @@ pub fn validate_fd_control(_spec: &Spec) {
eprintln!("mismatched fds inside container! {:?}", fd_details);
}
}

pub fn validate_rootfs_propagation(spec: &Spec) {
let linux = spec.linux().as_ref().unwrap();
let propagation = linux.rootfs_propagation().as_ref().unwrap();

let target_dir = Builder::new()
.prefix("target")
.tempdir()
.expect("Failed to create target directory");
let target_path = target_dir.path();

match propagation.as_str() {
"shared" | "slave" | "private" => {
if let Err(e) = mount(
Some("/"),
target_dir.path(),
None::<&str>,
MsFlags::MS_BIND | MsFlags::MS_REC,
None::<&str>,
) {
eprintln!("bind-mount / {}: {}", target_dir.path().display(), e);
}

let mount_dir = Builder::new()
.prefix("mount")
.tempdir()
.expect("Failed to create mount directory");
let test_dir = Builder::new()
.prefix("test")
.tempdir()
.expect("Failed to create mount directory");
let tmpfile_path = test_dir.path().join("example");
let _file = File::create(&tmpfile_path)
.map_err(|e| format!("Failed to create temp file: {}", e));

mount(
Some(test_dir.path()),
mount_dir.path(),
None::<&str>,
MsFlags::MS_BIND | MsFlags::MS_REC,
None::<&str>,
)
.map_err(|e| {
format!(
"Failed to bind-mount {} to {}: {}",
test_dir.path().display(),
mount_dir.path().display(),
e
)
})
.unwrap();

let target_file = target_path
.join(mount_dir.path().strip_prefix("/").unwrap())
.join(tmpfile_path.file_name().unwrap());
let file_visible = target_file.exists();

match propagation.as_str() {
"shared" => {
if file_visible {
println!("shared root propagation exposes {:?}", target_file);
} else {
eprintln!(
"Error: shared root propagation failed to expose {:?}",
target_file
);
}
}
"slave" | "private" => {
if !file_visible {
println!(
"{} root propagation does not expose {:?}",
propagation, target_file
);
} else {
eprintln!(
"Error: {} root propagation unexpectedly exposed {:?}",
propagation, target_file
);
}
}
_ => unreachable!(),
}
}
"unbindable" => {
if let Err(e) = mount(
Some("/"),
target_dir.path(),
None::<&str>,
MsFlags::MS_BIND | MsFlags::MS_REC,
None::<&str>,
) {
if e == nix::errno::Errno::EINVAL {
println!("root propagation is unbindable");
} else {
eprintln!("Error occurred during mount: {}", e);
}
}
}
_ => {
eprintln!("Unrecognized rootfsPropagation: {}", propagation);
}
}
}

0 comments on commit c87a97e

Please sign in to comment.