From b2e015cf4fd972f39d33bc2d366cf32f4e6b3ba4 Mon Sep 17 00:00:00 2001 From: jiaxiao zhou Date: Fri, 4 Aug 2023 23:44:05 +0000 Subject: [PATCH] feat: add default executor to spin shim Signed-off-by: jiaxiao zhou --- containerd-shim-spin-v1/src/linux_executor.rs | 102 ++++++++++++++++++ containerd-shim-spin-v1/src/main.rs | 16 ++- 2 files changed, 113 insertions(+), 5 deletions(-) create mode 100644 containerd-shim-spin-v1/src/linux_executor.rs diff --git a/containerd-shim-spin-v1/src/linux_executor.rs b/containerd-shim-spin-v1/src/linux_executor.rs new file mode 100644 index 00000000..6879c79e --- /dev/null +++ b/containerd-shim-spin-v1/src/linux_executor.rs @@ -0,0 +1,102 @@ +//! This file is copied over from runwasi's +//! +//! TODO: I believe the can_handle function can be abstracted to runwasi's containerd-shim-wasm crate +//! for sharing. + +use containerd_shim_wasm::sandbox::oci; +use libcontainer::workload::default::DefaultExecutor; +use libcontainer::workload::{Executor, ExecutorError}; + +use oci_spec::runtime::Spec; +use std::io::Read; +use std::{fs::OpenOptions, path::PathBuf}; + +#[derive(Default)] +pub struct LinuxContainerExecutor { + default_executor: DefaultExecutor, +} + +impl Executor for LinuxContainerExecutor { + fn exec(&self, spec: &Spec) -> Result<(), ExecutorError> { + self.default_executor.exec(spec) + } + + fn can_handle(&self, spec: &Spec) -> bool { + let args = oci::get_args(spec); + + if args.is_empty() { + return false; + } + + let executable = args[0].as_str(); + + // mostly follows youki's verify_binary implementation + // https://github.com/containers/youki/blob/2d6fd7650bb0f22a78fb5fa982b5628f61fe25af/crates/libcontainer/src/process/container_init_process.rs#L106 + let path = if executable.contains('/') { + PathBuf::from(executable) + } else { + let path = std::env::var("PATH").unwrap_or_default(); + // check each path in $PATH + let mut found = false; + let mut found_path = PathBuf::default(); + for p in path.split(':') { + let path = PathBuf::from(p).join(executable); + if path.exists() { + found = true; + found_path = path; + break; + } + } + if !found { + return false; + } + found_path + }; + + // check execute permission + use std::os::unix::fs::PermissionsExt; + let metadata = path.metadata(); + if metadata.is_err() { + log::info!("failed to get metadata of {:?}", path); + return false; + } + let metadata = metadata.unwrap(); + let permissions = metadata.permissions(); + if !metadata.is_file() || permissions.mode() & 0o001 == 0 { + log::info!("{} is not a file or has no execute permission", executable); + return false; + } + + // check the shebang and ELF magic number + // https://en.wikipedia.org/wiki/Executable_and_Linkable_Format#File_header + let mut buffer = [0; 4]; + + let file = OpenOptions::new().read(true).open(path); + if file.is_err() { + log::info!("failed to open {}", executable); + return false; + } + let mut file = file.unwrap(); + match file.read_exact(&mut buffer) { + Ok(_) => {} + Err(err) => { + log::info!("failed to read shebang of {}: {}", executable, err); + return false; + } + } + match buffer { + // ELF magic number + [0x7f, 0x45, 0x4c, 0x46] => true, + // shebang + [0x23, 0x21, ..] => true, + _ => { + log::info!("{} is not a valid script or elf file", executable); + false + } + } + } + + fn name(&self) -> &'static str { + self.default_executor.name() + } +} diff --git a/containerd-shim-spin-v1/src/main.rs b/containerd-shim-spin-v1/src/main.rs index 4b4e72c9..d043f48e 100644 --- a/containerd-shim-spin-v1/src/main.rs +++ b/containerd-shim-spin-v1/src/main.rs @@ -27,6 +27,7 @@ use libcontainer::container::Container; use libcontainer::container::ContainerStatus; use libcontainer::signal::Signal; use libcontainer::syscall::syscall::create_syscall; +use linux_executor::LinuxContainerExecutor; use log::error; use nix::errno::Errno; use nix::sys::wait::{waitid, Id as WaitID, WaitPidFlag, WaitStatus}; @@ -34,6 +35,7 @@ use serde::Deserialize; use serde::Serialize; mod executor; +mod linux_executor; const SPIN_ADDR: &str = "0.0.0.0:80"; static DEFAULT_CONTAINER_ROOT_DIR: &str = "/run/containerd/spin"; @@ -92,15 +94,19 @@ impl Wasi { let stdout = maybe_open_stdio(stdout).context("could not open stdout")?; let stderr = maybe_open_stdio(stderr).context("could not open stderr")?; + let spin_executor = Box::new(SpinExecutor { + stdin, + stdout, + stderr, + }); + let default_executor = Box::::default(); + let container = ContainerBuilder::new(self.id.clone(), syscall.as_ref()) - .with_executor(vec![Box::new(SpinExecutor { - stdin, - stdout, - stderr, - })])? + .with_executor(vec![default_executor, spin_executor])? .with_root_path(self.rootdir.clone())? .as_init(&self.bundle) .with_systemd(false) + .with_detach(true) .build()?; Ok(container) }