Skip to content

Commit

Permalink
Change rootless required function and privilege decision
Browse files Browse the repository at this point in the history
  • Loading branch information
YJDoc2 committed Aug 18, 2023
1 parent 33ebda8 commit 07bd6ad
Show file tree
Hide file tree
Showing 9 changed files with 50 additions and 44 deletions.
11 changes: 10 additions & 1 deletion crates/libcgroups/src/common.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,15 @@ use super::stats::Stats;
pub const CGROUP_PROCS: &str = "cgroup.procs";
pub const DEFAULT_CGROUP_ROOT: &str = "/sys/fs/cgroup";

pub 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;

Expand Down Expand Up @@ -388,7 +397,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",
Expand Down
7 changes: 6 additions & 1 deletion crates/libcontainer/src/container/init_builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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::{
Expand Down Expand Up @@ -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);
Expand Down
4 changes: 4 additions & 0 deletions crates/libcontainer/src/container/tenant_builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)?;

Expand Down
2 changes: 2 additions & 0 deletions crates/libcontainer/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)]
Expand Down
3 changes: 2 additions & 1 deletion crates/libcontainer/src/process/container_init_process.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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(
Expand Down
42 changes: 3 additions & 39 deletions crates/libcontainer/src/user_ns.rs
Original file line number Diff line number Diff line change
@@ -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;
Expand Down Expand Up @@ -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")]
Expand Down Expand Up @@ -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");

Expand Down Expand Up @@ -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() {
Expand Down Expand Up @@ -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()
Expand Down Expand Up @@ -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 {
Expand Down Expand Up @@ -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![])
Expand Down
15 changes: 15 additions & 0 deletions crates/libcontainer/src/utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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::*;
Expand Down
8 changes: 7 additions & 1 deletion crates/youki/src/observability.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion crates/youki/src/rootpath.rs
Original file line number Diff line number Diff line change
@@ -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;
Expand Down

0 comments on commit 07bd6ad

Please sign in to comment.