From 4aa466b9488c94511d4b65f725cd7356af0f8743 Mon Sep 17 00:00:00 2001 From: Bananymous Date: Tue, 17 Sep 2024 17:16:46 +0300 Subject: [PATCH] Kernel/LibC: Implement all chmod family functions using fchmodat --- kernel/include/kernel/Process.h | 3 +- kernel/kernel/Process.cpp | 41 +++++++++++-------- .../libraries/LibC/include/sys/syscall.h | 3 +- userspace/libraries/LibC/sys/stat.cpp | 9 +++- 4 files changed, 34 insertions(+), 22 deletions(-) diff --git a/kernel/include/kernel/Process.h b/kernel/include/kernel/Process.h index f7c98169..44d57541 100644 --- a/kernel/include/kernel/Process.h +++ b/kernel/include/kernel/Process.h @@ -113,8 +113,7 @@ namespace Kernel BAN::ErrorOr sys_pread(int fd, void* buffer, size_t count, off_t offset); - BAN::ErrorOr sys_chmod(const char* path, mode_t mode); - BAN::ErrorOr sys_fchmod(int fildes, mode_t mode); + 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_socket(int domain, int type, int protocol); diff --git a/kernel/kernel/Process.cpp b/kernel/kernel/Process.cpp index 784cbbf1..8fba490f 100644 --- a/kernel/kernel/Process.cpp +++ b/kernel/kernel/Process.cpp @@ -1026,28 +1026,37 @@ namespace Kernel return TRY(inode->read(offset, { (uint8_t*)buffer, count })); } - BAN::ErrorOr Process::sys_chmod(const char* path, mode_t mode) + BAN::ErrorOr Process::sys_fchmodat(int fd, const char* path, mode_t mode, int flag) { if (mode & S_IFMASK) return BAN::Error::from_errno(EINVAL); - - LockGuard _(m_process_lock); - TRY(validate_string_access(path)); - - 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->chmod(mode)); - - return 0; - } - - BAN::ErrorOr Process::sys_fchmod(int fildes, mode_t mode) - { - if (mode & S_IFMASK) + if (flag & ~AT_SYMLINK_NOFOLLOW) return BAN::Error::from_errno(EINVAL); + if (flag == AT_SYMLINK_NOFOLLOW) + flag = O_NOFOLLOW; LockGuard _(m_process_lock); - auto inode = TRY(m_open_file_descriptors.inode_of(fildes)); + 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 (!m_credentials.is_superuser() && inode->uid() != m_credentials.euid()) + { + dwarnln("cannot chmod uid {} vs {}", inode->uid(), m_credentials.euid()); + return BAN::Error::from_errno(EPERM); + } + TRY(inode->chmod(mode)); return 0; diff --git a/userspace/libraries/LibC/include/sys/syscall.h b/userspace/libraries/LibC/include/sys/syscall.h index 071c70c7..5aef859c 100644 --- a/userspace/libraries/LibC/include/sys/syscall.h +++ b/userspace/libraries/LibC/include/sys/syscall.h @@ -51,8 +51,7 @@ __BEGIN_DECLS O(SYS_MUNMAP, munmap) \ O(SYS_TTY_CTRL, tty_ctrl) \ O(SYS_POWEROFF, poweroff) \ - O(SYS_CHMOD, chmod) \ - O(SYS_FCHMOD, fchmod) \ + O(SYS_FCHMODAT, fchmodat) \ O(SYS_CREATE_DIR, create_dir) \ O(SYS_UNLINK, unlink) \ O(SYS_READLINKAT, readlinkat) \ diff --git a/userspace/libraries/LibC/sys/stat.cpp b/userspace/libraries/LibC/sys/stat.cpp index ad3189e9..d1ffb259 100644 --- a/userspace/libraries/LibC/sys/stat.cpp +++ b/userspace/libraries/LibC/sys/stat.cpp @@ -9,12 +9,17 @@ mode_t __umask = 0; int chmod(const char* path, mode_t mode) { - return syscall(SYS_CHMOD, path, mode); + return fchmodat(AT_FDCWD, path, mode, 0); } int fchmod(int fildes, mode_t mode) { - return syscall(SYS_FCHMOD, fildes, mode); + return fchmodat(fildes, nullptr, mode, 0); +} + +int fchmodat(int fildes, const char* path, mode_t mode, int flag) +{ + return syscall(SYS_FCHMODAT, fildes, path, mode, flag); } int fstat(int fildes, struct stat* buf)