use anyhow::{Context, bail};
use nix::unistd::{self, Pid};
use crate::capabilities;
use crate::cgroup;
use crate::namespace;
use crate::procfs::ProcStatus;
use crate::result::Result;
fn enter_namespaces(container_pid: Pid) -> Result<bool> {
let supported_namespaces =
namespace::supported_namespaces().context("failed to list namespaces")?;
if !supported_namespaces.contains(namespace::MOUNT.name) {
bail!("the system has no support for mount namespaces");
}
let mount_namespace = namespace::MOUNT
.open(container_pid)
.context("could not access mount namespace")?;
let mut other_namespaces = Vec::new();
let mut user_ns_entered = false;
let other_kinds = &[
namespace::UTS,
namespace::CGROUP,
namespace::PID,
namespace::NET,
namespace::IPC,
namespace::USER,
];
for kind in other_kinds {
if !supported_namespaces.contains(kind.name) {
continue;
}
if kind.is_same(container_pid) {
continue;
}
let ns = kind
.open(container_pid)
.with_context(|| format!("failed to open {} namespace", kind.name))?;
if kind.name == namespace::USER.name {
user_ns_entered = true;
}
other_namespaces.push(ns);
}
mount_namespace
.apply()
.context("failed to enter mount namespace")?;
for ns in other_namespaces {
ns.apply().context("failed to apply namespace")?;
}
Ok(user_ns_entered)
}
pub(crate) fn apply_security_context(
process_status: &mut ProcStatus,
in_user_namespace: bool,
) -> Result<()> {
if in_user_namespace {
let _ = unistd::setgroups(&[]);
unistd::setgid(process_status.gid).context("could not set group id")?;
unistd::setuid(process_status.uid).context("could not set user id")?;
}
capabilities::drop(
process_status.effective_capabilities,
process_status.last_cap,
)
.context("failed to apply capabilities")?;
Ok(())
}
pub(crate) fn enter_container(process_status: &mut ProcStatus) -> Result<()> {
cgroup::move_to(unistd::getpid(), process_status.global_pid)
.context("failed to change cgroup")?;
let in_user_ns = enter_namespaces(process_status.global_pid).with_context(|| {
format!(
"failed to enter namespaces for PID {}",
process_status.global_pid
)
})?;
apply_security_context(process_status, in_user_ns).with_context(|| {
format!(
"failed to apply security context (UID={}, GID={})",
process_status.uid, process_status.gid
)
})?;
Ok(())
}