diff options
author | sin-ack <sin-ack@users.noreply.github.com> | 2022-10-01 12:24:56 +0000 |
---|---|---|
committer | Andrew Kaster <andrewdkaster@gmail.com> | 2022-12-11 19:55:37 -0700 |
commit | 2a502fe2326778ba7f5bded6b5e45476865b0ab1 (patch) | |
tree | b594a069d4b46d52643fc31397713de6f33cbfe2 | |
parent | fa692e13f944a5808ddc9c50e4e8015487c3ae0c (diff) | |
download | serenity-2a502fe2326778ba7f5bded6b5e45476865b0ab1.zip |
Kernel+LibC+LibCore+UserspaceEmulator: Implement `faccessat(2)`
Co-Authored-By: Daniel Bertalan <dani@danielbertalan.dev>
-rw-r--r-- | Kernel/API/POSIX/fcntl.h | 1 | ||||
-rw-r--r-- | Kernel/API/Syscall.h | 9 | ||||
-rw-r--r-- | Kernel/CMakeLists.txt | 2 | ||||
-rw-r--r-- | Kernel/FileSystem/VirtualFileSystem.cpp | 12 | ||||
-rw-r--r-- | Kernel/FileSystem/VirtualFileSystem.h | 10 | ||||
-rw-r--r-- | Kernel/Process.h | 2 | ||||
-rw-r--r-- | Kernel/Syscalls/access.cpp | 22 | ||||
-rw-r--r-- | Kernel/Syscalls/faccessat.cpp | 33 | ||||
-rw-r--r-- | Userland/DevTools/UserspaceEmulator/Emulator.h | 2 | ||||
-rw-r--r-- | Userland/DevTools/UserspaceEmulator/Emulator_syscalls.cpp | 16 | ||||
-rw-r--r-- | Userland/Libraries/LibC/unistd.cpp | 10 | ||||
-rw-r--r-- | Userland/Libraries/LibC/unistd.h | 1 | ||||
-rw-r--r-- | Userland/Libraries/LibCore/System.cpp | 8 |
13 files changed, 89 insertions, 39 deletions
diff --git a/Kernel/API/POSIX/fcntl.h b/Kernel/API/POSIX/fcntl.h index 9b6fb615ce..1aa225a789 100644 --- a/Kernel/API/POSIX/fcntl.h +++ b/Kernel/API/POSIX/fcntl.h @@ -48,6 +48,7 @@ extern "C" { #define AT_FDCWD -100 #define AT_SYMLINK_NOFOLLOW 0x100 #define AT_REMOVEDIR 0x200 +#define AT_EACCESS 0x400 struct flock { short l_type; diff --git a/Kernel/API/Syscall.h b/Kernel/API/Syscall.h index d31e79afe1..06b38e491d 100644 --- a/Kernel/API/Syscall.h +++ b/Kernel/API/Syscall.h @@ -41,7 +41,6 @@ enum class NeedsBigProcessLock { // #define ENUMERATE_SYSCALLS(S) \ S(accept4, NeedsBigProcessLock::No) \ - S(access, NeedsBigProcessLock::Yes) \ S(adjtime, NeedsBigProcessLock::No) \ S(alarm, NeedsBigProcessLock::Yes) \ S(allocate_tls, NeedsBigProcessLock::Yes) \ @@ -68,6 +67,7 @@ enum class NeedsBigProcessLock { S(execve, NeedsBigProcessLock::Yes) \ S(exit, NeedsBigProcessLock::Yes) \ S(exit_thread, NeedsBigProcessLock::Yes) \ + S(faccessat, NeedsBigProcessLock::Yes) \ S(fchdir, NeedsBigProcessLock::No) \ S(fchmod, NeedsBigProcessLock::No) \ S(fchown, NeedsBigProcessLock::No) \ @@ -508,6 +508,13 @@ struct SC_scheduler_parameters_params { struct sched_param parameters; }; +struct SC_faccessat_params { + int dirfd; + StringArgument pathname; + int mode; + int flags; +}; + void initialize(); int sync(); diff --git a/Kernel/CMakeLists.txt b/Kernel/CMakeLists.txt index 49f2d93093..2f5400b3da 100644 --- a/Kernel/CMakeLists.txt +++ b/Kernel/CMakeLists.txt @@ -264,7 +264,6 @@ set(KERNEL_SOURCES Scheduler.cpp StdLib.cpp Syscalls/anon_create.cpp - Syscalls/access.cpp Syscalls/alarm.cpp Syscalls/beep.cpp Syscalls/chdir.cpp @@ -276,6 +275,7 @@ set(KERNEL_SOURCES Syscalls/dup2.cpp Syscalls/emuctl.cpp Syscalls/exit.cpp + Syscalls/faccessat.cpp Syscalls/fallocate.cpp Syscalls/fcntl.cpp Syscalls/fsync.cpp diff --git a/Kernel/FileSystem/VirtualFileSystem.cpp b/Kernel/FileSystem/VirtualFileSystem.cpp index 398e8c4b8c..337cdfe8fd 100644 --- a/Kernel/FileSystem/VirtualFileSystem.cpp +++ b/Kernel/FileSystem/VirtualFileSystem.cpp @@ -523,24 +523,26 @@ ErrorOr<void> VirtualFileSystem::mkdir(Credentials const& credentials, StringVie return {}; } -ErrorOr<void> VirtualFileSystem::access(Credentials const& credentials, StringView path, int mode, Custody& base) +ErrorOr<void> VirtualFileSystem::access(Credentials const& credentials, StringView path, int mode, Custody& base, AccessFlags access_flags) { - auto custody = TRY(resolve_path(credentials, path, base)); + auto should_follow_symlinks = !has_flag(access_flags, AccessFlags::DoNotFollowSymlinks); + auto custody = TRY(resolve_path(credentials, path, base, nullptr, should_follow_symlinks ? 0 : O_NOFOLLOW_NOERROR)); auto& inode = custody->inode(); auto metadata = inode.metadata(); + auto use_effective_ids = has_flag(access_flags, AccessFlags::EffectiveAccess) ? UseEffectiveIDs::Yes : UseEffectiveIDs::No; if (mode & R_OK) { - if (!metadata.may_read(credentials, UseEffectiveIDs::No)) + if (!metadata.may_read(credentials, use_effective_ids)) return EACCES; } if (mode & W_OK) { - if (!metadata.may_write(credentials, UseEffectiveIDs::No)) + if (!metadata.may_write(credentials, use_effective_ids)) return EACCES; if (custody->is_readonly()) return EROFS; } if (mode & X_OK) { - if (!metadata.may_execute(credentials, UseEffectiveIDs::No)) + if (!metadata.may_execute(credentials, use_effective_ids)) return EACCES; } return {}; diff --git a/Kernel/FileSystem/VirtualFileSystem.h b/Kernel/FileSystem/VirtualFileSystem.h index 9a6be3362c..07c5af9055 100644 --- a/Kernel/FileSystem/VirtualFileSystem.h +++ b/Kernel/FileSystem/VirtualFileSystem.h @@ -34,6 +34,14 @@ struct UidAndGid { GroupID gid; }; +enum class AccessFlags { + None = 0, + EffectiveAccess = 1 << 0, + DoNotFollowSymlinks = 1 << 1, +}; + +AK_ENUM_BITWISE_OPERATORS(AccessFlags); + class VirtualFileSystem { public: // Required to be at least 8 by POSIX @@ -63,7 +71,7 @@ public: ErrorOr<void> chmod(Credentials const&, Custody&, mode_t); ErrorOr<void> chown(Credentials const&, StringView path, UserID, GroupID, Custody& base, int options); ErrorOr<void> chown(Credentials const&, Custody&, UserID, GroupID); - ErrorOr<void> access(Credentials const&, StringView path, int mode, Custody& base); + ErrorOr<void> access(Credentials const&, StringView path, int mode, Custody& base, AccessFlags); ErrorOr<InodeMetadata> lookup_metadata(Credentials const&, StringView path, Custody& base, int options = 0); ErrorOr<void> utime(Credentials const&, StringView path, Custody& base, time_t atime, time_t mtime); ErrorOr<void> utimensat(Credentials const&, StringView path, Custody& base, timespec const& atime, timespec const& mtime, int options = 0); diff --git a/Kernel/Process.h b/Kernel/Process.h index cc1410d9e0..d7d91c3986 100644 --- a/Kernel/Process.h +++ b/Kernel/Process.h @@ -371,7 +371,7 @@ public: ErrorOr<FlatPtr> sys$setresuid(UserID, UserID, UserID); ErrorOr<FlatPtr> sys$setresgid(GroupID, GroupID, GroupID); ErrorOr<FlatPtr> sys$alarm(unsigned seconds); - ErrorOr<FlatPtr> sys$access(Userspace<char const*> pathname, size_t path_length, int mode); + ErrorOr<FlatPtr> sys$faccessat(Userspace<Syscall::SC_faccessat_params const*>); ErrorOr<FlatPtr> sys$fcntl(int fd, int cmd, uintptr_t extra_arg); ErrorOr<FlatPtr> sys$ioctl(int fd, unsigned request, FlatPtr arg); ErrorOr<FlatPtr> sys$mkdir(int dirfd, Userspace<char const*> pathname, size_t path_length, mode_t mode); diff --git a/Kernel/Syscalls/access.cpp b/Kernel/Syscalls/access.cpp deleted file mode 100644 index 6a2a246e48..0000000000 --- a/Kernel/Syscalls/access.cpp +++ /dev/null @@ -1,22 +0,0 @@ -/* - * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org> - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#include <AK/StringView.h> -#include <Kernel/FileSystem/VirtualFileSystem.h> -#include <Kernel/Process.h> - -namespace Kernel { - -ErrorOr<FlatPtr> Process::sys$access(Userspace<char const*> user_path, size_t path_length, int mode) -{ - VERIFY_PROCESS_BIG_LOCK_ACQUIRED(this); - TRY(require_promise(Pledge::rpath)); - auto path = TRY(get_syscall_path_argument(user_path, path_length)); - TRY(VirtualFileSystem::the().access(credentials(), path->view(), mode, current_directory())); - return 0; -} - -} diff --git a/Kernel/Syscalls/faccessat.cpp b/Kernel/Syscalls/faccessat.cpp new file mode 100644 index 0000000000..edb7b1b637 --- /dev/null +++ b/Kernel/Syscalls/faccessat.cpp @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org> + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include <AK/StringView.h> +#include <Kernel/FileSystem/VirtualFileSystem.h> +#include <Kernel/Process.h> + +namespace Kernel { + +ErrorOr<FlatPtr> Process::sys$faccessat(Userspace<Syscall::SC_faccessat_params const*> user_params) +{ + VERIFY_PROCESS_BIG_LOCK_ACQUIRED(this); + TRY(require_promise(Pledge::rpath)); + auto params = TRY(copy_typed_from_user(user_params)); + auto pathname = TRY(get_syscall_path_argument(params.pathname)); + + if ((params.flags & ~(AT_SYMLINK_NOFOLLOW | AT_EACCESS)) != 0) + return EINVAL; + + auto flags = AccessFlags::None; + if (params.flags & AT_SYMLINK_NOFOLLOW) + flags |= AccessFlags::DoNotFollowSymlinks; + if (params.flags & AT_EACCESS) + flags |= AccessFlags::EffectiveAccess; + + TRY(VirtualFileSystem::the().access(credentials(), pathname->view(), params.mode, TRY(custody_for_dirfd(params.dirfd)), flags)); + return 0; +} + +} diff --git a/Userland/DevTools/UserspaceEmulator/Emulator.h b/Userland/DevTools/UserspaceEmulator/Emulator.h index 92b0c1d44b..5139c8ad07 100644 --- a/Userland/DevTools/UserspaceEmulator/Emulator.h +++ b/Userland/DevTools/UserspaceEmulator/Emulator.h @@ -144,7 +144,6 @@ private: void emit_profile_event(AK::OutputStream&, StringView event_name, DeprecatedString const& contents); int virt$accept4(FlatPtr); - int virt$access(FlatPtr, size_t, int); u32 virt$allocate_tls(FlatPtr, size_t); int virt$anon_create(size_t, int); int virt$beep(); @@ -164,6 +163,7 @@ private: int virt$emuctl(FlatPtr, FlatPtr, FlatPtr); int virt$execve(FlatPtr); void virt$exit(int); + int virt$faccessat(FlatPtr); int virt$fchmod(int, mode_t); int virt$fchown(int, uid_t, gid_t); u32 virt$fcntl(int fd, int, u32); diff --git a/Userland/DevTools/UserspaceEmulator/Emulator_syscalls.cpp b/Userland/DevTools/UserspaceEmulator/Emulator_syscalls.cpp index d213227e49..92454f0965 100644 --- a/Userland/DevTools/UserspaceEmulator/Emulator_syscalls.cpp +++ b/Userland/DevTools/UserspaceEmulator/Emulator_syscalls.cpp @@ -42,8 +42,6 @@ u32 Emulator::virt_syscall(u32 function, u32 arg1, u32 arg2, u32 arg3) switch (function) { case SC_accept4: return virt$accept4(arg1); - case SC_access: - return virt$access(arg1, arg2, arg3); case SC_allocate_tls: return virt$allocate_tls(arg1, arg2); case SC_anon_create: @@ -83,6 +81,8 @@ u32 Emulator::virt_syscall(u32 function, u32 arg1, u32 arg2, u32 arg3) case SC_exit: virt$exit((int)arg1); return 0; + case SC_faccessat: + return virt$faccessat(arg1); case SC_fchmod: return virt$fchmod(arg1, arg2); case SC_fchown: @@ -1462,10 +1462,16 @@ int Emulator::virt$getsid(pid_t pid) return syscall(SC_getsid, pid); } -int Emulator::virt$access(FlatPtr path, size_t path_length, int type) +int Emulator::virt$faccessat(FlatPtr params_addr) { - auto host_path = mmu().copy_buffer_from_vm(path, path_length); - return syscall(SC_access, host_path.data(), host_path.size(), type); + Syscall::SC_faccessat_params params; + mmu().copy_from_vm(¶ms, params_addr, sizeof(params)); + + auto host_path = mmu().copy_buffer_from_vm(reinterpret_cast<FlatPtr>(params.pathname.characters), params.pathname.length); + Syscall::SC_faccessat_params host_params = params; + host_params.pathname = { reinterpret_cast<char const*>(host_path.data()), host_path.size() }; + + return syscall(SC_faccessat, &host_params); } int Emulator::virt$waitid(FlatPtr params_addr) diff --git a/Userland/Libraries/LibC/unistd.cpp b/Userland/Libraries/LibC/unistd.cpp index b5dc377770..54c8a51361 100644 --- a/Userland/Libraries/LibC/unistd.cpp +++ b/Userland/Libraries/LibC/unistd.cpp @@ -799,11 +799,19 @@ int setresgid(gid_t rgid, gid_t egid, gid_t sgid) // https://pubs.opengroup.org/onlinepubs/9699919799/functions/access.html int access(char const* pathname, int mode) { + return faccessat(AT_FDCWD, pathname, mode, 0); +} + +// https://pubs.opengroup.org/onlinepubs/9699919799/functions/faccessat.html +int faccessat(int dirfd, char const* pathname, int mode, int flags) +{ if (!pathname) { errno = EFAULT; return -1; } - int rc = syscall(SC_access, pathname, strlen(pathname), mode); + + Syscall::SC_faccessat_params params { dirfd, { pathname, strlen(pathname) }, mode, flags }; + int rc = syscall(SC_faccessat, ¶ms); __RETURN_WITH_ERRNO(rc, rc, -1); } diff --git a/Userland/Libraries/LibC/unistd.h b/Userland/Libraries/LibC/unistd.h index 02d4bc672a..a7c104b2cb 100644 --- a/Userland/Libraries/LibC/unistd.h +++ b/Userland/Libraries/LibC/unistd.h @@ -104,6 +104,7 @@ int pipe(int pipefd[2]); int pipe2(int pipefd[2], int flags); unsigned int alarm(unsigned int seconds); int access(char const* pathname, int mode); +int faccessat(int dirfd, char const* pathname, int mode, int flags); int isatty(int fd); int mknod(char const* pathname, mode_t, dev_t); long fpathconf(int fd, int name); diff --git a/Userland/Libraries/LibCore/System.cpp b/Userland/Libraries/LibCore/System.cpp index f96519ebf4..c2bb6f135a 100644 --- a/Userland/Libraries/LibCore/System.cpp +++ b/Userland/Libraries/LibCore/System.cpp @@ -1372,7 +1372,13 @@ ErrorOr<void> access(StringView pathname, int mode) return Error::from_syscall("access"sv, -EFAULT); #ifdef AK_OS_SERENITY - int rc = ::syscall(Syscall::SC_access, pathname.characters_without_null_termination(), pathname.length(), mode); + Syscall::SC_faccessat_params params { + .dirfd = AT_FDCWD, + .pathname = { pathname.characters_without_null_termination(), pathname.length() }, + .mode = mode, + .flags = 0, + }; + int rc = ::syscall(Syscall::SC_faccessat, ¶ms); HANDLE_SYSCALL_RETURN_VALUE("access", rc, {}); #else DeprecatedString path_string = pathname; |