From 60a2e27f02a24e3e1de065f80777070c6a47b5ee Mon Sep 17 00:00:00 2001 From: PiotrProkop Date: Tue, 26 May 2026 15:06:50 +0200 Subject: [PATCH] agent: Restore process CWD auto-creation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Commit b56313472 ("agent: Align agent OCI spec with oci-spec-rs", PR #9944) inverted the condition guarding the create_dir_all call for process.cwd: the leading `!` was dropped during the refactor. As a result, the CWD is created only when process.cwd is the empty string. When the guest then runs chdir(process.cwd) and CWD doesn't exist it returns ENOENT. The agent propagates that to the shim, which surfaces it to containerd as "failed to create shim task: ENOENT: No such file or directory" — indistinguishable from a missing argv[0]. This regressed the original fix in PR #2375 (Fixes #2374), which deliberately mirrored runc's behavior. Put the `!` back. Co-Authored-By: Claude Opus 4.7 (1M context) Signed-off-by: PiotrProkop --- src/agent/rustjail/src/mount.rs | 48 ++++++++++++++++++++++++++++++++- 1 file changed, 47 insertions(+), 1 deletion(-) diff --git a/src/agent/rustjail/src/mount.rs b/src/agent/rustjail/src/mount.rs index fce3547850..fb80d3fdc8 100644 --- a/src/agent/rustjail/src/mount.rs +++ b/src/agent/rustjail/src/mount.rs @@ -1016,7 +1016,7 @@ pub fn finish_rootfs(cfd_log: RawFd, spec: &Spec, process: &Process) -> Result<( unistd::chdir("/")?; let process_cwd = process.cwd().display().to_string(); - if process_cwd.is_empty() { + 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. @@ -1339,6 +1339,52 @@ mod tests { assert!(ret.is_ok(), "Should pass. Got: {:?}", ret); } + // Regression test for the bug where the create_dir_all guard was inverted + // and CWD was only created when process.cwd was empty (the opposite of + // what we want). See PR #2375 (original fix for #2374) and the regression + // introduced by PR #9944 ("agent: Align agent OCI spec with oci-spec-rs"). + #[test] + #[serial(chdir)] + fn test_finish_rootfs_creates_missing_cwd() { + let stdout_fd = std::io::stdout().as_raw_fd(); + + // Pick a unique absolute path that does not yet exist on disk. The + // function chdirs to "/" before creating CWD, so the path is taken to + // be relative to the (test process's) filesystem root. + let unique = format!( + "kata-rustjail-cwd-test-{}-{}", + std::process::id(), + std::time::SystemTime::now() + .duration_since(std::time::UNIX_EPOCH) + .unwrap() + .as_nanos(), + ); + let cwd_path = std::path::PathBuf::from("/tmp").join(&unique); + assert!( + !cwd_path.exists(), + "test cwd path unexpectedly already exists: {:?}", + cwd_path, + ); + + let mut spec = oci::Spec::default(); + spec.set_linux(Some(oci::Linux::default())); + + let mut process = oci::Process::default(); + process.set_cwd(cwd_path.clone()); + + let ret = finish_rootfs(stdout_fd, &spec, &process); + + let created = cwd_path.exists(); + let _ = remove_dir_all(&cwd_path); + + assert!(ret.is_ok(), "finish_rootfs failed: {:?}", ret); + assert!( + created, + "finish_rootfs did not create process.cwd: {:?}", + cwd_path, + ); + } + #[test] fn test_readonly_path() { let ret = readonly_path("abc");