From 560247cde3340619819d76086118ade27e7b2362 Mon Sep 17 00:00:00 2001 From: Yashodhan Joshi Date: Sun, 11 Jul 2021 21:25:25 +0530 Subject: [PATCH] Document Capabilities and refactor its drop_privileges function --- docs/doc-draft.md | 4 ++++ src/capabilities.rs | 18 ++++++++---------- src/command/linux.rs | 28 ++++++++++++++++++++++++++-- 3 files changed, 38 insertions(+), 12 deletions(-) diff --git a/docs/doc-draft.md b/docs/doc-draft.md index 4abe5b428..a2a725269 100644 --- a/docs/doc-draft.md +++ b/docs/doc-draft.md @@ -92,3 +92,7 @@ This also provides implementation for Linux syscalls for the trait. [oci runtime specification]: https://github.com/opencontainers/runtime-spec/blob/master/runtime.md [runc man pages]: (https://github.com/opencontainers/runc/blob/master/man/runc.8.md) + +## Capabilities + +- [Simple explanation of capabilities](https://blog.container-solutions.com/linux-capabilities-in-practice) diff --git a/src/capabilities.rs b/src/capabilities.rs index 79088fdf3..051c882be 100644 --- a/src/capabilities.rs +++ b/src/capabilities.rs @@ -1,9 +1,11 @@ +//! Handles Management of Capabilities use crate::command::Syscall; use caps::*; use anyhow::Result; use oci_spec::{LinuxCapabilities, LinuxCapabilityType}; +/// Converts a list of capability types to capabilities has set fn to_set(caps: &[LinuxCapabilityType]) -> CapsHashSet { let mut capabilities = CapsHashSet::new(); for c in caps { @@ -12,29 +14,25 @@ fn to_set(caps: &[LinuxCapabilityType]) -> CapsHashSet { capabilities } +/// reset capabilities of process calling this to effective capabilities +/// effective capability set is set of capabilities used by kernel to perform checks +/// see https://man7.org/linux/man-pages/man7/capabilities.7.html for more information pub fn reset_effective(syscall: &impl Syscall) -> Result<()> { log::debug!("reset all caps"); syscall.set_capability(CapSet::Effective, &caps::all())?; Ok(()) } +/// Drop any extra granted capabilities, and reset to defaults which are in oci specification pub fn drop_privileges(cs: &LinuxCapabilities, syscall: &impl Syscall) -> Result<()> { - let all = caps::all(); log::debug!("dropping bounding capabilities to {:?}", cs.bounding); - for c in all.difference(&to_set(&cs.bounding)) { - match c { - Capability::CAP_PERFMON | Capability::CAP_CHECKPOINT_RESTORE | Capability::CAP_BPF => { - log::warn!("{:?} doesn't support.", c); - continue; - } - _ => caps::drop(None, CapSet::Bounding, *c)?, - } - } + syscall.set_capability(CapSet::Bounding, &to_set(&cs.bounding))?; syscall.set_capability(CapSet::Effective, &to_set(&cs.effective))?; syscall.set_capability(CapSet::Permitted, &to_set(&cs.permitted))?; syscall.set_capability(CapSet::Inheritable, &to_set(&cs.inheritable))?; + // check specifically for ambient, as those might not always be available if let Err(e) = syscall.set_capability(CapSet::Ambient, &to_set(&cs.ambient)) { log::error!("failed to set ambient capabilities: {}", e); } diff --git a/src/command/linux.rs b/src/command/linux.rs index e2cb86eea..cc055c172 100644 --- a/src/command/linux.rs +++ b/src/command/linux.rs @@ -5,7 +5,7 @@ use std::sync::Arc; use std::{any::Any, mem, path::Path, ptr}; use anyhow::{bail, Result}; -use caps::{errors::CapsError, CapSet, CapsHashSet}; +use caps::{errors::CapsError, CapSet, Capability, CapsHashSet}; use libc::{c_char, uid_t}; use nix::{ errno::Errno, @@ -114,7 +114,31 @@ impl Syscall for LinuxSyscall { /// Set capabilities for container process fn set_capability(&self, cset: CapSet, value: &CapsHashSet) -> Result<(), CapsError> { - caps::set(None, cset, value) + match cset { + // caps::set cannot set capabilities in bounding set, + // so we do it differently + CapSet::Bounding => { + // get all capabilities + let all = caps::all(); + // the difference will give capabilities + // which are to be unset + // for each such =, drop that capability + // after this, only those which are to be set will remain set + for c in all.difference(value) { + match c { + Capability::CAP_PERFMON + | Capability::CAP_CHECKPOINT_RESTORE + | Capability::CAP_BPF => { + log::warn!("{:?} is not supported.", c); + continue; + } + _ => caps::drop(None, CapSet::Bounding, *c)?, + } + } + Ok(()) + } + _ => caps::set(None, cset, value), + } } /// Sets hostname for process