Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 41 additions & 3 deletions src/capability.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
//! Linux capability handling

use lazy_static::lazy_static;
use std::string::ToString;
use std::{collections::HashSet, ops::Deref};
use strum::{AsRefStr, EnumIter, EnumString, IntoEnumIterator, IntoStaticStr};
use strum::{AsRefStr, Display, EnumIter, EnumString, IntoEnumIterator, IntoStaticStr};

#[derive(Debug)]
#[derive(Clone, Debug)]
/// A set of capabilities.
pub struct Capabilities(HashSet<Capability>);

Expand All @@ -23,7 +25,43 @@ impl Deref for Capabilities {
}
}

#[derive(AsRefStr, IntoStaticStr, Copy, Clone, Debug, EnumIter, EnumString, Eq, Hash, PartialEq)]
impl Default for Capabilities {
fn default() -> Self {
DEFAULT_CAPABILITIES.clone()
}
}

impl Into<Vec<String>> for Capabilities {
fn into(self) -> Vec<String> {
(&self).into()
}
}

impl Into<Vec<String>> for &Capabilities {
fn into(self) -> Vec<String> {
self.iter().map(ToString::to_string).collect()
}
}

lazy_static! {
static ref DEFAULT_CAPABILITIES: Capabilities = {
let mut s = HashSet::new();
s.insert(Capability::CapChown);
s.insert(Capability::CapDacOverride);
s.insert(Capability::CapFsetid);
s.insert(Capability::CapFowner);
s.insert(Capability::CapSetgid);
s.insert(Capability::CapSetuid);
s.insert(Capability::CapSetpcap);
s.insert(Capability::CapNetBindService);
s.insert(Capability::CapKill);
Capabilities(s)
};
}

#[derive(
AsRefStr, IntoStaticStr, Copy, Clone, Debug, Display, EnumIter, EnumString, Eq, Hash, PartialEq,
)]
#[strum(serialize_all = "shouty_snake_case")]
/// All available capabilities.
pub enum Capability {
Expand Down
8 changes: 4 additions & 4 deletions src/oci_spec/runtime.rs
Original file line number Diff line number Diff line change
Expand Up @@ -108,8 +108,8 @@ impl Spec {
}
}

#[derive(PartialEq, Eq, Serialize, Deserialize, Debug, Builder, Getters)]
#[builder(pattern = "owned", setter(into, strip_option))]
#[derive(PartialEq, Eq, Serialize, Deserialize, Debug, Default, Builder, Getters)]
#[builder(default, pattern = "owned", setter(into, strip_option))]
/// Process contains information to start a specific application inside the container.
pub struct Process {
#[getset(get = "pub")]
Expand Down Expand Up @@ -243,8 +243,8 @@ pub struct Box {
}

/// User specifies specific user (and group) information for the container process.
#[derive(PartialEq, Eq, Serialize, Deserialize, Debug, Builder, Getters)]
#[builder(pattern = "owned", setter(into, strip_option))]
#[derive(PartialEq, Eq, Serialize, Deserialize, Debug, Default, Builder, Getters)]
#[builder(default, pattern = "owned", setter(into, strip_option))]
pub struct User {
#[getset(get_copy = "pub")]
/// UID is the user id.
Expand Down
4 changes: 2 additions & 2 deletions src/sandbox/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ bitflags! {
}
}

#[derive(Builder, Getters)]
#[derive(Builder, Debug, Getters)]
#[builder(pattern = "owned", setter(into))]
/// SandboxData holds all the data which will be passed around to the `Pod` trait, too.
pub struct SandboxData {
Expand Down Expand Up @@ -77,7 +77,7 @@ pub struct SandboxData {
}

pub trait Pod {
/// Run a previously created sandbox.
/// Run a new sandbox.
fn run(&mut self, _: &SandboxData) -> Result<()> {
Ok(())
}
Expand Down
116 changes: 113 additions & 3 deletions src/sandbox/pinned.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,118 @@
//! A pod sandbox implementation which does pin it's namespaces to file descriptors.

use crate::sandbox::Pod;
use crate::{
capability::Capabilities,
oci_spec::runtime::{
LinuxCapabilities, LinuxCapabilitiesBuilder, Process, ProcessBuilder, Spec, SpecBuilder,
},
sandbox::SandboxData,
};
use anyhow::{Context, Result};
use getset::Getters;
use log::{debug, trace};

#[derive(Default)]
pub struct PinnedSandbox {}
#[derive(Default, Getters)]
pub struct PinnedSandbox {
#[get]
runtime_spec: Spec,
}

impl Pod for PinnedSandbox {}
impl Pod for PinnedSandbox {
/// Run a new sandbox.
fn run(&mut self, sandbox_data: &SandboxData) -> Result<()> {
debug!("Running pod sandbox: {:?}", sandbox_data);

// Build the OCI runtime specification
let runtime_spec = self.build_runtime_spec()?;
debug!(
"Built OCI runtime spec for sandbox {}: {:?}",
sandbox_data.id(),
runtime_spec
);

// Update the sandbox state
self.runtime_spec = runtime_spec;
Ok(())
}
}

impl PinnedSandbox {
/// Build the runtime spec.
pub fn build_runtime_spec(&self) -> Result<Spec> {
trace!("Building OCI runtime spec");
let spec = SpecBuilder::default()
.process(self.build_runtime_spec_process()?)
.build()
.context("build OCI runtime spec")?;
Ok(spec)
}

/// Build the runtime spec process.
fn build_runtime_spec_process(&self) -> Result<Process> {
trace!("Building OCI runtime spec process");
Ok(ProcessBuilder::default()
.capabilities(self.build_runtime_spec_capabilities()?)
.build()
.context("build process")?)
}

/// Build the runtime spec process Linux capabilities.
fn build_runtime_spec_capabilities(&self) -> Result<LinuxCapabilities> {
trace!("Building OCI runtime spec capabilities");
let default_capabilities = Capabilities::default();
Ok(LinuxCapabilitiesBuilder::default()
.bounding(&default_capabilities)
.effective(&default_capabilities)
.inheritable(&default_capabilities)
.permitted(&default_capabilities)
.build()
.context("build capabilities")?)
}
}

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

#[test]
fn run_success() -> Result<()> {
let sandbox_data = new_sandbox_data()?;
let mut sandbox = PinnedSandbox::default();

sandbox.run(&sandbox_data)?;

let capabilities = sandbox
.runtime_spec()
.process()
.as_ref()
.context("no process")?
.capabilities()
.as_ref()
.context("no capabilities")?;
let default_capabilities: Vec<String> = Capabilities::default().into();
assert_eq!(
capabilities.bounding().as_ref().context("no boundings")?,
&default_capabilities
);
assert_eq!(
capabilities.effective().as_ref().context("no effective")?,
&default_capabilities
);
assert_eq!(
capabilities
.inheritable()
.as_ref()
.context("no effective")?,
&default_capabilities
);
assert_eq!(
capabilities.permitted().as_ref().context("no effective")?,
&default_capabilities
);
assert!(capabilities.ambient().is_none());

Ok(())
}
}