From 2557cba4f8dd82618cc11dc07552e869a5fe22e5 Mon Sep 17 00:00:00 2001 From: Aleksa Sarai Date: Mon, 9 Dec 2024 00:31:14 +1100 Subject: [PATCH] Root::mkdir_all: switch mkdir loop to use basic openat There is no reason to use the resolver to look a path component under a directory we have a handle to already. The O_NOFOLLOW behaviour was also somewhat hidden behind the way the resolver API works. Signed-off-by: Aleksa Sarai --- src/root.rs | 23 +++++++++++++++++------ 1 file changed, 17 insertions(+), 6 deletions(-) diff --git a/src/root.rs b/src/root.rs index b60a22cd..5f1704cc 100644 --- a/src/root.rs +++ b/src/root.rs @@ -995,6 +995,12 @@ impl RootRef<'_> { // For the remaining components, create a each component one-by-one. for part in remaining_parts { + if part.as_bytes().contains(&b'/') { + Err(ErrorImpl::SafetyViolation { + description: "remaining component for mkdir contains '/'".into(), + })?; + } + // NOTE: mkdirat(2) does not follow trailing symlinks (even if it is // a dangling symlink with only a trailing component missing), so we // can safely create the final component without worrying about @@ -1009,11 +1015,16 @@ impl RootRef<'_> { // Get a handle to the directory we just created. Unfortunately we // can't do an atomic create+open (a-la O_CREAT) with mkdirat(), so // a separate O_NOFOLLOW is the best we can do. - let next = self - .resolver - .resolve(¤t, &part, true) - .and_then(|handle| handle.reopen(OpenFlags::O_DIRECTORY)) - .wrap("failed to open newly-created directory with O_DIRECTORY")?; + let next = syscalls::openat( + ¤t, + &part, + OpenFlags::O_NOFOLLOW | OpenFlags::O_DIRECTORY, + 0, + ) + .map_err(|err| ErrorImpl::RawOsError { + operation: "open newly created directory".into(), + source: err, + })?; // Unfortunately, we cannot create a directory and open it // atomically (a-la O_CREAT). This means an attacker could swap our @@ -1035,7 +1046,7 @@ impl RootRef<'_> { // doesn't seem to provide any practical benefit. // Keep walking. - current = next; + current = next.into(); } Ok(Handle::from_fd(current))