From 49083bfa31a89a5a5cb93f821e3d352477536fb1 Mon Sep 17 00:00:00 2001 From: Samuel Ortiz Date: Sun, 1 Aug 2021 02:14:03 +0200 Subject: [PATCH] agent: Create the process CWD when it does not exist Although the OCI specification does not explictly requires that, we should create the process CWD if it does not exist, before chdir'ing to it. Without that fizx, the kata-agent fails to create a container and returns a grpc error when it's trying to change the containerd working directory to an non existing folder. runc, the OCI runtime reference implementation, also creates the process CWD when it's not part of the container rootfs. Fixes #2374 Signed-off-by: Samuel Ortiz --- src/agent/rustjail/src/container.rs | 2 +- src/agent/rustjail/src/mount.rs | 17 ++++++++++++++--- 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/src/agent/rustjail/src/container.rs b/src/agent/rustjail/src/container.rs index 01bd54b9e6..c40816f6e3 100644 --- a/src/agent/rustjail/src/container.rs +++ b/src/agent/rustjail/src/container.rs @@ -561,7 +561,7 @@ fn do_init_child(cwfd: RawFd) -> Result<()> { } if to_new.contains(CloneFlags::CLONE_NEWNS) { - mount::finish_rootfs(cfd_log, &spec)?; + mount::finish_rootfs(cfd_log, &spec, &oci_process)?; } if !oci_process.cwd.is_empty() { diff --git a/src/agent/rustjail/src/mount.rs b/src/agent/rustjail/src/mount.rs index 8c4602615c..fb35e1ff12 100644 --- a/src/agent/rustjail/src/mount.rs +++ b/src/agent/rustjail/src/mount.rs @@ -13,7 +13,7 @@ use nix::mount::{MntFlags, MsFlags}; use nix::sys::stat::{self, Mode, SFlag}; use nix::unistd::{self, Gid, Uid}; use nix::NixPath; -use oci::{LinuxDevice, Mount, Spec}; +use oci::{LinuxDevice, Mount, Process, Spec}; use std::collections::{HashMap, HashSet}; use std::fs::{self, OpenOptions}; use std::mem::MaybeUninit; @@ -902,10 +902,21 @@ fn bind_dev(dev: &LinuxDevice) -> Result<()> { Ok(()) } -pub fn finish_rootfs(cfd_log: RawFd, spec: &Spec) -> Result<()> { +pub fn finish_rootfs(cfd_log: RawFd, spec: &Spec, process: &Process) -> Result<()> { let olddir = unistd::getcwd()?; log_child!(cfd_log, "old cwd: {}", olddir.to_str().unwrap()); unistd::chdir("/")?; + + if !process.cwd.is_empty() { + // Although the process.cwd string can be unclean/malicious (../../dev, etc), + // we are running on our own mount namespace and we just chrooted into the + // container's root. It's safe to create CWD from there. + log_child!(cfd_log, "Creating CWD {}", process.cwd.as_str()); + // Unconditionally try to create CWD, create_dir_all will not fail if + // it already exists. + fs::create_dir_all(process.cwd.as_str())?; + } + if spec.linux.is_some() { let linux = spec.linux.as_ref().unwrap(); @@ -1211,7 +1222,7 @@ mod tests { options: vec!["ro".to_string(), "shared".to_string()], }]; - let ret = finish_rootfs(stdout_fd, &spec); + let ret = finish_rootfs(stdout_fd, &spec, &oci::Process::default()); assert!(ret.is_ok(), "Should pass. Got: {:?}", ret); }