diff --git a/Kernel/CMakeLists.txt b/Kernel/CMakeLists.txt index 7157fa197b8..b850dc3291c 100644 --- a/Kernel/CMakeLists.txt +++ b/Kernel/CMakeLists.txt @@ -43,6 +43,7 @@ set(KERNEL_SOURCES CMOS.cpp CommandLine.cpp Coredump.cpp + Credentials.cpp Devices/AsyncDeviceRequest.cpp Devices/Audio/AC97.cpp Devices/Audio/Channel.cpp diff --git a/Kernel/Credentials.cpp b/Kernel/Credentials.cpp new file mode 100644 index 00000000000..06eea482273 --- /dev/null +++ b/Kernel/Credentials.cpp @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2022, Andreas Kling + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include +#include +#include + +namespace Kernel { + +ErrorOr> Credentials::create(UserID uid, GroupID gid, UserID euid, GroupID egid, UserID suid, GroupID sgid, Span extra_gids) +{ + auto extra_gids_array = TRY(FixedArray::try_create(extra_gids)); + return adopt_nonnull_ref_or_enomem(new (nothrow) Credentials(uid, gid, euid, egid, suid, sgid, move(extra_gids_array))); +} + +Credentials::Credentials(UserID uid, GroupID gid, UserID euid, GroupID egid, UserID suid, GroupID sgid, FixedArray extra_gids) + : m_uid(uid) + , m_gid(gid) + , m_euid(euid) + , m_egid(egid) + , m_suid(suid) + , m_sgid(sgid) + , m_extra_gids(move(extra_gids)) +{ +} + +Credentials::~Credentials() = default; + +} diff --git a/Kernel/Credentials.h b/Kernel/Credentials.h new file mode 100644 index 00000000000..08ebcce1d2e --- /dev/null +++ b/Kernel/Credentials.h @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2022, Andreas Kling + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#pragma once + +#include +#include +#include + +namespace Kernel { + +class Credentials final : public AtomicRefCounted { +public: + static ErrorOr> create(UserID uid, GroupID gid, UserID euid, GroupID egid, UserID suid, GroupID sgid, Span extra_gids); + ~Credentials(); + + bool is_superuser() const { return euid() == 0; } + + UserID euid() const { return m_euid; } + GroupID egid() const { return m_egid; } + UserID uid() const { return m_uid; } + GroupID gid() const { return m_gid; } + UserID suid() const { return m_suid; } + GroupID sgid() const { return m_sgid; } + Span extra_gids() const { return m_extra_gids.span(); } + +private: + Credentials(UserID uid, GroupID gid, UserID euid, GroupID egid, UserID suid, GroupID sgid, FixedArray extra_gids); + + UserID m_uid; + GroupID m_gid; + UserID m_euid; + GroupID m_egid; + UserID m_suid; + GroupID m_sgid; + FixedArray m_extra_gids; +}; + +} diff --git a/Kernel/FileSystem/InodeMetadata.cpp b/Kernel/FileSystem/InodeMetadata.cpp index ec112ac6b6e..35b7074d999 100644 --- a/Kernel/FileSystem/InodeMetadata.cpp +++ b/Kernel/FileSystem/InodeMetadata.cpp @@ -11,17 +11,20 @@ namespace Kernel { bool InodeMetadata::may_read(Process const& process) const { - return may_read(process.euid(), process.egid(), process.extra_gids()); + auto credentials = process.credentials(); + return may_read(credentials->euid(), credentials->egid(), credentials->extra_gids()); } bool InodeMetadata::may_write(Process const& process) const { - return may_write(process.euid(), process.egid(), process.extra_gids()); + auto credentials = process.credentials(); + return may_write(credentials->euid(), credentials->egid(), credentials->extra_gids()); } bool InodeMetadata::may_execute(Process const& process) const { - return may_execute(process.euid(), process.egid(), process.extra_gids()); + auto credentials = process.credentials(); + return may_execute(credentials->euid(), credentials->egid(), credentials->extra_gids()); } } diff --git a/Kernel/Forward.h b/Kernel/Forward.h index a82e12963ca..04bacdf7c1b 100644 --- a/Kernel/Forward.h +++ b/Kernel/Forward.h @@ -14,6 +14,7 @@ namespace Kernel { class BlockDevice; class CharacterDevice; class Coredump; +class Credentials; class Custody; class DevTmpFSDeviceInode; class DevTmpFSDirectoryInode; diff --git a/Kernel/Process.cpp b/Kernel/Process.cpp index 71dac127adc..5adb6d85e72 100644 --- a/Kernel/Process.cpp +++ b/Kernel/Process.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018-2021, Andreas Kling + * Copyright (c) 2018-2022, Andreas Kling * * SPDX-License-Identifier: BSD-2-Clause */ @@ -11,6 +11,7 @@ #include #include #include +#include #include #include #ifdef ENABLE_KERNEL_COVERAGE_COLLECTION @@ -85,7 +86,8 @@ UNMAP_AFTER_INIT void Process::initialize() bool Process::in_group(GroupID gid) const { - return this->gid() == gid || extra_gids().contains_slow(gid); + auto credentials = this->credentials(); + return credentials->gid() == gid || credentials->extra_gids().contains_slow(gid); } void Process::kill_threads_except_self() @@ -224,12 +226,13 @@ ErrorOr> Process::try_create(LockRefPtr& firs { auto space = TRY(Memory::AddressSpace::try_create(fork_parent ? &fork_parent->address_space() : nullptr)); auto unveil_tree = UnveilNode { TRY(KString::try_create("/"sv)), UnveilMetadata(TRY(KString::try_create("/"sv))) }; - auto process = TRY(adopt_nonnull_lock_ref_or_enomem(new (nothrow) Process(move(name), uid, gid, ppid, is_kernel_process, move(current_directory), move(executable), tty, move(unveil_tree)))); + auto credentials = TRY(Credentials::create(uid, gid, uid, gid, uid, gid, {})); + auto process = TRY(adopt_nonnull_lock_ref_or_enomem(new (nothrow) Process(move(name), move(credentials), ppid, is_kernel_process, move(current_directory), move(executable), tty, move(unveil_tree)))); TRY(process->attach_resources(move(space), first_thread, fork_parent)); return process; } -Process::Process(NonnullOwnPtr name, UserID uid, GroupID gid, ProcessID ppid, bool is_kernel_process, LockRefPtr current_directory, LockRefPtr executable, TTY* tty, UnveilNode unveil_tree) +Process::Process(NonnullOwnPtr name, NonnullRefPtr credentials, ProcessID ppid, bool is_kernel_process, LockRefPtr current_directory, LockRefPtr executable, TTY* tty, UnveilNode unveil_tree) : m_name(move(name)) , m_is_kernel_process(is_kernel_process) , m_executable(move(executable)) @@ -243,12 +246,7 @@ Process::Process(NonnullOwnPtr name, UserID uid, GroupID gid, ProcessID m_protected_values.pid = allocate_pid(); m_protected_values.ppid = ppid; - m_protected_values.uid = uid; - m_protected_values.gid = gid; - m_protected_values.euid = uid; - m_protected_values.egid = gid; - m_protected_values.suid = uid; - m_protected_values.sgid = gid; + m_protected_values.credentials = move(credentials); dbgln_if(PROCESS_DEBUG, "Created new process {}({})", m_name, this->pid().value()); } @@ -938,4 +936,39 @@ ErrorOr Process::require_promise(Pledge promise) return EPROMISEVIOLATION; } +UserID Process::uid() const +{ + return credentials()->uid(); +} + +GroupID Process::gid() const +{ + return credentials()->gid(); +} + +UserID Process::euid() const +{ + return credentials()->euid(); +} + +GroupID Process::egid() const +{ + return credentials()->egid(); +} + +UserID Process::suid() const +{ + return credentials()->suid(); +} + +GroupID Process::sgid() const +{ + return credentials()->sgid(); +} + +NonnullRefPtr Process::credentials() const +{ + return *m_protected_values.credentials; +} + } diff --git a/Kernel/Process.h b/Kernel/Process.h index d81fa3a335d..887b80aea0f 100644 --- a/Kernel/Process.h +++ b/Kernel/Process.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018-2021, Andreas Kling + * Copyright (c) 2018-2022, Andreas Kling * * SPDX-License-Identifier: BSD-2-Clause */ @@ -11,12 +11,14 @@ #include #include #include +#include #include #include #include #include #include #include +#include #include #include #include @@ -110,13 +112,8 @@ class Process final ProcessID pid { 0 }; ProcessID ppid { 0 }; SessionID sid { 0 }; - UserID euid { 0 }; - GroupID egid { 0 }; - UserID uid { 0 }; - GroupID gid { 0 }; - UserID suid { 0 }; - GroupID sgid { 0 }; - Vector extra_gids; + // FIXME: This should be a NonnullRefPtr + RefPtr credentials; bool dumpable { false }; Atomic has_promises { false }; Atomic promises { 0 }; @@ -226,15 +223,17 @@ public: bool is_session_leader() const { return sid().value() == pid().value(); } ProcessGroupID pgid() const { return m_pg ? m_pg->pgid() : 0; } bool is_group_leader() const { return pgid().value() == pid().value(); } - Vector const& extra_gids() const { return m_protected_values.extra_gids; } - UserID euid() const { return m_protected_values.euid; } - GroupID egid() const { return m_protected_values.egid; } - UserID uid() const { return m_protected_values.uid; } - GroupID gid() const { return m_protected_values.gid; } - UserID suid() const { return m_protected_values.suid; } - GroupID sgid() const { return m_protected_values.sgid; } ProcessID ppid() const { return m_protected_values.ppid; } + NonnullRefPtr credentials() const; + + UserID euid() const; + GroupID egid() const; + UserID uid() const; + GroupID gid() const; + UserID suid() const; + GroupID sgid() const; + bool is_dumpable() const { return m_protected_values.dumpable; } void set_dumpable(bool); @@ -353,8 +352,8 @@ public: ErrorOr sys$sigpending(Userspace); ErrorOr sys$sigsuspend(Userspace); ErrorOr sys$sigtimedwait(Userspace, Userspace, Userspace); - ErrorOr sys$getgroups(size_t, Userspace); - ErrorOr sys$setgroups(size_t, Userspace); + ErrorOr sys$getgroups(size_t, Userspace); + ErrorOr sys$setgroups(size_t, Userspace); ErrorOr sys$pipe(Userspace, int flags); ErrorOr sys$killpg(pid_t pgrp, int sig); ErrorOr sys$seteuid(UserID); @@ -557,7 +556,7 @@ private: bool add_thread(Thread&); bool remove_thread(Thread&); - Process(NonnullOwnPtr name, UserID, GroupID, ProcessID ppid, bool is_kernel_process, LockRefPtr current_directory, LockRefPtr executable, TTY* tty, UnveilNode unveil_tree); + Process(NonnullOwnPtr name, NonnullRefPtr, ProcessID ppid, bool is_kernel_process, LockRefPtr current_directory, LockRefPtr executable, TTY* tty, UnveilNode unveil_tree); static ErrorOr> try_create(LockRefPtr& first_thread, NonnullOwnPtr name, UserID, GroupID, ProcessID ppid, bool is_kernel_process, LockRefPtr current_directory = nullptr, LockRefPtr executable = nullptr, TTY* = nullptr, Process* fork_parent = nullptr); ErrorOr attach_resources(NonnullOwnPtr&&, LockRefPtr& first_thread, Process* fork_parent); static ProcessID allocate_pid(); diff --git a/Kernel/Syscalls/execve.cpp b/Kernel/Syscalls/execve.cpp index 9e2eb436cd5..0a8dd5eeeba 100644 --- a/Kernel/Syscalls/execve.cpp +++ b/Kernel/Syscalls/execve.cpp @@ -495,6 +495,42 @@ ErrorOr Process::do_exec(NonnullLockRefPtr main_progr if (has_interpreter) main_program_fd_allocation = TRY(allocate_fd()); + auto old_credentials = this->credentials(); + auto new_credentials = old_credentials; + + bool executable_is_setid = false; + + if (!(main_program_description->custody()->mount_flags() & MS_NOSUID)) { + auto main_program_metadata = main_program_description->metadata(); + + auto new_euid = old_credentials->euid(); + auto new_egid = old_credentials->egid(); + auto new_suid = old_credentials->suid(); + auto new_sgid = old_credentials->sgid(); + + if (main_program_metadata.is_setuid()) { + executable_is_setid = true; + new_euid = main_program_metadata.uid; + new_suid = main_program_metadata.uid; + } + if (main_program_metadata.is_setgid()) { + executable_is_setid = true; + new_egid = main_program_metadata.gid; + new_sgid = main_program_metadata.gid; + } + + if (executable_is_setid) { + new_credentials = TRY(Credentials::create( + old_credentials->uid(), + old_credentials->gid(), + new_euid, + new_egid, + new_suid, + new_sgid, + old_credentials->extra_gids())); + } + } + // We commit to the new executable at this point. There is no turning back! // Prevent other processes from attaching to us with ptrace while we're doing this. @@ -506,24 +542,10 @@ ErrorOr Process::do_exec(NonnullLockRefPtr main_progr kill_threads_except_self(); - bool executable_is_setid = false; - - if (!(main_program_description->custody()->mount_flags() & MS_NOSUID)) { - auto main_program_metadata = main_program_description->metadata(); - if (main_program_metadata.is_setuid()) { - executable_is_setid = true; - ProtectedDataMutationScope scope { *this }; - m_protected_values.euid = main_program_metadata.uid; - m_protected_values.suid = main_program_metadata.uid; - } - if (main_program_metadata.is_setgid()) { - executable_is_setid = true; - ProtectedDataMutationScope scope { *this }; - m_protected_values.egid = main_program_metadata.gid; - m_protected_values.sgid = main_program_metadata.gid; - } + { + ProtectedDataMutationScope scope { *this }; + m_protected_values.credentials = move(new_credentials); } - set_dumpable(!executable_is_setid); // We make sure to enter the new address space before destroying the old one. diff --git a/Kernel/Syscalls/fork.cpp b/Kernel/Syscalls/fork.cpp index 0a7fc74a8d7..772b38764b0 100644 --- a/Kernel/Syscalls/fork.cpp +++ b/Kernel/Syscalls/fork.cpp @@ -56,7 +56,7 @@ ErrorOr Process::sys$fork(RegisterState& regs) child->m_protected_values.has_promises = m_protected_values.has_promises.load(); child->m_protected_values.has_execpromises = m_protected_values.has_execpromises.load(); child->m_protected_values.sid = m_protected_values.sid; - child->m_protected_values.extra_gids = m_protected_values.extra_gids; + child->m_protected_values.credentials = m_protected_values.credentials; child->m_protected_values.umask = m_protected_values.umask; child->m_protected_values.signal_trampoline = m_protected_values.signal_trampoline; child->m_protected_values.dumpable = m_protected_values.dumpable; diff --git a/Kernel/Syscalls/getuid.cpp b/Kernel/Syscalls/getuid.cpp index b1664536614..14827020e7e 100644 --- a/Kernel/Syscalls/getuid.cpp +++ b/Kernel/Syscalls/getuid.cpp @@ -36,35 +36,50 @@ ErrorOr Process::sys$getegid() return egid().value(); } -ErrorOr Process::sys$getresuid(Userspace ruid, Userspace euid, Userspace suid) +ErrorOr Process::sys$getresuid(Userspace user_ruid, Userspace user_euid, Userspace user_suid) { VERIFY_PROCESS_BIG_LOCK_ACQUIRED(this); TRY(require_promise(Pledge::stdio)); - TRY(copy_to_user(ruid, &m_protected_values.uid)); - TRY(copy_to_user(euid, &m_protected_values.euid)); - TRY(copy_to_user(suid, &m_protected_values.suid)); + + auto credentials = this->credentials(); + auto uid = credentials->uid(); + auto euid = credentials->euid(); + auto suid = credentials->suid(); + + TRY(copy_to_user(user_ruid, &uid)); + TRY(copy_to_user(user_euid, &euid)); + TRY(copy_to_user(user_suid, &suid)); return 0; } -ErrorOr Process::sys$getresgid(Userspace rgid, Userspace egid, Userspace sgid) +ErrorOr Process::sys$getresgid(Userspace user_rgid, Userspace user_egid, Userspace user_sgid) { VERIFY_PROCESS_BIG_LOCK_ACQUIRED(this); TRY(require_promise(Pledge::stdio)); - TRY(copy_to_user(rgid, &m_protected_values.gid)); - TRY(copy_to_user(egid, &m_protected_values.egid)); - TRY(copy_to_user(sgid, &m_protected_values.sgid)); + + auto credentials = this->credentials(); + auto gid = credentials->gid(); + auto egid = credentials->egid(); + auto sgid = credentials->sgid(); + + TRY(copy_to_user(user_rgid, &gid)); + TRY(copy_to_user(user_egid, &egid)); + TRY(copy_to_user(user_sgid, &sgid)); return 0; } -ErrorOr Process::sys$getgroups(size_t count, Userspace user_gids) +ErrorOr Process::sys$getgroups(size_t count, Userspace user_gids) { VERIFY_PROCESS_BIG_LOCK_ACQUIRED(this); TRY(require_promise(Pledge::stdio)); + + auto credentials = this->credentials(); + if (!count) - return extra_gids().size(); - if (count != extra_gids().size()) + return credentials->extra_gids().size(); + if (count != credentials->extra_gids().size()) return EINVAL; - TRY(copy_to_user(user_gids, extra_gids().data(), sizeof(gid_t) * count)); + TRY(copy_to_user(user_gids, credentials->extra_gids().data(), sizeof(GroupID) * count)); return 0; } diff --git a/Kernel/Syscalls/setuid.cpp b/Kernel/Syscalls/setuid.cpp index 1e726f499e0..758e09f4e68 100644 --- a/Kernel/Syscalls/setuid.cpp +++ b/Kernel/Syscalls/setuid.cpp @@ -16,15 +16,26 @@ ErrorOr Process::sys$seteuid(UserID new_euid) if (new_euid == (uid_t)-1) return EINVAL; - if (new_euid != uid() && new_euid != suid() && !is_superuser()) + auto credentials = this->credentials(); + + if (new_euid != credentials->uid() && new_euid != credentials->suid() && !credentials->is_superuser()) return EPERM; - if (euid() != new_euid) - set_dumpable(false); + auto new_credentials = TRY(Credentials::create( + credentials->uid(), + credentials->gid(), + new_euid, + credentials->egid(), + credentials->suid(), + credentials->sgid(), + credentials->extra_gids())); ProtectedDataMutationScope scope { *this }; - m_protected_values.euid = new_euid; + if (credentials->euid() != new_euid) + set_dumpable(false); + + m_protected_values.credentials = move(new_credentials); return 0; } @@ -36,14 +47,26 @@ ErrorOr Process::sys$setegid(GroupID new_egid) if (new_egid == (uid_t)-1) return EINVAL; - if (new_egid != gid() && new_egid != sgid() && !is_superuser()) + auto credentials = this->credentials(); + + if (new_egid != credentials->gid() && new_egid != credentials->sgid() && !credentials->is_superuser()) return EPERM; - if (egid() != new_egid) - set_dumpable(false); + auto new_credentials = TRY(Credentials::create( + credentials->uid(), + credentials->gid(), + credentials->euid(), + new_egid, + credentials->suid(), + credentials->sgid(), + credentials->extra_gids())); ProtectedDataMutationScope scope { *this }; - m_protected_values.egid = new_egid; + + if (credentials->egid() != new_egid) + set_dumpable(false); + + m_protected_values.credentials = move(new_credentials); return 0; } @@ -55,16 +78,26 @@ ErrorOr Process::sys$setuid(UserID new_uid) if (new_uid == (uid_t)-1) return EINVAL; - if (new_uid != uid() && new_uid != euid() && !is_superuser()) + auto credentials = this->credentials(); + + if (new_uid != credentials->uid() && new_uid != credentials->euid() && !credentials->is_superuser()) return EPERM; - if (euid() != new_uid) - set_dumpable(false); + auto new_credentials = TRY(Credentials::create( + new_uid, + credentials->gid(), + new_uid, + credentials->egid(), + new_uid, + credentials->sgid(), + credentials->extra_gids())); ProtectedDataMutationScope scope { *this }; - m_protected_values.uid = new_uid; - m_protected_values.euid = new_uid; - m_protected_values.suid = new_uid; + + if (credentials->euid() != new_uid) + set_dumpable(false); + + m_protected_values.credentials = move(new_credentials); return 0; } @@ -76,16 +109,26 @@ ErrorOr Process::sys$setgid(GroupID new_gid) if (new_gid == (uid_t)-1) return EINVAL; - if (new_gid != gid() && new_gid != egid() && !is_superuser()) + auto credentials = this->credentials(); + + if (new_gid != credentials->gid() && new_gid != credentials->egid() && !credentials->is_superuser()) return EPERM; - if (egid() != new_gid) - set_dumpable(false); + auto new_credentials = TRY(Credentials::create( + credentials->uid(), + new_gid, + credentials->euid(), + new_gid, + credentials->suid(), + new_gid, + credentials->extra_gids())); ProtectedDataMutationScope scope { *this }; - m_protected_values.gid = new_gid; - m_protected_values.egid = new_gid; - m_protected_values.sgid = new_gid; + + if (credentials->egid() != new_gid) + set_dumpable(false); + + m_protected_values.credentials = move(new_credentials); return 0; } @@ -94,24 +137,35 @@ ErrorOr Process::sys$setreuid(UserID new_ruid, UserID new_euid) VERIFY_PROCESS_BIG_LOCK_ACQUIRED(this); TRY(require_promise(Pledge::id)); - if (new_ruid == (uid_t)-1) - new_ruid = uid(); - if (new_euid == (uid_t)-1) - new_euid = euid(); + auto credentials = this->credentials(); - auto ok = [this](UserID id) { return id == uid() || id == euid() || id == suid(); }; + if (new_ruid == (uid_t)-1) + new_ruid = credentials->uid(); + if (new_euid == (uid_t)-1) + new_euid = credentials->euid(); + + auto ok = [&credentials](UserID id) { return id == credentials->uid() || id == credentials->euid() || id == credentials->suid(); }; if (!ok(new_ruid) || !ok(new_euid)) return EPERM; if (new_ruid < (uid_t)-1 || new_euid < (uid_t)-1) return EINVAL; - if (euid() != new_euid) - set_dumpable(false); + auto new_credentials = TRY(Credentials::create( + new_ruid, + credentials->gid(), + new_euid, + credentials->egid(), + credentials->suid(), + credentials->sgid(), + credentials->extra_gids())); ProtectedDataMutationScope scope { *this }; - m_protected_values.uid = new_ruid; - m_protected_values.euid = new_euid; + + if (credentials->euid() != new_euid) + set_dumpable(false); + + m_protected_values.credentials = move(new_credentials); return 0; } @@ -120,24 +174,34 @@ ErrorOr Process::sys$setresuid(UserID new_ruid, UserID new_euid, UserID VERIFY_PROCESS_BIG_LOCK_ACQUIRED(this); TRY(require_promise(Pledge::id)); - if (new_ruid == (uid_t)-1) - new_ruid = uid(); - if (new_euid == (uid_t)-1) - new_euid = euid(); - if (new_suid == (uid_t)-1) - new_suid = suid(); + auto credentials = this->credentials(); - auto ok = [this](UserID id) { return id == uid() || id == euid() || id == suid(); }; - if ((!ok(new_ruid) || !ok(new_euid) || !ok(new_suid)) && !is_superuser()) + if (new_ruid == (uid_t)-1) + new_ruid = credentials->uid(); + if (new_euid == (uid_t)-1) + new_euid = credentials->euid(); + if (new_suid == (uid_t)-1) + new_suid = credentials->suid(); + + auto ok = [&credentials](UserID id) { return id == credentials->uid() || id == credentials->euid() || id == credentials->suid(); }; + if ((!ok(new_ruid) || !ok(new_euid) || !ok(new_suid)) && !credentials->is_superuser()) return EPERM; - if (euid() != new_euid) - set_dumpable(false); + auto new_credentials = TRY(Credentials::create( + new_ruid, + credentials->gid(), + new_euid, + credentials->egid(), + new_suid, + credentials->sgid(), + credentials->extra_gids())); ProtectedDataMutationScope scope { *this }; - m_protected_values.uid = new_ruid; - m_protected_values.euid = new_euid; - m_protected_values.suid = new_suid; + + if (credentials->euid() != new_euid) + set_dumpable(false); + + m_protected_values.credentials = move(new_credentials); return 0; } @@ -146,58 +210,84 @@ ErrorOr Process::sys$setresgid(GroupID new_rgid, GroupID new_egid, Grou VERIFY_PROCESS_BIG_LOCK_ACQUIRED(this); TRY(require_promise(Pledge::id)); - if (new_rgid == (gid_t)-1) - new_rgid = gid(); - if (new_egid == (gid_t)-1) - new_egid = egid(); - if (new_sgid == (gid_t)-1) - new_sgid = sgid(); + auto credentials = this->credentials(); - auto ok = [this](GroupID id) { return id == gid() || id == egid() || id == sgid(); }; - if ((!ok(new_rgid) || !ok(new_egid) || !ok(new_sgid)) && !is_superuser()) + if (new_rgid == (gid_t)-1) + new_rgid = credentials->gid(); + if (new_egid == (gid_t)-1) + new_egid = credentials->egid(); + if (new_sgid == (gid_t)-1) + new_sgid = credentials->sgid(); + + auto ok = [&credentials](GroupID id) { return id == credentials->gid() || id == credentials->egid() || id == credentials->sgid(); }; + if ((!ok(new_rgid) || !ok(new_egid) || !ok(new_sgid)) && !credentials->is_superuser()) return EPERM; - if (egid() != new_egid) - set_dumpable(false); + auto new_credentials = TRY(Credentials::create( + credentials->uid(), + new_rgid, + credentials->euid(), + new_egid, + credentials->suid(), + new_sgid, + credentials->extra_gids())); ProtectedDataMutationScope scope { *this }; - m_protected_values.gid = new_rgid; - m_protected_values.egid = new_egid; - m_protected_values.sgid = new_sgid; + + if (credentials->egid() != new_egid) + set_dumpable(false); + + m_protected_values.credentials = move(new_credentials); return 0; } -ErrorOr Process::sys$setgroups(size_t count, Userspace user_gids) +ErrorOr Process::sys$setgroups(size_t count, Userspace user_gids) { VERIFY_PROCESS_BIG_LOCK_ACQUIRED(this); TRY(require_promise(Pledge::id)); - if (!is_superuser()) + + auto credentials = this->credentials(); + + if (!credentials->is_superuser()) return EPERM; if (!count) { ProtectedDataMutationScope scope { *this }; - m_protected_values.extra_gids.clear(); + m_protected_values.credentials = TRY(Credentials::create( + credentials->uid(), + credentials->gid(), + credentials->euid(), + credentials->egid(), + credentials->suid(), + credentials->sgid(), + {})); return 0; } - Vector new_extra_gids; + Vector new_extra_gids; TRY(new_extra_gids.try_resize(count)); TRY(copy_n_from_user(new_extra_gids.data(), user_gids, count)); - HashTable unique_extra_gids; + HashTable unique_extra_gids; for (auto& extra_gid : new_extra_gids) { if (extra_gid != gid()) TRY(unique_extra_gids.try_set(extra_gid)); } - ProtectedDataMutationScope scope { *this }; - TRY(m_protected_values.extra_gids.try_resize(unique_extra_gids.size())); - size_t i = 0; - for (auto& extra_gid : unique_extra_gids) { - if (extra_gid == gid()) - continue; - m_protected_values.extra_gids[i++] = extra_gid; + new_extra_gids.clear_with_capacity(); + for (auto extra_gid : unique_extra_gids) { + TRY(new_extra_gids.try_append(extra_gid)); } + + ProtectedDataMutationScope scope { *this }; + m_protected_values.credentials = TRY(Credentials::create( + credentials->uid(), + credentials->gid(), + credentials->euid(), + credentials->egid(), + credentials->suid(), + credentials->sgid(), + new_extra_gids.span())); return 0; }