1
0
mirror of https://github.com/containers/youki synced 2025-04-30 13:20:17 +02:00

Check if rootless container is required and ensure prerequisites

This commit is contained in:
Furisto 2021-06-15 17:29:07 +02:00
parent b7d639091a
commit 181518b867
2 changed files with 67 additions and 0 deletions

@ -18,3 +18,4 @@ pub mod start;
pub mod stdio;
pub mod tty;
pub mod utils;
pub mod rootless;

66
src/rootless.rs Normal file

@ -0,0 +1,66 @@
use anyhow::{bail, Result};
use nix::sched::CloneFlags;
use oci_spec::{LinuxIdMapping, Mount, Spec};
use crate::namespaces::Namespaces;
/// Checks if rootless mode should be used
pub fn should_use_rootless() -> Result<bool> {
if !nix::unistd::geteuid().is_root() {
return Ok(true);
}
if let Ok("true") = std::env::var("YOUKI_USE_ROOTLESS").as_deref() {
return Ok(true);
}
Ok(false)
}
/// Validates that the spec contains the required information for
/// running in rootless mode
pub fn validate(spec: &Spec) -> Result<()> {
let linux = spec.linux.as_ref().unwrap();
if linux.uid_mappings.is_empty() {
bail!("rootless containers require at least one uid mapping");
}
if linux.gid_mappings.is_empty() {
bail!("rootless containers require at least one gid mapping")
}
let namespaces: Namespaces = linux.namespaces.clone().into();
if !namespaces.clone_flags.contains(CloneFlags::CLONE_NEWUSER) {
bail!("rootless containers require the specification of a user namespace");
}
validate_mounts(&spec.mounts, &linux.uid_mappings, &linux.gid_mappings)?;
Ok(())
}
fn validate_mounts(
mounts: &Vec<Mount>,
uid_mappings: &Vec<LinuxIdMapping>,
gid_mappings: &Vec<LinuxIdMapping>,
) -> Result<()> {
for mount in mounts {
for opt in &mount.options {
if opt.starts_with("uid=") && !is_id_mapped(&opt[4..], uid_mappings)? {
bail!("Mount {:?} specifies option {} which is not mapped inside the rootless container", mount, opt);
} else if opt.starts_with("gid=") && !is_id_mapped(&opt[4..], gid_mappings)? {
bail!("Mount {:?} specifies option {} which is not mapped inside the rootless container", mount, opt);
}
}
}
Ok(())
}
fn is_id_mapped(id: &str, mappings: &Vec<LinuxIdMapping>) -> Result<bool> {
let id = id.parse::<u32>()?;
Ok(mappings
.iter()
.all(|m| id >= m.container_id && id <= m.container_id + m.size))
}