Skip to content

Commit

Permalink
Use Features structure in the OCI spec
Browse files Browse the repository at this point in the history
Signed-off-by: Kotaro Inoue <k.musaino@gmail.com>
  • Loading branch information
musaprg committed Sep 9, 2024
1 parent 74add24 commit 6646793
Showing 1 changed file with 104 additions and 128 deletions.
232 changes: 104 additions & 128 deletions crates/youki/src/commands/features.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,66 +5,14 @@ use std::path::Path;
use anyhow::Result;
use caps::{all, CapSet};
use liboci_cli::Features;
use serde::{Deserialize, Serialize};
use oci_spec::runtime::{
ApparmorBuilder, Arch, CgroupBuilder, FeaturesBuilder, LinuxFeatureBuilder, LinuxNamespaceType,
LinuxSeccompAction, SeccompBuilder,
};

// TODO: Add youki specific annotations such as version, commit hash etc.
pub const ANNOTATION_LIBSECCOMP_VERSION: &str = "io.github.seccomp.libseccomp.version";

#[derive(Debug, Serialize, Deserialize)]
pub struct HardFeatures {
// Minimum OCI Runtime Spec version recognized by the runtime, e.g., "1.0.0".
oci_version_min: String,
// Maximum OCI Runtime Spec version recognized by the runtime, e.g., "1.0.2-dev".
oci_version_max: String,
// List of the recognized hook names, e.g., "createRuntime".
hooks: Option<Vec<String>>,
// List of the recognized mount options, e.g., "ro".
mount_options: Option<Vec<String>>,
// Specific to Linux.
linux: Option<Linux>,
// Contains implementation-specific annotation strings.
annotations: Option<std::collections::HashMap<String, String>>,
}

// Specific to Linux.
#[derive(Debug, Serialize, Deserialize)]
pub struct Linux {
// List of the recognized namespaces, e.g., "mount".
namespaces: Option<Vec<String>>,
// List of the recognized capabilities, e.g., "CAP_SYS_ADMIN".
capabilities: Option<Vec<String>>,
cgroup: Option<Cgroup>,
seccomp: Option<Seccomp>,
apparmor: Option<Apparmor>,
selinux: Option<Selinux>,
}

#[derive(Debug, Serialize, Deserialize)]
struct Seccomp {
enabled: Option<bool>,
actions: Option<Vec<String>>,
operators: Option<Vec<String>>,
archs: Option<Vec<String>>,
}

#[derive(Debug, Serialize, Deserialize)]
struct Apparmor {
enabled: Option<bool>,
}

#[derive(Debug, Serialize, Deserialize)]
struct Selinux {
enabled: Option<bool>,
}

#[derive(Debug, Serialize, Deserialize)]
struct Cgroup {
v1: Option<bool>,
v2: Option<bool>,
systemd: Option<bool>,
systemd_user: Option<bool>,
}

// Function to query and return capabilities
fn query_caps() -> Result<Vec<String>> {
let mut available_caps = Vec::new();
Expand All @@ -80,15 +28,24 @@ fn query_caps() -> Result<Vec<String>> {
}

// Function to query and return namespaces
fn query_supported_namespaces() -> Result<Vec<String>> {
fn query_supported_namespaces() -> Result<Vec<LinuxNamespaceType>> {
let mut supported_namespaces = Vec::new();

let ns_types = vec!["pid", "net", "uts", "ipc", "mnt", "user", "cgroup", "time"];
let ns_types = vec![
LinuxNamespaceType::Pid,
LinuxNamespaceType::Network,
LinuxNamespaceType::Uts,
LinuxNamespaceType::Ipc,
LinuxNamespaceType::Mount,
LinuxNamespaceType::User,
LinuxNamespaceType::Cgroup,
LinuxNamespaceType::Time,
];

for ns in ns_types {
let ns_path = format!("/proc/self/ns/{}", ns);
if Path::new(&ns_path).exists() {
supported_namespaces.push(ns.to_string());
supported_namespaces.push(ns);
}
}

Expand All @@ -115,18 +72,18 @@ pub fn features(_: Features) -> Result<()> {
}
};

let features = HardFeatures {
oci_version_min: String::from("1.0.0"),
oci_version_max: String::from("1.0.2-dev"),
hooks: Some(vec![
let features = FeaturesBuilder::default()
.oci_version_max(String::from("1.0.2-dev"))
.oci_version_min(String::from("1.0.0"))
.hooks(vec![
String::from("prestart"),
String::from("createRuntime"),
String::from("createContainer"),
String::from("startContainer"),
String::from("poststart"),
String::from("poststop"),
]),
mount_options: Some(vec![
])
.mount_options(vec![
String::from("acl"),
String::from("async"),
String::from("atime"),
Expand Down Expand Up @@ -189,78 +146,97 @@ pub fn features(_: Features) -> Result<()> {
String::from("sync"),
String::from("tmpcopyup"),
String::from("unbindable"),
]),
linux: Some(Linux {
namespaces: Some(namespaces),
capabilities: Some(capabilities),
cgroup: Some(Cgroup {
v1: Some(true),
v2: Some(true),
systemd: Some(true),
systemd_user: Some(true),
}),
seccomp: Some(Seccomp {
enabled: Some(true),
actions: Some(vec![
String::from("SCMP_ACT_ALLOW"),
String::from("SCMP_ACT_ERRNO"),
String::from("SCMP_ACT_KILL"),
String::from("SCMP_ACT_KILL_PROCESS"),
String::from("SCMP_ACT_KILL_THREAD"),
String::from("SCMP_ACT_LOG"),
String::from("SCMP_ACT_NOTIFY"),
String::from("SCMP_ACT_TRACE"),
String::from("SCMP_ACT_TRAP"),
]),
operators: Some(vec![
String::from("SCMP_CMP_EQ"),
String::from("SCMP_CMP_GE"),
String::from("SCMP_CMP_GT"),
String::from("SCMP_CMP_LE"),
String::from("SCMP_CMP_LT"),
String::from("SCMP_CMP_MASKED_EQ"),
String::from("SCMP_CMP_NE"),
]),
archs: Some(vec![
String::from("SCMP_ARCH_AARCH64"),
String::from("SCMP_ARCH_ARM"),
String::from("SCMP_ARCH_MIPS"),
String::from("SCMP_ARCH_MIPS64"),
String::from("SCMP_ARCH_MIPS64N32"),
String::from("SCMP_ARCH_MIPSEL"),
String::from("SCMP_ARCH_MIPSEL64"),
String::from("SCMP_ARCH_MIPSEL64N32"),
String::from("SCMP_ARCH_PPC"),
String::from("SCMP_ARCH_PPC64"),
String::from("SCMP_ARCH_PPC64LE"),
String::from("SCMP_ARCH_RISCV64"),
String::from("SCMP_ARCH_S390"),
String::from("SCMP_ARCH_S390X"),
String::from("SCMP_ARCH_X32"),
String::from("SCMP_ARCH_X86"),
String::from("SCMP_ARCH_X86_64"),
]),
}),
apparmor: Some(Apparmor {
enabled: Some(true),
}),
selinux: Some(Selinux {
enabled: Some(true),
}),
}),
annotations: {
])
.linux(
LinuxFeatureBuilder::default()
.namespaces(namespaces)
.capabilities(capabilities)
.cgroup(
CgroupBuilder::default()
.v1(true)
.v2(true)
.systemd(true)
.systemd_user(true)
.build()
.unwrap(),
)
.seccomp(
SeccompBuilder::default()
.enabled(true)
.actions(vec![
LinuxSeccompAction::ScmpActKill,
LinuxSeccompAction::ScmpActKillThread,
LinuxSeccompAction::ScmpActKillProcess,
LinuxSeccompAction::ScmpActTrap,
LinuxSeccompAction::ScmpActErrno,
LinuxSeccompAction::ScmpActNotify,
LinuxSeccompAction::ScmpActTrace,
LinuxSeccompAction::ScmpActLog,
LinuxSeccompAction::ScmpActAllow,
])
.operators(vec![
String::from("SCMP_CMP_EQ"),
String::from("SCMP_CMP_GE"),
String::from("SCMP_CMP_GT"),
String::from("SCMP_CMP_LE"),
String::from("SCMP_CMP_LT"),
String::from("SCMP_CMP_MASKED_EQ"),
String::from("SCMP_CMP_NE"),
])
.archs(vec![
Arch::ScmpArchNative,
Arch::ScmpArchAarch64,
Arch::ScmpArchArm,
Arch::ScmpArchMips,
Arch::ScmpArchMips64,
Arch::ScmpArchMips64n32,
Arch::ScmpArchMipsel,
Arch::ScmpArchMipsel64,
Arch::ScmpArchMipsel64n32,
Arch::ScmpArchPpc,
Arch::ScmpArchPpc64,
Arch::ScmpArchPpc64le,
Arch::ScmpArchRiscv64,
Arch::ScmpArchS390,
Arch::ScmpArchS390x,
Arch::ScmpArchX32,
Arch::ScmpArchX86,
Arch::ScmpArchX86_64,
])
.known_flags(vec![])
.supported_flags(vec![])
.build()
.unwrap(),
)
.apparmor(ApparmorBuilder::default().enabled(true).build().unwrap())
.build()
.unwrap(),
)
.annotations({
let mut annotations_map = HashMap::new();
annotations_map.insert(
ANNOTATION_LIBSECCOMP_VERSION.to_string(),
String::from("2.5.3"),
);
Some(annotations_map)
},
};
annotations_map
})
.build()
.unwrap();

// Print out the created struct to verify
let pretty_json_str = serde_json::to_string_pretty(&features)?;
println!("{}", pretty_json_str);

Ok(())
}

#[cfg(test)]
mod tests {
use super::*;

#[test]
fn test_features() {
let features = Features {};
assert!(crate::commands::features::features(features).is_ok());
}
}

0 comments on commit 6646793

Please sign in to comment.