1
0
mirror of https://github.com/containers/youki synced 2024-11-23 01:11:58 +01:00

Change rootless required function and privilege decision

This commit is contained in:
Yashodhan Joshi 2023-08-18 12:08:43 +05:30
parent 33ebda81ea
commit 7078ad6882
9 changed files with 52 additions and 44 deletions

@ -25,6 +25,17 @@ use super::stats::Stats;
pub const CGROUP_PROCS: &str = "cgroup.procs";
pub const DEFAULT_CGROUP_ROOT: &str = "/sys/fs/cgroup";
#[cfg(feature = "systemd")]
#[inline]
fn is_true_root() -> bool {
if !nix::unistd::geteuid().is_root() {
return false;
}
let uid_map_path = "/proc/self/uid_map";
let content = std::fs::read_to_string(uid_map_path)
.unwrap_or_else(|_| panic!("failed to read {}", uid_map_path));
content.contains("4294967295")
}
pub trait CgroupManager {
type Error;
@ -388,7 +399,7 @@ fn create_systemd_cgroup_manager(
);
}
let use_system = nix::unistd::geteuid().is_root();
let use_system = is_true_root();
tracing::info!(
"systemd cgroup manager with system bus {} will be used",

@ -13,7 +13,7 @@ use crate::{
error::{ErrInvalidSpec, LibcontainerError, MissingSpecError},
notify_socket::NOTIFY_FILE,
process::args::ContainerType,
tty, user_ns,
tty, user_ns, utils,
};
use super::{
@ -87,6 +87,11 @@ impl InitContainerBuilder {
};
let user_ns_config = UserNamespaceConfig::new(&spec)?;
if utils::rootless_required() && !utils::is_in_new_userns() && user_ns_config.is_none() {
return Err(LibcontainerError::NoUserNamespace);
}
let config = YoukiConfig::from_spec(&spec, container.id(), user_ns_config.is_some())?;
config.save(&container_dir).map_err(|err| {
tracing::error!(?container_dir, "failed to save config: {}", err);

@ -121,6 +121,10 @@ impl TenantContainerBuilder {
let use_systemd = self.should_use_systemd(&container);
let user_ns_config = UserNamespaceConfig::new(&spec)?;
if utils::rootless_required() && !utils::is_in_new_userns() && user_ns_config.is_none() {
return Err(LibcontainerError::NoUserNamespace);
}
let (read_end, write_end) =
pipe2(OFlag::O_CLOEXEC).map_err(LibcontainerError::OtherSyscall)?;

@ -22,6 +22,8 @@ pub enum LibcontainerError {
InvalidInput(String),
#[error("requires at least one executors")]
NoExecutors,
#[error("rootless container requires valid user namespace definition")]
NoUserNamespace,
// Invalid inputs
#[error(transparent)]

@ -376,7 +376,8 @@ pub fn container_init_process(
})?;
}
let bind_service = namespaces.get(LinuxNamespaceType::User)?.is_some();
let bind_service =
namespaces.get(LinuxNamespaceType::User)?.is_some() || utils::is_in_new_userns();
let rootfs = RootFS::new();
rootfs
.prepare_rootfs(

@ -1,5 +1,6 @@
use crate::error::MissingSpecError;
use crate::namespaces::{NamespaceError, Namespaces};
use crate::utils;
use nix::unistd::Pid;
use oci_spec::runtime::{Linux, LinuxIdMapping, LinuxNamespace, LinuxNamespaceType, Mount, Spec};
use std::fs;
@ -85,8 +86,6 @@ type Result<T> = std::result::Result<T, UserNamespaceError>;
pub enum ValidateSpecError {
#[error(transparent)]
MissingSpec(#[from] crate::error::MissingSpecError),
#[error("rootless container requires valid user namespace definition")]
NoUserNamespace, // TODO fix this while fixing podman
#[error("new user namespace requires valid uid mappings")]
NoUIDMappings,
#[error("new user namespace requires valid gid mappings")]
@ -152,13 +151,6 @@ impl UserNamespaceConfig {
.get(LinuxNamespaceType::User)
.map_err(ValidateSpecError::Namespaces)?;
// If conditions requires us to use rootless, we must either create a new
// user namespace or enter an existing.
// TODO FIX THIS FOR ROOTLESS
if rootless_required() && user_namespace.is_none() {
return Err(UserNamespaceError::NoUserNamespace);
}
if user_namespace.is_some() && user_namespace.unwrap().path().is_none() {
tracing::debug!("container with new user namespace should be created");
@ -225,22 +217,12 @@ impl TryFrom<&Linux> for UserNamespaceConfig {
uid_mappings: linux.uid_mappings().to_owned(),
gid_mappings: linux.gid_mappings().to_owned(),
user_namespace: user_namespace.cloned(),
privileged: nix::unistd::geteuid().is_root(),
privileged: !utils::rootless_required(),
id_mapper: UserNamespaceIDMapper::new(),
})
}
}
/// Checks if rootless mode should be used
// TODO fix this along with podman
pub fn rootless_required() -> bool {
if !nix::unistd::geteuid().is_root() {
return true;
}
matches!(std::env::var("YOUKI_USE_ROOTLESS").as_deref(), Ok("true"))
}
pub fn unprivileged_user_ns_enabled() -> Result<bool> {
let user_ns_sysctl = Path::new("/proc/sys/kernel/unprivileged_userns_clone");
if !user_ns_sysctl.exists() {
@ -269,10 +251,6 @@ fn validate_spec_for_new_user_ns(spec: &Spec) -> std::result::Result<(), Validat
"validating spec for container with new user namespace"
);
let linux = spec.linux().as_ref().ok_or(MissingSpecError::Linux)?;
let namespaces = Namespaces::try_from(linux.namespaces().as_ref())?;
if namespaces.get(LinuxNamespaceType::User)?.is_none() {
return Err(ValidateSpecError::NoUserNamespace);
}
let gid_mappings = linux
.gid_mappings()
@ -303,9 +281,8 @@ fn validate_spec_for_new_user_ns(spec: &Spec) -> std::result::Result<(), Validat
.as_ref()
.and_then(|process| process.user().additional_gids().as_ref())
{
let privileged = nix::unistd::geteuid().is_root();
let privileged = !utils::rootless_required();
// TODO fix this along with fixes for podman
match (privileged, additional_gids.is_empty()) {
(true, false) => {
for gid in additional_gids {
@ -516,19 +493,6 @@ mod tests {
.size(10_u32)
.build()?];
let linux_no_userns = LinuxBuilder::default()
.namespaces(vec![])
.uid_mappings(uid_mappings.clone())
.gid_mappings(gid_mappings.clone())
.build()?;
assert!(validate_spec_for_new_user_ns(
&SpecBuilder::default()
.linux(linux_no_userns)
.build()
.unwrap()
)
.is_err());
let linux_uid_empty = LinuxBuilder::default()
.namespaces(vec![userns.clone()])
.uid_mappings(vec![])

@ -258,6 +258,21 @@ pub fn ensure_procfs(path: &Path) -> Result<(), EnsureProcfsError> {
Ok(())
}
pub fn is_in_new_userns() -> bool {
let uid_map_path = "/proc/self/uid_map";
let content = std::fs::read_to_string(uid_map_path)
.unwrap_or_else(|_| panic!("failed to read {}", uid_map_path));
!content.contains("4294967295")
}
/// Checks if rootless mode needs to be used
pub fn rootless_required() -> bool {
if !nix::unistd::geteuid().is_root() {
return true;
}
is_in_new_userns()
}
#[cfg(test)]
mod tests {
use super::*;

@ -73,7 +73,13 @@ where
let log_level_filter = tracing_subscriber::filter::LevelFilter::from(level);
let log_format = detect_log_format(config.log_format.as_deref())
.with_context(|| "failed to detect log format")?;
let systemd_journald = if config.systemd_log {
#[cfg(debug_assertions)]
let journald = true;
#[cfg(not(debug_assertions))]
let journald = config.systemd_log;
let systemd_journald = if journald {
Some(tracing_journald::layer()?.with_syslog_identifier("youki".to_string()))
} else {
None

@ -1,6 +1,6 @@
use anyhow::{bail, Result};
use libcontainer::user_ns::rootless_required;
use libcontainer::utils::create_dir_all_with_mode;
use libcontainer::utils::rootless_required;
use nix::libc;
use nix::sys::stat::Mode;
use nix::unistd::getuid;