From 4696ba05d0e7b7cd2bf5c85944268c08694d4a79 Mon Sep 17 00:00:00 2001 From: moz-sec Date: Mon, 11 Nov 2024 07:24:44 +0000 Subject: [PATCH] test: add relative_network_cgroups test --- tests/contest/contest/src/main.rs | 2 + .../contest/contest/src/tests/cgroups/mod.rs | 1 + .../src/tests/cgroups/relative_network.rs | 94 +++++++++++++++++++ 3 files changed, 97 insertions(+) create mode 100644 tests/contest/contest/src/tests/cgroups/relative_network.rs diff --git a/tests/contest/contest/src/main.rs b/tests/contest/contest/src/main.rs index e0d3a4a02f..d7344e64c4 100644 --- a/tests/contest/contest/src/main.rs +++ b/tests/contest/contest/src/main.rs @@ -103,6 +103,7 @@ fn main() -> Result<()> { let cgroup_v1_memory = cgroups::memory::get_test_group(); let cgroup_v1_network = cgroups::network::get_test_group(); let cgroup_v1_blkio = cgroups::blkio::get_test_group(); + let cgroup_v1_relative_network = cgroups::relative_network::get_test_group(); let seccomp = get_seccomp_test(); let seccomp_notify = get_seccomp_notify_test(); let ro_paths = get_ro_paths_test(); @@ -128,6 +129,7 @@ fn main() -> Result<()> { tm.add_test_group(Box::new(cgroup_v1_memory)); tm.add_test_group(Box::new(cgroup_v1_network)); tm.add_test_group(Box::new(cgroup_v1_blkio)); + tm.add_test_group(Box::new(cgroup_v1_relative_network)); tm.add_test_group(Box::new(seccomp)); tm.add_test_group(Box::new(seccomp_notify)); tm.add_test_group(Box::new(ro_paths)); diff --git a/tests/contest/contest/src/tests/cgroups/mod.rs b/tests/contest/contest/src/tests/cgroups/mod.rs index 51f467d5c0..b8cea1d4c2 100644 --- a/tests/contest/contest/src/tests/cgroups/mod.rs +++ b/tests/contest/contest/src/tests/cgroups/mod.rs @@ -9,6 +9,7 @@ pub mod cpu; pub mod memory; pub mod network; pub mod pids; +pub mod relative_network; pub fn cleanup_v1() -> Result<()> { for subsystem in list_subsystem_mount_points()? { diff --git a/tests/contest/contest/src/tests/cgroups/relative_network.rs b/tests/contest/contest/src/tests/cgroups/relative_network.rs new file mode 100644 index 0000000000..202a4f9c77 --- /dev/null +++ b/tests/contest/contest/src/tests/cgroups/relative_network.rs @@ -0,0 +1,94 @@ +use std::path::Path; + +use anyhow::{Context, Result}; +use oci_spec::runtime::{ + LinuxBuilder, LinuxInterfacePriorityBuilder, LinuxNetworkBuilder, LinuxResourcesBuilder, Spec, + SpecBuilder, +}; +use pnet_datalink::interfaces; +use test_framework::{test_result, ConditionalTest, TestGroup, TestResult}; + +use crate::utils::test_outside_container; +use crate::utils::test_utils::check_container_created; + +fn create_spec(cgroup_name: &str, class_id: u32, prio: u32, if_name: &str) -> Result { + // Create the Linux Spec + let linux_spec = LinuxBuilder::default() + .cgroups_path(Path::new("testdir/runtime-test/container").join(cgroup_name)) + .resources( + LinuxResourcesBuilder::default() + .network( + LinuxNetworkBuilder::default() + .class_id(class_id) + .priorities(vec![LinuxInterfacePriorityBuilder::default() + .name(if_name) + .priority(prio) + .build() + .context("failed to build network interface priority spec")?]) + .build() + .context("failed to build network spec")?, + ) + .build() + .context("failed to build resource spec")?, + ) + .build() + .context("failed to build linux spec")?; + + // Create the top level Spec + let spec = SpecBuilder::default() + .linux(linux_spec) + .build() + .context("failed to build spec")?; + + Ok(spec) +} + +// Gets the loopback interface if it exists +fn get_loopback_interface() -> Option { + let interfaces = interfaces(); + let lo_if_name = interfaces.first().map(|iface| &iface.name)?; + + Some(lo_if_name.to_string()) +} + +fn test_relative_network_cgroups() -> TestResult { + let cgroup_name = "test_relative_network_cgroups"; + + let id = 255; + let prio = 10; + let if_name = "lo"; + let spec = test_result!(create_spec(cgroup_name, id, prio, if_name)); + + test_outside_container(spec, &|data| { + test_result!(check_container_created(&data)); + TestResult::Passed + }) +} + +fn can_run() -> bool { + // Ensure the expected network interfaces exist on the system running the test + let iface_exists = get_loopback_interface().is_some(); + + // This is kind of annoying, network controller can be at a number of mount points + let cgroup_paths_exists = (Path::new("/sys/fs/cgroup/net_cls/net_cls.classid").exists() + && Path::new("/sys/fs/cgroup/net_prio/net_prio.ifpriomap").exists()) + || (Path::new("/sys/fs/cgroup/net_cls,net_prio/net_cls.classid").exists() + && Path::new("/sys/fs/cgroup/net_cls,net_prio/net_prio.ifpriomap").exists()) + || (Path::new("/sys/fs/cgroup/net_prio,net_cls/net_cls.classid").exists() + && Path::new("/sys/fs/cgroup/net_prio,net_cl/net_prio.ifpriomap").exists()); + + iface_exists && cgroup_paths_exists +} + +pub fn get_test_group() -> TestGroup { + let mut test_group = TestGroup::new("cgroup_v1_relative_network"); + let linux_cgroups_network = ConditionalTest::new( + "test_linux_cgroups_relative_network", + Box::new(can_run), + Box::new(test_relative_network_cgroups), + ); + + test_group.add(vec![Box::new(linux_cgroups_network)]); + + test_group +}