From d4ce837b018c9d2963fa6709862ca4a7034c098c Mon Sep 17 00:00:00 2001 From: gursewak1997 Date: Fri, 14 Aug 2026 12:11:27 -0700 Subject: [PATCH] tmpfiles: Tolerate EACCES when resolving declared paths MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The path canonicalization added in cfec5cc0 opens the parent directory of every declared tmpfiles.d path to get its (dev, ino) identity. Entries like selinux-policy's `w /sys/fs/selinux/checkreqprot` point at virtual filesystem paths that return EACCES in rootless containers. Treat these the same as a missing parent — return None — since the /var walker cannot encounter inaccessible paths either. Fixes: https://github.com/containers/bootc/issues/2379 Assisted-by: AI Signed-off-by: gursewak1997 --- crates/tmpfiles/src/path_resolution.rs | 29 ++++++++++++++++++++++---- 1 file changed, 25 insertions(+), 4 deletions(-) diff --git a/crates/tmpfiles/src/path_resolution.rs b/crates/tmpfiles/src/path_resolution.rs index d3c140aa5..897e082cb 100644 --- a/crates/tmpfiles/src/path_resolution.rs +++ b/crates/tmpfiles/src/path_resolution.rs @@ -110,10 +110,12 @@ impl PathResolver { return Ok(Some(PathIdentity::new(self.root_dev, self.root_ino, leaf))); } - let Some(parent_file) = self.root_dir.open_optional(parent).map_err(to_err)? else { - // Some component of the parent doesn't exist: see the docs above - // on why `None` is correct here. - return Ok(None); + let parent_file = match self.root_dir.open_optional(parent) { + Ok(Some(f)) => f, + Ok(None) => return Ok(None), + // Tolerate inaccessible paths (EACCES in rootless containers). + Err(e) if e.kind() == std::io::ErrorKind::PermissionDenied => return Ok(None), + Err(e) => return Err(to_err(e)), }; let parent_meta = parent_file.metadata().map_err(to_err)?; Ok(Some(PathIdentity::new( @@ -126,6 +128,8 @@ impl PathResolver { #[cfg(test)] mod tests { + use cap_std::fs::PermissionsExt as _; + use super::*; fn newroot() -> Result { @@ -267,6 +271,23 @@ mod tests { Ok(()) } + #[test] + fn test_resolve_parent_identity_permission_denied() -> anyhow::Result<()> { + if rustix::process::getuid().is_root() { + return Ok(()); + } + let rootfs = &newroot()?; + rootfs.create_dir("noaccess")?; + rootfs.set_permissions("noaccess", cap_std::fs::Permissions::from_mode(0o000))?; + let resolver = PathResolver::new(rootfs)?; + let resolved = resolver.resolve_parent_identity(Path::new("/noaccess/child/leaf"))?; + assert_eq!(resolved, None, "EACCES parent should resolve to None"); + + // Restore permissions so the temp dir can be cleaned up. + rootfs.set_permissions("noaccess", cap_std::fs::Permissions::from_mode(0o755))?; + Ok(()) + } + #[test] fn test_resolve_parent_identity_chain() -> anyhow::Result<()> { let rootfs = &newroot()?;