From e431e90b20d60d15816de81aef9adb67e0e939c3 Mon Sep 17 00:00:00 2001 From: Bananymous Date: Tue, 17 Sep 2024 18:35:01 +0300 Subject: [PATCH] Kernel/LibC: Implement all chown family function with fchownat --- kernel/include/kernel/Process.h | 2 +- kernel/kernel/Process.cpp | 37 ++++++++++++++++--- .../libraries/LibC/include/sys/syscall.h | 2 +- userspace/libraries/LibC/unistd.cpp | 17 ++++++++- 4 files changed, 49 insertions(+), 9 deletions(-) diff --git a/kernel/include/kernel/Process.h b/kernel/include/kernel/Process.h index 44d575416e..ac1b7f11cb 100644 --- a/kernel/include/kernel/Process.h +++ b/kernel/include/kernel/Process.h @@ -114,7 +114,7 @@ namespace Kernel BAN::ErrorOr sys_pread(int fd, void* buffer, size_t count, off_t offset); BAN::ErrorOr sys_fchmodat(int fd, const char* path, mode_t mode, int flag); - BAN::ErrorOr sys_chown(const char* path, uid_t uid, gid_t gid); + BAN::ErrorOr sys_fchownat(int fd, const char* path, uid_t uid, gid_t gid, int flag); BAN::ErrorOr sys_socket(int domain, int type, int protocol); BAN::ErrorOr sys_getsockname(int socket, sockaddr* address, socklen_t* address_len); diff --git a/kernel/kernel/Process.cpp b/kernel/kernel/Process.cpp index 8fba490f58..7dd25f0cf3 100644 --- a/kernel/kernel/Process.cpp +++ b/kernel/kernel/Process.cpp @@ -1062,14 +1062,39 @@ namespace Kernel return 0; } - BAN::ErrorOr Process::sys_chown(const char* path, uid_t uid, gid_t gid) + BAN::ErrorOr Process::sys_fchownat(int fd, const char* path, uid_t uid, gid_t gid, int flag) { - LockGuard _(m_process_lock); - TRY(validate_string_access(path)); + if (flag & ~AT_SYMLINK_NOFOLLOW) + return BAN::Error::from_errno(EINVAL); + if (flag == AT_SYMLINK_NOFOLLOW) + flag = O_NOFOLLOW; - auto absolute_path = TRY(absolute_path_of(path)); - auto file = TRY(VirtualFileSystem::get().file_from_absolute_path(m_credentials, absolute_path, O_WRONLY)); - TRY(file.inode->chown(uid, gid)); + LockGuard _(m_process_lock); + if (path) + TRY(validate_string_access(path)); + + VirtualFileSystem::File parent_file; + if (path && path[0] == '/') + parent_file = VirtualFileSystem::get().root_file(); + else if (fd == AT_FDCWD) + parent_file = TRY(m_working_directory.clone()); + else + parent_file = TRY(m_open_file_descriptors.file_of(fd)); + + auto inode = path + ? TRY(VirtualFileSystem::get().file_from_relative_path(parent_file, m_credentials, path, flag)).inode + : parent_file.inode; + + if (uid != -1 && !m_credentials.is_superuser()) + return BAN::Error::from_errno(EPERM); + if (gid != -1 && !m_credentials.is_superuser() && (m_credentials.euid() != uid || !m_credentials.has_egid(gid))) + return BAN::Error::from_errno(EPERM); + + if (uid == -1) + uid = inode->uid(); + if (gid == -1) + gid = inode->gid(); + TRY(inode->chown(uid, gid)); return 0; } diff --git a/userspace/libraries/LibC/include/sys/syscall.h b/userspace/libraries/LibC/include/sys/syscall.h index 5aef859c7f..bc5d9b27f5 100644 --- a/userspace/libraries/LibC/include/sys/syscall.h +++ b/userspace/libraries/LibC/include/sys/syscall.h @@ -57,7 +57,7 @@ __BEGIN_DECLS O(SYS_READLINKAT, readlinkat) \ O(SYS_MSYNC, msync) \ O(SYS_PREAD, pread) \ - O(SYS_CHOWN, chown) \ + O(SYS_FCHOWNAT, fchownat) \ O(SYS_LOAD_KEYMAP, load_keymap) \ O(SYS_SOCKET, socket) \ O(SYS_BIND, bind) \ diff --git a/userspace/libraries/LibC/unistd.cpp b/userspace/libraries/LibC/unistd.cpp index 62493da1d8..5553373145 100644 --- a/userspace/libraries/LibC/unistd.cpp +++ b/userspace/libraries/LibC/unistd.cpp @@ -315,7 +315,22 @@ int chdir(const char* path) int chown(const char* path, uid_t owner, gid_t group) { - return syscall(SYS_CHOWN, path, owner, group); + return fchownat(AT_FDCWD, path, owner, group, 0); +} + +int lchown(const char* path, uid_t owner, gid_t group) +{ + return fchownat(AT_FDCWD, path, owner, group, AT_SYMLINK_NOFOLLOW); +} + +int fchown(int fildes, uid_t owner, gid_t group) +{ + return fchownat(fildes, nullptr, owner, group, 0); +} + +int fchownat(int fd, const char* path, uid_t owner, gid_t group, int flag) +{ + return syscall(SYS_FCHOWNAT, fd, path, owner, group, flag); } void sync(void)