1
0
Fork 0
mirror of https://github.com/containers/youki synced 2024-05-10 09:36:13 +02:00
youki/tests/contest/contest/src/tests/seccomp_notify/mod.rs
Toru Komatsu 464344923f
Name the test tools `contest` (#2486)
* Name the test tools `contest`

Signed-off-by: utam0k <k0ma@utam0k.jp>

* Address the feedbacks

Signed-off-by: utam0k <k0ma@utam0k.jp>

* Fix a build error

Signed-off-by: utam0k <k0ma@utam0k.jp>

* Fix a workflow

Signed-off-by: utam0k <k0ma@utam0k.jp>

* Address the feedbacks

Signed-off-by: utam0k <k0ma@utam0k.jp>

---------

Signed-off-by: utam0k <k0ma@utam0k.jp>
2024-01-12 14:28:47 +05:30

128 lines
4.5 KiB
Rust

use crate::utils::{get_runtime_path, test_outside_container};
use anyhow::{anyhow, bail, Result};
use oci_spec::runtime::{
Arch, LinuxBuilder, LinuxSeccompAction, LinuxSeccompBuilder, LinuxSyscallBuilder, SpecBuilder,
};
use std::{
path::PathBuf,
sync::mpsc::{self, Receiver, Sender},
thread,
};
use test_framework::{Test, TestGroup, TestResult};
mod seccomp_agent;
const SECCOMP_LISTENER_PATH: &str = "/tmp/youki_seccomp_agent.unix";
const SECCOMP_METADATA: &str = "Hello World! This is an opaque seccomp metadata string";
fn get_seccomp_listener() -> PathBuf {
let seccomp_listener_path = PathBuf::from(SECCOMP_LISTENER_PATH);
// We will have to clean up leftover unix domain socket from previous runs.
if seccomp_listener_path.exists() {
std::fs::remove_file(&seccomp_listener_path)
.expect("failed to clean up existing seccomp listener");
}
seccomp_listener_path
}
fn test_seccomp_notify() -> Result<()> {
let seccomp_listener_path = get_seccomp_listener();
let seccomp_meta = String::from(SECCOMP_METADATA);
// Create a spec to include seccomp notify. We will need to have at least
// one syscall set to seccomp notify. We also need to set seccomp listener
// path and metadata.
let spec = SpecBuilder::default()
.linux(
LinuxBuilder::default()
.seccomp(
LinuxSeccompBuilder::default()
.default_action(LinuxSeccompAction::ScmpActAllow)
.architectures(vec![Arch::ScmpArchX86_64])
.listener_path(&seccomp_listener_path)
.listener_metadata(seccomp_meta)
.syscalls(vec![LinuxSyscallBuilder::default()
.names(vec![String::from("getcwd")])
.action(LinuxSeccompAction::ScmpActNotify)
.build()
.unwrap()])
.build()
.unwrap(),
)
.build()
.unwrap(),
)
.build()
.unwrap();
// two threads. One run container life cycle. Another one run seccomp agent...
let (sender, receiver): (
Sender<seccomp_agent::SeccompAgentResult>,
Receiver<seccomp_agent::SeccompAgentResult>,
) = mpsc::channel();
// We have to launch the seccomp agent before we launch the container.
// Otherwise, the container creation will be blocked on trying to send to
// the seccomp listener and never returns.
let child = thread::spawn(move || {
let res = seccomp_agent::recv_seccomp_listener(&seccomp_listener_path);
sender
.send(res)
.expect("failed to send seccomp agent result back to main thread");
});
if let TestResult::Failed(err) = test_outside_container(spec, &move |data| {
let (container_process_state, _) = receiver
.recv()
.expect("failed to receive from channel")
.expect("failed to receive from seccomp listener");
let state = match data.state {
Some(s) => s,
None => return TestResult::Failed(anyhow!("state command returned error")),
};
if state.id != container_process_state.state.id {
return TestResult::Failed(anyhow!("container id doesn't match"));
}
if state.pid.unwrap() != container_process_state.pid {
return TestResult::Failed(anyhow!("container process id doesn't match"));
}
if SECCOMP_METADATA != container_process_state.metadata {
return TestResult::Failed(anyhow!("seccomp listener metadata doesn't match"));
}
TestResult::Passed
}) {
bail!("failed to run test outside container: {:?}", err);
}
if let Err(err) = child.join() {
bail!("seccomp listener child thread fails: {:?}", err);
}
Ok(())
}
pub fn get_seccomp_notify_test() -> TestGroup {
let seccomp_notify_test = Test::new(
"seccomp_notify",
Box::new(|| {
let runtime = get_runtime_path();
// runc doesn't support seccomp notify yet
if runtime.ends_with("runc") {
return TestResult::Skipped;
}
match test_seccomp_notify() {
Ok(_) => TestResult::Passed,
Err(err) => TestResult::Failed(err),
}
}),
);
let mut tg = TestGroup::new("seccomp_notify");
tg.add(vec![Box::new(seccomp_notify_test)]);
tg
}