use crate::error::{oci_error, OciSpecError};
use derive_builder::Builder;
use getset::{CopyGetters, Getters, MutGetters, Setters};
use serde::{Deserialize, Serialize};
use std::{collections::HashMap, fmt::Display, path::PathBuf, vec};
use strum_macros::{Display as StrumDisplay, EnumString};
#[derive(
Builder, Clone, Debug, Deserialize, Eq, Getters, MutGetters, Setters, PartialEq, Serialize,
)]
#[serde(rename_all = "camelCase")]
#[builder(
default,
pattern = "owned",
setter(into, strip_option),
build_fn(error = "OciSpecError")
)]
#[getset(get_mut = "pub", get = "pub", set = "pub")]
pub struct Linux {
#[serde(default, skip_serializing_if = "Option::is_none")]
uid_mappings: Option<Vec<LinuxIdMapping>>,
#[serde(default, skip_serializing_if = "Option::is_none")]
gid_mappings: Option<Vec<LinuxIdMapping>>,
#[serde(default, skip_serializing_if = "Option::is_none")]
sysctl: Option<HashMap<String, String>>,
#[serde(default, skip_serializing_if = "Option::is_none")]
resources: Option<LinuxResources>,
#[serde(default, skip_serializing_if = "Option::is_none")]
cgroups_path: Option<PathBuf>,
#[serde(default, skip_serializing_if = "Option::is_none")]
namespaces: Option<Vec<LinuxNamespace>>,
#[serde(default, skip_serializing_if = "Option::is_none")]
devices: Option<Vec<LinuxDevice>>,
#[serde(default, skip_serializing_if = "Option::is_none")]
seccomp: Option<LinuxSeccomp>,
#[serde(default, skip_serializing_if = "Option::is_none")]
rootfs_propagation: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
masked_paths: Option<Vec<String>>,
#[serde(default, skip_serializing_if = "Option::is_none")]
readonly_paths: Option<Vec<String>>,
#[serde(default, skip_serializing_if = "Option::is_none")]
mount_label: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
intel_rdt: Option<LinuxIntelRdt>,
#[serde(default, skip_serializing_if = "Option::is_none")]
personality: Option<LinuxPersonality>,
#[serde(default, skip_serializing_if = "Option::is_none")]
time_offsets: Option<HashMap<String, String>>,
}
impl Default for Linux {
fn default() -> Self {
Linux {
uid_mappings: Default::default(),
gid_mappings: Default::default(),
sysctl: Default::default(),
resources: Some(LinuxResources {
devices: vec![].into(),
memory: Default::default(),
cpu: Default::default(),
pids: Default::default(),
block_io: Default::default(),
hugepage_limits: Default::default(),
network: Default::default(),
rdma: Default::default(),
unified: Default::default(),
}),
cgroups_path: Default::default(),
namespaces: get_default_namespaces().into(),
devices: Default::default(),
rootfs_propagation: Default::default(),
masked_paths: get_default_maskedpaths().into(),
readonly_paths: get_default_readonly_paths().into(),
mount_label: Default::default(),
seccomp: None,
intel_rdt: None,
personality: None,
time_offsets: None,
}
}
}
impl Linux {
pub fn rootless(uid: u32, gid: u32) -> Self {
let mut namespaces = get_default_namespaces();
namespaces.retain(|ns| ns.typ != LinuxNamespaceType::Network);
namespaces.push(LinuxNamespace {
typ: LinuxNamespaceType::User,
..Default::default()
});
Self {
resources: None,
uid_mappings: Some(vec![LinuxIdMapping {
container_id: 0,
host_id: uid,
size: 1,
}]),
gid_mappings: Some(vec![LinuxIdMapping {
container_id: 0,
host_id: gid,
size: 1,
}]),
namespaces: Some(namespaces),
..Default::default()
}
}
}
#[derive(
Builder, Clone, Copy, CopyGetters, Debug, Default, Deserialize, Eq, PartialEq, Serialize,
)]
#[serde(rename_all = "camelCase")]
#[builder(
default,
pattern = "owned",
setter(into, strip_option),
build_fn(error = "OciSpecError")
)]
#[getset(get_copy = "pub", set = "pub")]
pub struct LinuxIdMapping {
#[serde(default, rename = "hostID")]
host_id: u32,
#[serde(default, rename = "containerID")]
container_id: u32,
#[serde(default)]
size: u32,
}
#[derive(Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize, EnumString)]
#[strum(serialize_all = "lowercase")]
#[serde(rename_all = "lowercase")]
pub enum LinuxDeviceType {
A,
B,
C,
U,
P,
}
#[allow(clippy::derivable_impls)] impl Default for LinuxDeviceType {
fn default() -> LinuxDeviceType {
LinuxDeviceType::A
}
}
impl LinuxDeviceType {
pub fn as_str(&self) -> &str {
match self {
Self::A => "a",
Self::B => "b",
Self::C => "c",
Self::U => "u",
Self::P => "p",
}
}
}
#[derive(
Builder,
Clone,
CopyGetters,
Debug,
Default,
Deserialize,
Eq,
Getters,
MutGetters,
Setters,
PartialEq,
Serialize,
)]
#[builder(
default,
pattern = "owned",
setter(into, strip_option),
build_fn(error = "OciSpecError")
)]
pub struct LinuxDeviceCgroup {
#[serde(default)]
#[getset(get_mut = "pub", get_copy = "pub", set = "pub")]
allow: bool,
#[serde(default, rename = "type", skip_serializing_if = "Option::is_none")]
#[getset(get_mut = "pub", get_copy = "pub", set = "pub")]
typ: Option<LinuxDeviceType>,
#[serde(default, skip_serializing_if = "Option::is_none")]
#[getset(get_mut = "pub", get_copy = "pub", set = "pub")]
major: Option<i64>,
#[serde(default, skip_serializing_if = "Option::is_none")]
#[getset(get_mut = "pub", get_copy = "pub", set = "pub")]
minor: Option<i64>,
#[serde(default)]
#[getset(get_mut = "pub", get = "pub", set = "pub")]
access: Option<String>,
}
impl Display for LinuxDeviceCgroup {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let major = self
.major
.map(|mj| mj.to_string())
.unwrap_or_else(|| "*".to_string());
let minor = self
.minor
.map(|mi| mi.to_string())
.unwrap_or_else(|| "*".to_string());
let access = self.access.as_deref().unwrap_or("");
write!(
f,
"{} {}:{} {}",
&self.typ.unwrap_or_default().as_str(),
&major,
&minor,
&access
)
}
}
#[derive(
Builder, Clone, Copy, CopyGetters, Debug, Default, Deserialize, Eq, PartialEq, Serialize,
)]
#[serde(rename_all = "camelCase")]
#[builder(
default,
pattern = "owned",
setter(into, strip_option),
build_fn(error = "OciSpecError")
)]
#[getset(get_copy = "pub", set = "pub")]
pub struct LinuxMemory {
#[serde(skip_serializing_if = "Option::is_none")]
#[getset(get_copy = "pub", set = "pub")]
limit: Option<i64>,
#[serde(skip_serializing_if = "Option::is_none")]
#[getset(get_copy = "pub", set = "pub")]
reservation: Option<i64>,
#[serde(skip_serializing_if = "Option::is_none")]
#[getset(get_copy = "pub", set = "pub")]
swap: Option<i64>,
#[serde(skip_serializing_if = "Option::is_none")]
#[getset(get_copy = "pub", set = "pub")]
kernel: Option<i64>,
#[serde(skip_serializing_if = "Option::is_none", rename = "kernelTCP")]
#[getset(get_copy = "pub", set = "pub")]
kernel_tcp: Option<i64>,
#[serde(skip_serializing_if = "Option::is_none")]
#[getset(get_copy = "pub", set = "pub")]
swappiness: Option<u64>,
#[serde(skip_serializing_if = "Option::is_none", rename = "disableOOMKiller")]
#[getset(get_copy = "pub", set = "pub")]
disable_oom_killer: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
#[getset(get_copy = "pub", set = "pub")]
use_hierarchy: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
#[getset(get_copy = "pub", set = "pub")]
check_before_update: Option<bool>,
}
#[derive(
Builder,
Clone,
CopyGetters,
Debug,
Default,
Deserialize,
Eq,
Getters,
Setters,
PartialEq,
Serialize,
)]
#[serde(rename_all = "camelCase")]
#[builder(
default,
pattern = "owned",
setter(into, strip_option),
build_fn(error = "OciSpecError")
)]
pub struct LinuxCpu {
#[serde(skip_serializing_if = "Option::is_none")]
#[getset(get_copy = "pub", set = "pub")]
shares: Option<u64>,
#[serde(skip_serializing_if = "Option::is_none")]
#[getset(get_copy = "pub", set = "pub")]
quota: Option<i64>,
#[serde(skip_serializing_if = "Option::is_none")]
#[getset(get_copy = "pub", set = "pub")]
idle: Option<i64>,
#[serde(skip_serializing_if = "Option::is_none")]
#[getset(get_copy = "pub", set = "pub")]
burst: Option<u64>,
#[serde(skip_serializing_if = "Option::is_none")]
#[getset(get_copy = "pub", set = "pub")]
period: Option<u64>,
#[serde(skip_serializing_if = "Option::is_none")]
#[getset(get_copy = "pub", set = "pub")]
realtime_runtime: Option<i64>,
#[serde(skip_serializing_if = "Option::is_none")]
#[getset(get_copy = "pub", set = "pub")]
realtime_period: Option<u64>,
#[serde(default, skip_serializing_if = "Option::is_none")]
#[getset(get = "pub", set = "pub")]
cpus: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
#[getset(get = "pub", set = "pub")]
mems: Option<String>,
}
#[derive(
Builder,
Clone,
Copy,
Debug,
Default,
Deserialize,
Eq,
CopyGetters,
Setters,
PartialEq,
Serialize,
)]
#[builder(
default,
pattern = "owned",
setter(into, strip_option),
build_fn(error = "OciSpecError")
)]
#[getset(get_copy = "pub", set = "pub")]
pub struct LinuxPids {
#[serde(default)]
limit: i64,
}
#[derive(
Builder, Clone, Copy, CopyGetters, Debug, Default, Deserialize, Eq, PartialEq, Serialize,
)]
#[serde(rename_all = "camelCase")]
#[builder(
default,
pattern = "owned",
setter(into, strip_option),
build_fn(error = "OciSpecError")
)]
#[getset(get_copy = "pub", set = "pub")]
pub struct LinuxWeightDevice {
#[serde(default)]
major: i64,
#[serde(default)]
minor: i64,
#[serde(skip_serializing_if = "Option::is_none")]
weight: Option<u16>,
#[serde(skip_serializing_if = "Option::is_none")]
leaf_weight: Option<u16>,
}
#[derive(
Builder, Clone, Copy, CopyGetters, Debug, Default, Deserialize, Eq, PartialEq, Serialize,
)]
#[builder(
default,
pattern = "owned",
setter(into, strip_option),
build_fn(error = "OciSpecError")
)]
#[getset(get_copy = "pub", set = "pub")]
pub struct LinuxThrottleDevice {
#[serde(default)]
major: i64,
#[serde(default)]
minor: i64,
#[serde(default)]
rate: u64,
}
#[derive(
Builder,
Clone,
CopyGetters,
Debug,
Default,
Deserialize,
Eq,
Getters,
Setters,
PartialEq,
Serialize,
)]
#[serde(rename_all = "camelCase")]
#[builder(
default,
pattern = "owned",
setter(into, strip_option),
build_fn(error = "OciSpecError")
)]
pub struct LinuxBlockIo {
#[serde(skip_serializing_if = "Option::is_none")]
#[getset(get_copy = "pub", set = "pub")]
weight: Option<u16>,
#[serde(skip_serializing_if = "Option::is_none")]
#[getset(get_copy = "pub", set = "pub")]
leaf_weight: Option<u16>,
#[serde(skip_serializing_if = "Option::is_none")]
#[getset(get = "pub", set = "pub")]
weight_device: Option<Vec<LinuxWeightDevice>>,
#[serde(skip_serializing_if = "Option::is_none")]
#[getset(get = "pub", set = "pub")]
throttle_read_bps_device: Option<Vec<LinuxThrottleDevice>>,
#[serde(skip_serializing_if = "Option::is_none")]
#[getset(get = "pub", set = "pub")]
throttle_write_bps_device: Option<Vec<LinuxThrottleDevice>>,
#[serde(skip_serializing_if = "Option::is_none")]
#[getset(get = "pub", set = "pub")]
throttle_read_iops_device: Option<Vec<LinuxThrottleDevice>>,
#[serde(skip_serializing_if = "Option::is_none")]
#[getset(get = "pub", set = "pub")]
throttle_write_iops_device: Option<Vec<LinuxThrottleDevice>>,
}
#[derive(
Builder,
Clone,
CopyGetters,
Debug,
Default,
Deserialize,
Eq,
Getters,
Setters,
PartialEq,
Serialize,
)]
#[serde(rename_all = "camelCase")]
#[builder(
default,
pattern = "owned",
setter(into, strip_option),
build_fn(error = "OciSpecError")
)]
pub struct LinuxHugepageLimit {
#[serde(default)]
#[getset(get = "pub", set = "pub")]
page_size: String,
#[serde(default)]
#[getset(get_copy = "pub", set = "pub")]
limit: i64,
}
#[derive(
Builder,
Clone,
CopyGetters,
Debug,
Default,
Deserialize,
Eq,
Getters,
Setters,
PartialEq,
Serialize,
)]
#[builder(
default,
pattern = "owned",
setter(into, strip_option),
build_fn(error = "OciSpecError")
)]
pub struct LinuxInterfacePriority {
#[serde(default)]
#[getset(get = "pub", set = "pub")]
name: String,
#[serde(default)]
#[getset(get_copy = "pub", set = "pub")]
priority: u32,
}
impl Display for LinuxInterfacePriority {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
writeln!(f, "{} {}", self.name, self.priority)
}
}
#[derive(
Builder,
Clone,
CopyGetters,
Debug,
Default,
Deserialize,
Eq,
Getters,
Setters,
PartialEq,
Serialize,
)]
#[builder(
default,
pattern = "owned",
setter(into, strip_option),
build_fn(error = "OciSpecError")
)]
pub struct LinuxNetwork {
#[serde(skip_serializing_if = "Option::is_none", rename = "classID")]
#[getset(get_copy = "pub", set = "pub")]
class_id: Option<u32>,
#[serde(default, skip_serializing_if = "Option::is_none")]
#[getset(get = "pub", set = "pub")]
priorities: Option<Vec<LinuxInterfacePriority>>,
}
#[derive(
Builder,
Clone,
CopyGetters,
Debug,
Default,
Deserialize,
Eq,
Getters,
MutGetters,
Setters,
PartialEq,
Serialize,
)]
#[serde(rename_all = "camelCase")]
#[builder(
default,
pattern = "owned",
setter(into, strip_option),
build_fn(error = "OciSpecError")
)]
pub struct LinuxResources {
#[serde(default, skip_serializing_if = "Option::is_none")]
#[getset(get_mut = "pub", get = "pub", set = "pub")]
devices: Option<Vec<LinuxDeviceCgroup>>,
#[serde(default, skip_serializing_if = "Option::is_none")]
#[getset(get_mut = "pub", get = "pub", set = "pub")]
memory: Option<LinuxMemory>,
#[serde(default, skip_serializing_if = "Option::is_none")]
#[getset(get_mut = "pub", get = "pub", set = "pub")]
cpu: Option<LinuxCpu>,
#[serde(default, skip_serializing_if = "Option::is_none")]
#[getset(get_mut = "pub", get = "pub", set = "pub")]
pids: Option<LinuxPids>,
#[serde(default, skip_serializing_if = "Option::is_none", rename = "blockIO")]
#[getset(get_mut = "pub", get = "pub", set = "pub")]
block_io: Option<LinuxBlockIo>,
#[serde(default, skip_serializing_if = "Option::is_none")]
#[getset(get_mut = "pub", get = "pub", set = "pub")]
hugepage_limits: Option<Vec<LinuxHugepageLimit>>,
#[serde(default, skip_serializing_if = "Option::is_none")]
#[getset(get_mut = "pub", get = "pub", set = "pub")]
network: Option<LinuxNetwork>,
#[serde(default, skip_serializing_if = "Option::is_none")]
#[getset(get_mut = "pub", get = "pub", set = "pub")]
rdma: Option<HashMap<String, LinuxRdma>>,
#[serde(default, skip_serializing_if = "Option::is_none")]
#[getset(get_mut = "pub", get = "pub", set = "pub")]
unified: Option<HashMap<String, String>>,
}
#[derive(
Builder,
Clone,
Copy,
CopyGetters,
Debug,
Default,
Deserialize,
Eq,
MutGetters,
PartialEq,
Serialize,
)]
#[serde(rename_all = "camelCase")]
#[builder(
default,
pattern = "owned",
setter(into, strip_option),
build_fn(error = "OciSpecError")
)]
#[getset(get_mut = "pub", get_copy = "pub", set = "pub")]
pub struct LinuxRdma {
#[serde(skip_serializing_if = "Option::is_none")]
hca_handles: Option<u32>,
#[serde(skip_serializing_if = "Option::is_none")]
hca_objects: Option<u32>,
}
#[derive(Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize, Hash, StrumDisplay)]
#[strum(serialize_all = "lowercase")]
#[serde(rename_all = "snake_case")]
pub enum LinuxNamespaceType {
#[strum(to_string = "mnt")]
Mount = 0x00020000,
Cgroup = 0x02000000,
Uts = 0x04000000,
Ipc = 0x08000000,
User = 0x10000000,
Pid = 0x20000000,
#[strum(to_string = "net")]
Network = 0x40000000,
Time = 0x00000080,
}
impl TryFrom<&str> for LinuxNamespaceType {
type Error = OciSpecError;
fn try_from(namespace: &str) -> Result<Self, Self::Error> {
match namespace {
"mnt" | "mount" => Ok(LinuxNamespaceType::Mount),
"cgroup" => Ok(LinuxNamespaceType::Cgroup),
"uts" => Ok(LinuxNamespaceType::Uts),
"ipc" => Ok(LinuxNamespaceType::Ipc),
"user" => Ok(LinuxNamespaceType::User),
"pid" => Ok(LinuxNamespaceType::Pid),
"net" | "network" => Ok(LinuxNamespaceType::Network),
"time" => Ok(LinuxNamespaceType::Time),
_ => Err(oci_error(format!(
"unknown namespace {namespace}, could not convert"
))),
}
}
}
impl Default for LinuxNamespaceType {
fn default() -> Self {
Self::Pid
}
}
#[derive(
Builder,
Clone,
CopyGetters,
Debug,
Default,
Deserialize,
Eq,
Getters,
Setters,
PartialEq,
Serialize,
)]
#[builder(
default,
pattern = "owned",
setter(into, strip_option),
build_fn(error = "OciSpecError")
)]
pub struct LinuxNamespace {
#[serde(rename = "type")]
#[getset(get_copy = "pub", set = "pub")]
typ: LinuxNamespaceType,
#[serde(default, skip_serializing_if = "Option::is_none")]
#[getset(get = "pub", set = "pub")]
path: Option<PathBuf>,
}
pub fn get_default_namespaces() -> Vec<LinuxNamespace> {
vec![
LinuxNamespace {
typ: LinuxNamespaceType::Pid,
path: Default::default(),
},
LinuxNamespace {
typ: LinuxNamespaceType::Network,
path: Default::default(),
},
LinuxNamespace {
typ: LinuxNamespaceType::Ipc,
path: Default::default(),
},
LinuxNamespace {
typ: LinuxNamespaceType::Uts,
path: Default::default(),
},
LinuxNamespace {
typ: LinuxNamespaceType::Mount,
path: Default::default(),
},
LinuxNamespace {
typ: LinuxNamespaceType::Cgroup,
path: Default::default(),
},
]
}
#[derive(
Builder,
Clone,
CopyGetters,
Debug,
Default,
Deserialize,
Eq,
Getters,
MutGetters,
Setters,
PartialEq,
Serialize,
)]
#[serde(rename_all = "camelCase")]
#[builder(
default,
pattern = "owned",
setter(into, strip_option),
build_fn(error = "OciSpecError")
)]
pub struct LinuxDevice {
#[serde(default)]
#[getset(get_mut = "pub", get = "pub", set = "pub")]
path: PathBuf,
#[serde(rename = "type")]
#[getset(get_mut = "pub", get_copy = "pub", set = "pub")]
typ: LinuxDeviceType,
#[serde(default)]
#[getset(get_mut = "pub", get_copy = "pub", set = "pub")]
major: i64,
#[serde(default)]
#[getset(get_mut = "pub", get_copy = "pub", set = "pub")]
minor: i64,
#[serde(default, skip_serializing_if = "Option::is_none")]
#[getset(get_mut = "pub", get_copy = "pub", set = "pub")]
file_mode: Option<u32>,
#[serde(default, skip_serializing_if = "Option::is_none")]
#[getset(get_mut = "pub", get_copy = "pub", set = "pub")]
uid: Option<u32>,
#[serde(default, skip_serializing_if = "Option::is_none")]
#[getset(get_mut = "pub", get_copy = "pub", set = "pub")]
gid: Option<u32>,
}
impl From<&LinuxDevice> for LinuxDeviceCgroup {
fn from(linux_device: &LinuxDevice) -> LinuxDeviceCgroup {
LinuxDeviceCgroup {
allow: true,
typ: linux_device.typ.into(),
major: Some(linux_device.major),
minor: Some(linux_device.minor),
access: "rwm".to_string().into(),
}
}
}
#[derive(
Builder,
Clone,
CopyGetters,
Debug,
Default,
Deserialize,
Eq,
Getters,
Setters,
PartialEq,
Serialize,
)]
#[serde(rename_all = "camelCase")]
#[builder(
default,
pattern = "owned",
setter(into, strip_option),
build_fn(error = "OciSpecError")
)]
pub struct LinuxSeccomp {
#[getset(get_copy = "pub", set = "pub")]
default_action: LinuxSeccompAction,
#[serde(default, skip_serializing_if = "Option::is_none")]
#[getset(get_copy = "pub", set = "pub")]
default_errno_ret: Option<u32>,
#[serde(default, skip_serializing_if = "Option::is_none")]
#[getset(get = "pub", set = "pub")]
architectures: Option<Vec<Arch>>,
#[serde(default, skip_serializing_if = "Option::is_none")]
#[getset(get = "pub", set = "pub")]
flags: Option<Vec<LinuxSeccompFilterFlag>>,
#[serde(default, skip_serializing_if = "Option::is_none")]
#[getset(get = "pub", set = "pub")]
listener_path: Option<PathBuf>,
#[serde(default, skip_serializing_if = "Option::is_none")]
#[getset(get = "pub", set = "pub")]
listener_metadata: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
#[getset(get = "pub", set = "pub")]
syscalls: Option<Vec<LinuxSyscall>>,
}
#[derive(Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize, StrumDisplay, EnumString)]
#[strum(serialize_all = "SCREAMING_SNAKE_CASE")]
#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
#[repr(u32)]
pub enum LinuxSeccompAction {
ScmpActKill = 0x00000000,
ScmpActKillProcess = 0x80000000,
ScmpActTrap = 0x00030000,
ScmpActErrno = 0x00050001,
ScmpActNotify = 0x7fc00000,
ScmpActTrace = 0x7ff00001,
ScmpActLog = 0x7ffc0000,
ScmpActAllow = 0x7fff0000,
}
impl Default for LinuxSeccompAction {
fn default() -> Self {
Self::ScmpActAllow
}
}
#[allow(clippy::enum_clike_unportable_variant)]
#[derive(Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize, StrumDisplay, EnumString)]
#[strum(serialize_all = "SCREAMING_SNAKE_CASE")]
#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
pub enum Arch {
ScmpArchNative = 0x00000000,
ScmpArchX86 = 0x40000003,
ScmpArchX86_64 = 0xc000003e,
ScmpArchX32 = 0x4000003e,
ScmpArchArm = 0x40000028,
ScmpArchAarch64 = 0xc00000b7,
ScmpArchMips = 0x00000008,
ScmpArchMips64 = 0x80000008,
ScmpArchMips64n32 = 0xa0000008,
ScmpArchMipsel = 0x40000008,
ScmpArchMipsel64 = 0xc0000008,
ScmpArchMipsel64n32 = 0xe0000008,
ScmpArchPpc = 0x00000014,
ScmpArchPpc64 = 0x80000015,
ScmpArchPpc64le = 0xc0000015,
ScmpArchS390 = 0x00000016,
ScmpArchS390x = 0x80000016,
}
#[derive(Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize, StrumDisplay, EnumString)]
#[strum(serialize_all = "SCREAMING_SNAKE_CASE")]
#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
pub enum LinuxSeccompFilterFlag {
SeccompFilterFlagLog,
SeccompFilterFlagTsync,
SeccompFilterFlagSpecAllow,
}
#[derive(Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize, StrumDisplay, EnumString)]
#[strum(serialize_all = "SCREAMING_SNAKE_CASE")]
#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
#[repr(u32)]
pub enum LinuxSeccompOperator {
ScmpCmpNe = 1,
ScmpCmpLt = 2,
ScmpCmpLe = 3,
ScmpCmpEq = 4,
ScmpCmpGe = 5,
ScmpCmpGt = 6,
ScmpCmpMaskedEq = 7,
}
impl Default for LinuxSeccompOperator {
fn default() -> Self {
Self::ScmpCmpEq
}
}
#[derive(
Builder,
Clone,
CopyGetters,
Debug,
Default,
Deserialize,
Eq,
Getters,
Setters,
PartialEq,
Serialize,
)]
#[serde(rename_all = "camelCase")]
#[builder(
default,
pattern = "owned",
setter(into, strip_option),
build_fn(error = "OciSpecError")
)]
pub struct LinuxSyscall {
#[getset(get = "pub", set = "pub")]
names: Vec<String>,
#[getset(get_copy = "pub", set = "pub")]
action: LinuxSeccompAction,
#[serde(default, skip_serializing_if = "Option::is_none")]
#[getset(get_copy = "pub", set = "pub")]
errno_ret: Option<u32>,
#[serde(default, skip_serializing_if = "Option::is_none")]
#[getset(get = "pub", set = "pub")]
args: Option<Vec<LinuxSeccompArg>>,
}
#[derive(
Builder, Clone, Copy, CopyGetters, Debug, Default, Deserialize, Eq, PartialEq, Serialize,
)]
#[serde(rename_all = "camelCase")]
#[builder(
default,
pattern = "owned",
setter(into, strip_option),
build_fn(error = "OciSpecError")
)]
#[getset(get_copy = "pub", set = "pub")]
pub struct LinuxSeccompArg {
index: usize,
value: u64,
#[serde(default, skip_serializing_if = "Option::is_none")]
value_two: Option<u64>,
op: LinuxSeccompOperator,
}
pub fn get_default_maskedpaths() -> Vec<String> {
vec![
"/proc/acpi".to_string(),
"/proc/asound".to_string(),
"/proc/kcore".to_string(),
"/proc/keys".to_string(),
"/proc/latency_stats".to_string(),
"/proc/timer_list".to_string(),
"/proc/timer_stats".to_string(),
"/proc/sched_debug".to_string(),
"/sys/firmware".to_string(),
"/proc/scsi".to_string(),
]
}
pub fn get_default_readonly_paths() -> Vec<String> {
vec![
"/proc/bus".to_string(),
"/proc/fs".to_string(),
"/proc/irq".to_string(),
"/proc/sys".to_string(),
"/proc/sysrq-trigger".to_string(),
]
}
#[derive(
Builder,
Clone,
Debug,
Default,
Deserialize,
Eq,
Getters,
MutGetters,
Setters,
PartialEq,
Serialize,
)]
#[serde(rename_all = "camelCase")]
#[builder(
default,
pattern = "owned",
setter(into, strip_option),
build_fn(error = "OciSpecError")
)]
#[getset(get_mut = "pub", get = "pub", set = "pub")]
pub struct LinuxIntelRdt {
#[serde(default, skip_serializing_if = "Option::is_none", rename = "closID")]
clos_id: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
l3_cache_schema: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
mem_bw_schema: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
enable_cmt: Option<bool>,
#[serde(default, skip_serializing_if = "Option::is_none")]
enable_mbm: Option<bool>,
}
#[derive(
Builder,
Clone,
CopyGetters,
Debug,
Default,
Deserialize,
Eq,
Getters,
Setters,
PartialEq,
Serialize,
)]
#[builder(
default,
pattern = "owned",
setter(into, strip_option),
build_fn(error = "OciSpecError")
)]
pub struct LinuxPersonality {
#[getset(get_copy = "pub", set = "pub")]
domain: LinuxPersonalityDomain,
#[serde(default, skip_serializing_if = "Option::is_none")]
#[getset(get = "pub", set = "pub")]
flags: Option<Vec<String>>,
}
#[derive(Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize, StrumDisplay, EnumString)]
pub enum LinuxPersonalityDomain {
#[serde(rename = "LINUX")]
#[strum(serialize = "LINUX")]
PerLinux,
#[serde(rename = "LINUX32")]
#[strum(serialize = "LINUX32")]
PerLinux32,
}
impl Default for LinuxPersonalityDomain {
fn default() -> Self {
Self::PerLinux
}
}
#[cfg(feature = "proptests")]
use quickcheck::{Arbitrary, Gen};
#[cfg(feature = "proptests")]
fn some_none_generator_util<T: Arbitrary>(g: &mut Gen) -> Option<T> {
let choice = g.choose(&[true, false]).unwrap();
match choice {
false => None,
true => Some(T::arbitrary(g)),
}
}
#[cfg(feature = "proptests")]
impl Arbitrary for LinuxDeviceCgroup {
fn arbitrary(g: &mut Gen) -> LinuxDeviceCgroup {
let typ_choices = ["a", "b", "c", "u", "p"];
let typ_chosen = g.choose(&typ_choices).unwrap();
let typ = match typ_chosen.to_string().as_str() {
"a" => LinuxDeviceType::A,
"b" => LinuxDeviceType::B,
"c" => LinuxDeviceType::C,
"u" => LinuxDeviceType::U,
"p" => LinuxDeviceType::P,
_ => LinuxDeviceType::A,
};
let access_choices = ["rwm", "m"];
LinuxDeviceCgroup {
allow: bool::arbitrary(g),
typ: typ.into(),
major: some_none_generator_util::<i64>(g),
minor: some_none_generator_util::<i64>(g),
access: g.choose(&access_choices).unwrap().to_string().into(),
}
}
}
#[cfg(feature = "proptests")]
impl Arbitrary for LinuxMemory {
fn arbitrary(g: &mut Gen) -> LinuxMemory {
LinuxMemory {
kernel: some_none_generator_util::<i64>(g),
kernel_tcp: some_none_generator_util::<i64>(g),
limit: some_none_generator_util::<i64>(g),
reservation: some_none_generator_util::<i64>(g),
swap: some_none_generator_util::<i64>(g),
swappiness: some_none_generator_util::<u64>(g),
disable_oom_killer: some_none_generator_util::<bool>(g),
use_hierarchy: some_none_generator_util::<bool>(g),
check_before_update: some_none_generator_util::<bool>(g),
}
}
}
#[cfg(feature = "proptests")]
impl Arbitrary for LinuxHugepageLimit {
fn arbitrary(g: &mut Gen) -> LinuxHugepageLimit {
let unit_choice = ["KB", "MB", "GB"];
let unit = g.choose(&unit_choice).unwrap();
let page_size = u64::arbitrary(g).to_string() + unit;
LinuxHugepageLimit {
page_size,
limit: i64::arbitrary(g),
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn device_type_enum_to_str() {
let type_a = LinuxDeviceType::A;
assert_eq!(type_a.as_str(), "a");
let type_b = LinuxDeviceType::B;
assert_eq!(type_b.as_str(), "b");
let type_c = LinuxDeviceType::C;
assert_eq!(type_c.as_str(), "c");
}
#[test]
fn device_type_string_to_enum() {
let devtype_str = "a";
let devtype_enum: LinuxDeviceType = devtype_str.parse().unwrap();
assert_eq!(devtype_enum, LinuxDeviceType::A);
let devtype_str = "b";
let devtype_enum: LinuxDeviceType = devtype_str.parse().unwrap();
assert_eq!(devtype_enum, LinuxDeviceType::B);
let devtype_str = "c";
let devtype_enum: LinuxDeviceType = devtype_str.parse().unwrap();
assert_eq!(devtype_enum, LinuxDeviceType::C);
let invalid_devtype_str = "x";
let unknown_devtype = invalid_devtype_str.parse::<LinuxDeviceType>();
assert!(unknown_devtype.is_err());
}
#[test]
fn ns_type_enum_to_string() {
let type_a = LinuxNamespaceType::Network;
assert_eq!(type_a.to_string(), "net");
let type_b = LinuxNamespaceType::Mount;
assert_eq!(type_b.to_string(), "mnt");
let type_c = LinuxNamespaceType::Ipc;
assert_eq!(type_c.to_string(), "ipc");
}
#[test]
fn ns_type_string_to_enum() {
let nstype_str = "net";
let nstype_enum = LinuxNamespaceType::try_from(nstype_str).unwrap();
assert_eq!(nstype_enum, LinuxNamespaceType::Network);
let nstype_str = "network";
let nstype_enum = LinuxNamespaceType::try_from(nstype_str).unwrap();
assert_eq!(nstype_enum, LinuxNamespaceType::Network);
let nstype_str = "ipc";
let nstype_enum = LinuxNamespaceType::try_from(nstype_str).unwrap();
assert_eq!(nstype_enum, LinuxNamespaceType::Ipc);
let nstype_str = "cgroup";
let nstype_enum = LinuxNamespaceType::try_from(nstype_str).unwrap();
assert_eq!(nstype_enum, LinuxNamespaceType::Cgroup);
let nstype_str = "mount";
let nstype_enum = LinuxNamespaceType::try_from(nstype_str).unwrap();
assert_eq!(nstype_enum, LinuxNamespaceType::Mount);
let invalid_nstype_str = "xxx";
let unknown_nstype = LinuxNamespaceType::try_from(invalid_nstype_str);
assert!(unknown_nstype.is_err());
}
#[test]
fn seccomp_action_enum_to_string() {
let type_a = LinuxSeccompAction::ScmpActKill;
assert_eq!(type_a.to_string(), "SCMP_ACT_KILL");
let type_b = LinuxSeccompAction::ScmpActAllow;
assert_eq!(type_b.to_string(), "SCMP_ACT_ALLOW");
let type_c = LinuxSeccompAction::ScmpActNotify;
assert_eq!(type_c.to_string(), "SCMP_ACT_NOTIFY");
}
#[test]
fn seccomp_action_string_to_enum() {
let action_str = "SCMP_ACT_KILL";
let action_enum: LinuxSeccompAction = action_str.parse().unwrap();
assert_eq!(action_enum, LinuxSeccompAction::ScmpActKill);
let action_str = "SCMP_ACT_ALLOW";
let action_enum: LinuxSeccompAction = action_str.parse().unwrap();
assert_eq!(action_enum, LinuxSeccompAction::ScmpActAllow);
let action_str = "SCMP_ACT_NOTIFY";
let action_enum: LinuxSeccompAction = action_str.parse().unwrap();
assert_eq!(action_enum, LinuxSeccompAction::ScmpActNotify);
let invalid_action_str = "x";
let unknown_action = invalid_action_str.parse::<LinuxSeccompAction>();
assert!(unknown_action.is_err());
}
#[test]
fn seccomp_arch_enum_to_string() {
let type_a = Arch::ScmpArchX86_64;
assert_eq!(type_a.to_string(), "SCMP_ARCH_X86_64");
let type_b = Arch::ScmpArchAarch64;
assert_eq!(type_b.to_string(), "SCMP_ARCH_AARCH64");
let type_c = Arch::ScmpArchPpc64le;
assert_eq!(type_c.to_string(), "SCMP_ARCH_PPC64LE");
}
#[test]
fn seccomp_arch_string_to_enum() {
let arch_type_str = "SCMP_ARCH_X86_64";
let arch_type_enum: Arch = arch_type_str.parse().unwrap();
assert_eq!(arch_type_enum, Arch::ScmpArchX86_64);
let arch_type_str = "SCMP_ARCH_AARCH64";
let arch_type_enum: Arch = arch_type_str.parse().unwrap();
assert_eq!(arch_type_enum, Arch::ScmpArchAarch64);
let arch_type_str = "SCMP_ARCH_PPC64LE";
let arch_type_enum: Arch = arch_type_str.parse().unwrap();
assert_eq!(arch_type_enum, Arch::ScmpArchPpc64le);
let invalid_arch_str = "x";
let unknown_arch = invalid_arch_str.parse::<Arch>();
assert!(unknown_arch.is_err());
}
#[test]
fn seccomp_filter_flag_enum_to_string() {
let type_a = LinuxSeccompFilterFlag::SeccompFilterFlagLog;
assert_eq!(type_a.to_string(), "SECCOMP_FILTER_FLAG_LOG");
let type_b = LinuxSeccompFilterFlag::SeccompFilterFlagTsync;
assert_eq!(type_b.to_string(), "SECCOMP_FILTER_FLAG_TSYNC");
let type_c = LinuxSeccompFilterFlag::SeccompFilterFlagSpecAllow;
assert_eq!(type_c.to_string(), "SECCOMP_FILTER_FLAG_SPEC_ALLOW");
}
#[test]
fn seccomp_filter_flag_string_to_enum() {
let filter_flag_type_str = "SECCOMP_FILTER_FLAG_LOG";
let filter_flag_type_enum: LinuxSeccompFilterFlag = filter_flag_type_str.parse().unwrap();
assert_eq!(
filter_flag_type_enum,
LinuxSeccompFilterFlag::SeccompFilterFlagLog
);
let filter_flag_type_str = "SECCOMP_FILTER_FLAG_TSYNC";
let filter_flag_type_enum: LinuxSeccompFilterFlag = filter_flag_type_str.parse().unwrap();
assert_eq!(
filter_flag_type_enum,
LinuxSeccompFilterFlag::SeccompFilterFlagTsync
);
let filter_flag_type_str = "SECCOMP_FILTER_FLAG_SPEC_ALLOW";
let filter_flag_type_enum: LinuxSeccompFilterFlag = filter_flag_type_str.parse().unwrap();
assert_eq!(
filter_flag_type_enum,
LinuxSeccompFilterFlag::SeccompFilterFlagSpecAllow
);
let invalid_filter_flag_str = "x";
let unknown_arch = invalid_filter_flag_str.parse::<LinuxSeccompFilterFlag>();
assert!(unknown_arch.is_err());
}
#[test]
fn seccomp_operator_enum_to_string() {
let type_a = LinuxSeccompOperator::ScmpCmpNe;
assert_eq!(type_a.to_string(), "SCMP_CMP_NE");
let type_b = LinuxSeccompOperator::ScmpCmpMaskedEq;
assert_eq!(type_b.to_string(), "SCMP_CMP_MASKED_EQ");
let type_c = LinuxSeccompOperator::ScmpCmpGt;
assert_eq!(type_c.to_string(), "SCMP_CMP_GT");
}
#[test]
fn seccomp_operator_string_to_enum() {
let seccomp_operator_str = "SCMP_CMP_GT";
let seccomp_operator_enum: LinuxSeccompOperator = seccomp_operator_str.parse().unwrap();
assert_eq!(seccomp_operator_enum, LinuxSeccompOperator::ScmpCmpGt);
let seccomp_operator_str = "SCMP_CMP_NE";
let seccomp_operator_enum: LinuxSeccompOperator = seccomp_operator_str.parse().unwrap();
assert_eq!(seccomp_operator_enum, LinuxSeccompOperator::ScmpCmpNe);
let seccomp_operator_str = "SCMP_CMP_MASKED_EQ";
let seccomp_operator_enum: LinuxSeccompOperator = seccomp_operator_str.parse().unwrap();
assert_eq!(seccomp_operator_enum, LinuxSeccompOperator::ScmpCmpMaskedEq);
let invalid_seccomp_operator_str = "x";
let unknown_operator = invalid_seccomp_operator_str.parse::<LinuxSeccompOperator>();
assert!(unknown_operator.is_err());
}
}