summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorsin-ack <sin-ack@users.noreply.github.com>2022-10-01 12:24:56 +0000
committerAndrew Kaster <andrewdkaster@gmail.com>2022-12-11 19:55:37 -0700
commit2a502fe2326778ba7f5bded6b5e45476865b0ab1 (patch)
treeb594a069d4b46d52643fc31397713de6f33cbfe2
parentfa692e13f944a5808ddc9c50e4e8015487c3ae0c (diff)
downloadserenity-2a502fe2326778ba7f5bded6b5e45476865b0ab1.zip
Kernel+LibC+LibCore+UserspaceEmulator: Implement `faccessat(2)`
Co-Authored-By: Daniel Bertalan <dani@danielbertalan.dev>
-rw-r--r--Kernel/API/POSIX/fcntl.h1
-rw-r--r--Kernel/API/Syscall.h9
-rw-r--r--Kernel/CMakeLists.txt2
-rw-r--r--Kernel/FileSystem/VirtualFileSystem.cpp12
-rw-r--r--Kernel/FileSystem/VirtualFileSystem.h10
-rw-r--r--Kernel/Process.h2
-rw-r--r--Kernel/Syscalls/access.cpp22
-rw-r--r--Kernel/Syscalls/faccessat.cpp33
-rw-r--r--Userland/DevTools/UserspaceEmulator/Emulator.h2
-rw-r--r--Userland/DevTools/UserspaceEmulator/Emulator_syscalls.cpp16
-rw-r--r--Userland/Libraries/LibC/unistd.cpp10
-rw-r--r--Userland/Libraries/LibC/unistd.h1
-rw-r--r--Userland/Libraries/LibCore/System.cpp8
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(&params, 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, &params);
__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, &params);
HANDLE_SYSCALL_RETURN_VALUE("access", rc, {});
#else
DeprecatedString path_string = pathname;