diff --git a/Kernel/FileSystem/File.h b/Kernel/FileSystem/File.h index f21ffc2d60..43d10e60be 100644 --- a/Kernel/FileSystem/File.h +++ b/Kernel/FileSystem/File.h @@ -57,6 +57,8 @@ public: virtual String absolute_path(const FileDescription&) const = 0; virtual KResult truncate(off_t) { return KResult(-EINVAL); } + virtual KResult chown(uid_t, gid_t) { return KResult(-EBADF); } + virtual KResult chmod(mode_t) { return KResult(-EBADF); } virtual const char* class_name() const = 0; diff --git a/Kernel/FileSystem/FileDescription.cpp b/Kernel/FileSystem/FileDescription.cpp index 067941d09d..0a4514db48 100644 --- a/Kernel/FileSystem/FileDescription.cpp +++ b/Kernel/FileSystem/FileDescription.cpp @@ -64,13 +64,6 @@ KResult FileDescription::fstat(stat& buffer) return metadata().stat(buffer); } -KResult FileDescription::fchmod(mode_t mode) -{ - if (!m_inode) - return KResult(-EBADF); - return VFS::the().chmod(*m_inode, mode); -} - off_t FileDescription::seek(off_t offset, int whence) { if (!m_file->is_seekable()) @@ -282,9 +275,12 @@ void FileDescription::set_file_flags(u32 flags) m_file_flags = flags; } +KResult FileDescription::chmod(mode_t mode) +{ + return m_file->chmod(mode); +} + KResult FileDescription::chown(uid_t uid, gid_t gid) { - if (!m_inode) - return KResult(-EINVAL); - return VFS::the().chown(*m_inode, uid, gid); + return m_file->chown(uid, gid); } diff --git a/Kernel/FileSystem/FileDescription.h b/Kernel/FileSystem/FileDescription.h index df3ab85429..8d7f5b499a 100644 --- a/Kernel/FileSystem/FileDescription.h +++ b/Kernel/FileSystem/FileDescription.h @@ -52,7 +52,7 @@ public: ssize_t write(const u8* data, ssize_t); KResult fstat(stat&); - KResult fchmod(mode_t); + KResult chmod(mode_t); bool can_read() const; bool can_write() const; diff --git a/Kernel/FileSystem/InodeFile.cpp b/Kernel/FileSystem/InodeFile.cpp index ea7a2347b6..f3449498a8 100644 --- a/Kernel/FileSystem/InodeFile.cpp +++ b/Kernel/FileSystem/InodeFile.cpp @@ -52,3 +52,13 @@ KResult InodeFile::truncate(off_t size) { return m_inode->truncate(size); } + +KResult InodeFile::chown(uid_t uid, gid_t gid) +{ + return VFS::the().chown(*m_inode, uid, gid); +} + +KResult InodeFile::chmod(mode_t mode) +{ + return VFS::the().chmod(*m_inode, mode); +} diff --git a/Kernel/FileSystem/InodeFile.h b/Kernel/FileSystem/InodeFile.h index c7def9be45..46a732d5fa 100644 --- a/Kernel/FileSystem/InodeFile.h +++ b/Kernel/FileSystem/InodeFile.h @@ -26,6 +26,8 @@ public: virtual String absolute_path(const FileDescription&) const override; virtual KResult truncate(off_t) override; + virtual KResult chown(uid_t, gid_t) override; + virtual KResult chmod(mode_t) override; virtual const char* class_name() const override { return "InodeFile"; } diff --git a/Kernel/Net/LocalSocket.cpp b/Kernel/Net/LocalSocket.cpp index 605dc5a660..01782d6762 100644 --- a/Kernel/Net/LocalSocket.cpp +++ b/Kernel/Net/LocalSocket.cpp @@ -34,6 +34,10 @@ LocalSocket::LocalSocket(int type) LOCKER(all_sockets().lock()); all_sockets().resource().append(this); + m_prebind_uid = current->process().uid(); + m_prebind_gid = current->process().gid(); + m_prebind_mode = 0666; + #ifdef DEBUG_LOCAL_SOCKET kprintf("%s(%u) LocalSocket{%p} created with type=%u\n", current->process().name().characters(), current->pid(), this, type); #endif @@ -76,7 +80,9 @@ KResult LocalSocket::bind(const sockaddr* address, socklen_t address_size) kprintf("%s(%u) LocalSocket{%p} bind(%s)\n", current->process().name().characters(), current->pid(), this, safe_address); #endif - auto result = VFS::the().open(safe_address, O_CREAT | O_EXCL, S_IFSOCK | 0666, current->process().current_directory()); + mode_t mode = S_IFSOCK | (m_prebind_mode & ~current->process().umask()); + UidAndGid owner { m_prebind_uid, m_prebind_gid }; + auto result = VFS::the().open( safe_address, O_CREAT | O_EXCL, mode, current->process().current_directory(), owner); if (result.is_error()) { if (result.error() == -EEXIST) return KResult(-EADDRINUSE); @@ -334,3 +340,25 @@ KResult LocalSocket::getsockopt(FileDescription& description, int level, int opt return Socket::getsockopt(description, level, option, value, value_size); } } + +KResult LocalSocket::chmod(mode_t mode) +{ + if (m_file) + return m_file->chmod(mode); + + m_prebind_mode = mode & 04777; + return KSuccess; +} + +KResult LocalSocket::chown(uid_t uid, gid_t gid) +{ + if (m_file) + return m_file->chown(uid, gid); + + if (!current->process().is_superuser() && (current->process().euid() != uid || !current->process().in_group(gid))) + return KResult(-EPERM); + + m_prebind_uid = uid; + m_prebind_gid = gid; + return KSuccess; +} diff --git a/Kernel/Net/LocalSocket.h b/Kernel/Net/LocalSocket.h index 2d3566eb4c..ba292c7286 100644 --- a/Kernel/Net/LocalSocket.h +++ b/Kernel/Net/LocalSocket.h @@ -30,6 +30,8 @@ public: virtual ssize_t sendto(FileDescription&, const void*, size_t, int, const sockaddr*, socklen_t) override; virtual ssize_t recvfrom(FileDescription&, void*, size_t, int flags, sockaddr*, socklen_t*) override; virtual KResult getsockopt(FileDescription&, int level, int option, void*, socklen_t*) override; + virtual KResult chown(uid_t, gid_t) override; + virtual KResult chmod(mode_t) override; private: explicit LocalSocket(int type); @@ -43,6 +45,10 @@ private: // An open socket file on the filesystem. RefPtr m_file; + uid_t m_prebind_uid { 0 }; + uid_t m_prebind_gid { 0 }; + mode_t m_prebind_mode { 0 }; + // A single LocalSocket is shared between two file descriptions // on the connect side and the accept side; so we need to store // an additional role for the connect side and differentiate diff --git a/Kernel/Process.cpp b/Kernel/Process.cpp index 80cd27a945..62d5cccf0b 100644 --- a/Kernel/Process.cpp +++ b/Kernel/Process.cpp @@ -2524,7 +2524,7 @@ int Process::sys$fchmod(int fd, mode_t mode) auto* description = file_description(fd); if (!description) return -EBADF; - return description->fchmod(mode); + return description->chmod(mode); } int Process::sys$fchown(int fd, uid_t uid, gid_t gid)