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.
This commit is contained in:
@@ -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<File, Errno> {
|
||||
// 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)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user