From 76d801f7cd8b4ceb203eb4e8a76afd03e4bf2feb Mon Sep 17 00:00:00 2001 From: Connor-GH Date: Fri, 1 May 2026 17:01:39 -0500 Subject: [PATCH] openat2: fix internal assumption causing EINVAL Inside of `openat2`, we are assuming that if we are passed `AT_SYMLINK_NOFOLLOW` that we are also passed a symlink. This is simply not the case, as POSIX defines the flag to only have a noticable effect if the resolved path is a symlink. Therefore, we cannot assume that we have a symlink if we see `AT_SYMLINK_NOFOLLOW`. The previous behavior caused an `EINVAL` in redoxfs because we do a consistency check to error out if we are passed `O_SYMLINK` (which was added because `AT_SYMLINK_NOFOLLOW` was observed) and aren't a symlink. Hmm, maybe a special errno like `ENOTLNK` should be deployed for this? It's specific enough that it could possibly be added to a future POSIX. --- src/platform/redox/path.rs | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/src/platform/redox/path.rs b/src/platform/redox/path.rs index 4d4ae48358..fc2b090828 100644 --- a/src/platform/redox/path.rs +++ b/src/platform/redox/path.rs @@ -485,6 +485,14 @@ pub(super) fn openat2_path(dirfd: c_int, path: &str, at_flags: c_int) -> Result< } } +fn at_flags_to_open_flags(at_flags: c_int) -> c_int { + let mut out: c_int = 0; + if at_flags & fcntl::AT_SYMLINK_NOFOLLOW == fcntl::AT_SYMLINK_NOFOLLOW { + out |= fcntl::O_NOFOLLOW; + } + out +} + /// Canonicalize and open `path` with respect to `dirfd`. /// /// This unexported openat2 is similar to the Linux syscall but with a different interface. The @@ -512,11 +520,7 @@ pub(super) fn openat2( oflags: c_int, ) -> Result { // Translate at flags into open flags; openat will do this on its own most likely. - let oflags = if at_flags & fcntl::AT_SYMLINK_NOFOLLOW == fcntl::AT_SYMLINK_NOFOLLOW { - fcntl::O_CLOEXEC | fcntl::O_NOFOLLOW | fcntl::O_PATH | fcntl::O_SYMLINK | oflags - } else { - fcntl::O_CLOEXEC | oflags - }; + let oflags = at_flags_to_open_flags(at_flags) | fcntl::O_CLOEXEC | oflags; let c_path = CString::new(path).map_err(|_| Errno(EINVAL))?; File::openat(dirfd, c_path.as_c_str().into(), oflags) }