From 5e062414c11df31ed595c363990005eef00fa263 Mon Sep 17 00:00:00 2001 From: Liav A Date: Wed, 2 Nov 2022 22:26:02 +0200 Subject: [PATCH] Kernel: Add support for jails Our implementation for Jails resembles much of how FreeBSD jails are working - it's essentially only a matter of using a RefPtr in the Process class to a Jail object. Then, when we iterate over all processes in various cases, we could ensure if either the current process is in jail and therefore should be restricted what is visible in terms of PID isolation, and also to be able to expose metadata about Jails in /sys/kernel/jails node (which does not reveal anything to a process which is in jail). A lifetime model for the Jail object is currently plain simple - there's simpy no way to manually delete a Jail object once it was created. Such feature should be carefully designed to allow safe destruction of a Jail without the possibility of releasing a process which is in Jail from the actual jail. Each process which is attached into a Jail cannot leave it until the end of a Process (i.e. when finalizing a Process). All jails are kept being referenced in the JailManagement. When a last attached process is finalized, the Jail is automatically destroyed. --- Kernel/API/Syscall.h | 11 ++ Kernel/Arch/aarch64/init.cpp | 1 + Kernel/Arch/x86/init.cpp | 2 + Kernel/CMakeLists.txt | 4 + Kernel/FileSystem/ProcFS.cpp | 18 +-- .../SysFS/Subsystems/Kernel/Directory.cpp | 2 + .../SysFS/Subsystems/Kernel/Jails.cpp | 38 +++++ .../SysFS/Subsystems/Kernel/Jails.h | 28 ++++ .../SysFS/Subsystems/Kernel/Processes.cpp | 6 +- .../Kernel/Variables/BooleanVariable.cpp | 27 ++-- .../Kernel/Variables/CapsLockRemap.cpp | 4 +- .../Kernel/Variables/CapsLockRemap.h | 3 +- .../Kernel/Variables/DumpKmallocStack.cpp | 4 +- .../Kernel/Variables/DumpKmallocStack.h | 3 +- Kernel/Forward.h | 1 + Kernel/Jail.cpp | 34 +++++ Kernel/Jail.h | 48 +++++++ Kernel/JailManagement.cpp | 76 ++++++++++ Kernel/JailManagement.h | 42 ++++++ Kernel/Memory/MemoryManager.cpp | 2 +- Kernel/Process.cpp | 130 +++++++++++++++++- Kernel/Process.h | 109 ++++----------- Kernel/ProcessExposed.cpp | 16 +-- Kernel/ProcessSpecificExposed.cpp | 14 +- Kernel/Syscalls/disown.cpp | 2 +- Kernel/Syscalls/execve.cpp | 4 + Kernel/Syscalls/fork.cpp | 20 +++ Kernel/Syscalls/jail.cpp | 59 ++++++++ Kernel/Syscalls/kill.cpp | 12 +- Kernel/Syscalls/profiling.cpp | 12 +- Kernel/Syscalls/sched.cpp | 2 +- Kernel/Syscalls/setpgid.cpp | 18 +-- Kernel/Syscalls/waitid.cpp | 2 +- Kernel/TTY/TTY.cpp | 9 +- Kernel/Thread.cpp | 6 +- 35 files changed, 609 insertions(+), 160 deletions(-) create mode 100644 Kernel/FileSystem/SysFS/Subsystems/Kernel/Jails.cpp create mode 100644 Kernel/FileSystem/SysFS/Subsystems/Kernel/Jails.h create mode 100644 Kernel/Jail.cpp create mode 100644 Kernel/Jail.h create mode 100644 Kernel/JailManagement.cpp create mode 100644 Kernel/JailManagement.h create mode 100644 Kernel/Syscalls/jail.cpp diff --git a/Kernel/API/Syscall.h b/Kernel/API/Syscall.h index bb04e3da3c..4e40fdce16 100644 --- a/Kernel/API/Syscall.h +++ b/Kernel/API/Syscall.h @@ -107,6 +107,8 @@ enum class NeedsBigProcessLock { S(inode_watcher_remove_watch, NeedsBigProcessLock::Yes) \ S(ioctl, NeedsBigProcessLock::Yes) \ S(join_thread, NeedsBigProcessLock::Yes) \ + S(jail_create, NeedsBigProcessLock::No) \ + S(jail_attach, NeedsBigProcessLock::No) \ S(kill, NeedsBigProcessLock::Yes) \ S(kill_thread, NeedsBigProcessLock::Yes) \ S(killpg, NeedsBigProcessLock::Yes) \ @@ -329,6 +331,15 @@ struct SC_setkeymap_params { StringArgument map_name; }; +struct SC_jail_create_params { + u64 index; + StringArgument name; +}; + +struct SC_jail_attach_params { + u64 index; +}; + struct SC_getkeymap_params { u32* map; u32* shift_map; diff --git a/Kernel/Arch/aarch64/init.cpp b/Kernel/Arch/aarch64/init.cpp index d8e039f3d4..7c1365393f 100644 --- a/Kernel/Arch/aarch64/init.cpp +++ b/Kernel/Arch/aarch64/init.cpp @@ -129,6 +129,7 @@ extern "C" [[noreturn]] void init() dmesgln("Initialize MMU"); Memory::MemoryManager::initialize(0); DeviceManagement::initialize(); + JailManagement::the(); // Invoke all static global constructors in the kernel. // Note that we want to do this as early as possible. diff --git a/Kernel/Arch/x86/init.cpp b/Kernel/Arch/x86/init.cpp index 9412a5a444..74d8036ab3 100644 --- a/Kernel/Arch/x86/init.cpp +++ b/Kernel/Arch/x86/init.cpp @@ -39,6 +39,7 @@ #include #include #include +#include #include #include #include @@ -237,6 +238,7 @@ extern "C" [[noreturn]] UNMAP_AFTER_INIT void init(BootInfo const& boot_info) __stack_chk_guard = get_fast_random(); ProcFSComponentRegistry::initialize(); + JailManagement::the(); Process::initialize(); Scheduler::initialize(); diff --git a/Kernel/CMakeLists.txt b/Kernel/CMakeLists.txt index 5b24d5ef26..78c53c541d 100644 --- a/Kernel/CMakeLists.txt +++ b/Kernel/CMakeLists.txt @@ -84,6 +84,8 @@ set(KERNEL_SOURCES Graphics/VirtIOGPU/GPU3DDevice.cpp Graphics/VirtIOGPU/GraphicsAdapter.cpp IOWindow.cpp + Jail.cpp + JailManagement.cpp SanCov.cpp Storage/ATA/AHCI/Controller.cpp Storage/ATA/AHCI/Port.cpp @@ -153,6 +155,7 @@ set(KERNEL_SOURCES FileSystem/SysFS/Subsystems/Kernel/Interrupts.cpp FileSystem/SysFS/Subsystems/Kernel/Processes.cpp FileSystem/SysFS/Subsystems/Kernel/CPUInfo.cpp + FileSystem/SysFS/Subsystems/Kernel/Jails.cpp FileSystem/SysFS/Subsystems/Kernel/Keymap.cpp FileSystem/SysFS/Subsystems/Kernel/Profile.cpp FileSystem/SysFS/Subsystems/Kernel/Directory.cpp @@ -262,6 +265,7 @@ set(KERNEL_SOURCES Syscalls/getuid.cpp Syscalls/hostname.cpp Syscalls/ioctl.cpp + Syscalls/jail.cpp Syscalls/keymap.cpp Syscalls/kill.cpp Syscalls/link.cpp diff --git a/Kernel/FileSystem/ProcFS.cpp b/Kernel/FileSystem/ProcFS.cpp index 214e7d00b5..6eb4ad3771 100644 --- a/Kernel/FileSystem/ProcFS.cpp +++ b/Kernel/FileSystem/ProcFS.cpp @@ -256,7 +256,7 @@ ErrorOr ProcFSProcessDirectoryInode::attach(OpenFileDescription&) InodeMetadata ProcFSProcessDirectoryInode::metadata() const { MutexLocker locker(m_inode_lock); - auto process = Process::from_pid(associated_pid()); + auto process = Process::from_pid_in_same_jail(associated_pid()); if (!process) return {}; @@ -279,7 +279,7 @@ ErrorOr ProcFSProcessDirectoryInode::read_bytes_locked(off_t, size_t, Us ErrorOr ProcFSProcessDirectoryInode::traverse_as_directory(Function(FileSystem::DirectoryEntryView const&)> callback) const { MutexLocker locker(procfs().m_lock); - auto process = Process::from_pid(associated_pid()); + auto process = Process::from_pid_in_same_jail(associated_pid()); if (!process) return EINVAL; return process->procfs_traits()->traverse_as_directory(procfs().fsid(), move(callback)); @@ -288,7 +288,7 @@ ErrorOr ProcFSProcessDirectoryInode::traverse_as_directory(Function> ProcFSProcessDirectoryInode::lookup(StringView name) { MutexLocker locker(procfs().m_lock); - auto process = Process::from_pid(associated_pid()); + auto process = Process::from_pid_in_same_jail(associated_pid()); if (!process) return ESRCH; if (name == "fd"sv) @@ -345,7 +345,7 @@ void ProcFSProcessSubDirectoryInode::did_seek(OpenFileDescription&, off_t) InodeMetadata ProcFSProcessSubDirectoryInode::metadata() const { MutexLocker locker(m_inode_lock); - auto process = Process::from_pid(associated_pid()); + auto process = Process::from_pid_in_same_jail(associated_pid()); if (!process) return {}; @@ -363,7 +363,7 @@ InodeMetadata ProcFSProcessSubDirectoryInode::metadata() const ErrorOr ProcFSProcessSubDirectoryInode::traverse_as_directory(Function(FileSystem::DirectoryEntryView const&)> callback) const { MutexLocker locker(procfs().m_lock); - auto process = Process::from_pid(associated_pid()); + auto process = Process::from_pid_in_same_jail(associated_pid()); if (!process) return EINVAL; switch (m_sub_directory_type) { @@ -382,7 +382,7 @@ ErrorOr ProcFSProcessSubDirectoryInode::traverse_as_directory(Function> ProcFSProcessSubDirectoryInode::lookup(StringView name) { MutexLocker locker(procfs().m_lock); - auto process = Process::from_pid(associated_pid()); + auto process = Process::from_pid_in_same_jail(associated_pid()); if (!process) return ESRCH; switch (m_sub_directory_type) { @@ -472,7 +472,7 @@ static mode_t determine_procfs_process_inode_mode(SegmentedProcFSIndex::ProcessS InodeMetadata ProcFSProcessPropertyInode::metadata() const { MutexLocker locker(m_inode_lock); - auto process = Process::from_pid(associated_pid()); + auto process = Process::from_pid_in_same_jail(associated_pid()); if (!process) return {}; @@ -499,7 +499,7 @@ ErrorOr ProcFSProcessPropertyInode::read_bytes_locked(off_t offset, size if (!description) { auto builder = TRY(KBufferBuilder::try_create()); - auto process = Process::from_pid(associated_pid()); + auto process = Process::from_pid_in_same_jail(associated_pid()); if (!process) return Error::from_errno(ESRCH); TRY(try_to_acquire_data(*process, builder)); @@ -585,7 +585,7 @@ ErrorOr ProcFSProcessPropertyInode::refresh_data(OpenFileDescription& desc // For process-specific inodes, hold the process's ptrace lock across refresh // and refuse to load data if the process is not dumpable. // Without this, files opened before a process went non-dumpable could still be used for dumping. - auto process = Process::from_pid(associated_pid()); + auto process = Process::from_pid_in_same_jail(associated_pid()); if (!process) return Error::from_errno(ESRCH); process->ptrace_lock().lock(); diff --git a/Kernel/FileSystem/SysFS/Subsystems/Kernel/Directory.cpp b/Kernel/FileSystem/SysFS/Subsystems/Kernel/Directory.cpp index 18980243b0..469f7d3fb5 100644 --- a/Kernel/FileSystem/SysFS/Subsystems/Kernel/Directory.cpp +++ b/Kernel/FileSystem/SysFS/Subsystems/Kernel/Directory.cpp @@ -13,6 +13,7 @@ #include #include #include +#include #include #include #include @@ -46,6 +47,7 @@ UNMAP_AFTER_INIT NonnullLockRefPtr SysFSGlobalK list.append(SysFSProfile::must_create(*global_kernel_stats_directory)); list.append(SysFSKernelLoadBase::must_create(*global_kernel_stats_directory)); list.append(SysFSPowerStateSwitchNode::must_create(*global_kernel_stats_directory)); + list.append(SysFSJails::must_create(*global_kernel_stats_directory)); list.append(SysFSGlobalNetworkStatsDirectory::must_create(*global_kernel_stats_directory)); list.append(SysFSGlobalKernelVariablesDirectory::must_create(*global_kernel_stats_directory)); diff --git a/Kernel/FileSystem/SysFS/Subsystems/Kernel/Jails.cpp b/Kernel/FileSystem/SysFS/Subsystems/Kernel/Jails.cpp new file mode 100644 index 0000000000..dbe37ce092 --- /dev/null +++ b/Kernel/FileSystem/SysFS/Subsystems/Kernel/Jails.cpp @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2022, Liav A. + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include +#include +#include +#include + +namespace Kernel { + +UNMAP_AFTER_INIT SysFSJails::SysFSJails(SysFSDirectory const& parent_directory) + : SysFSGlobalInformation(parent_directory) +{ +} + +UNMAP_AFTER_INIT NonnullLockRefPtr SysFSJails::must_create(SysFSDirectory const& parent_directory) +{ + return adopt_lock_ref_if_nonnull(new (nothrow) SysFSJails(parent_directory)).release_nonnull(); +} + +ErrorOr SysFSJails::try_generate(KBufferBuilder& builder) +{ + auto array = TRY(JsonArraySerializer<>::try_create(builder)); + TRY(JailManagement::the().for_each_in_same_jail([&array](Jail& jail) -> ErrorOr { + auto obj = TRY(array.add_object()); + TRY(obj.add("index"sv, jail.index().value())); + TRY(obj.add("name"sv, jail.name())); + TRY(obj.finish()); + return {}; + })); + TRY(array.finish()); + return {}; +} + +} diff --git a/Kernel/FileSystem/SysFS/Subsystems/Kernel/Jails.h b/Kernel/FileSystem/SysFS/Subsystems/Kernel/Jails.h new file mode 100644 index 0000000000..2dfbf73eaa --- /dev/null +++ b/Kernel/FileSystem/SysFS/Subsystems/Kernel/Jails.h @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2022, Liav A. + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#pragma once + +#include +#include +#include +#include +#include + +namespace Kernel { + +class SysFSJails final : public SysFSGlobalInformation { +public: + virtual StringView name() const override { return "jails"sv; } + + static NonnullLockRefPtr must_create(SysFSDirectory const& parent_directory); + +private: + explicit SysFSJails(SysFSDirectory const& parent_directory); + virtual ErrorOr try_generate(KBufferBuilder& builder) override; +}; + +} diff --git a/Kernel/FileSystem/SysFS/Subsystems/Kernel/Processes.cpp b/Kernel/FileSystem/SysFS/Subsystems/Kernel/Processes.cpp index d9ba50c8fb..50ddbf3b18 100644 --- a/Kernel/FileSystem/SysFS/Subsystems/Kernel/Processes.cpp +++ b/Kernel/FileSystem/SysFS/Subsystems/Kernel/Processes.cpp @@ -141,10 +141,10 @@ ErrorOr SysFSOverallProcesses::try_generate(KBufferBuilder& builder) { auto array = TRY(json.add_array("processes"sv)); + // FIXME: Do we actually want to expose the colonel process in a Jail environment? TRY(build_process(array, *Scheduler::colonel())); - TRY(Process::all_instances().with([&](auto& processes) -> ErrorOr { - for (auto& process : processes) - TRY(build_process(array, process)); + TRY(Process::for_each_in_same_jail([&](Process& process) -> ErrorOr { + TRY(build_process(array, process)); return {}; })); TRY(array.finish()); diff --git a/Kernel/FileSystem/SysFS/Subsystems/Kernel/Variables/BooleanVariable.cpp b/Kernel/FileSystem/SysFS/Subsystems/Kernel/Variables/BooleanVariable.cpp index e1a1b43486..456f07480d 100644 --- a/Kernel/FileSystem/SysFS/Subsystems/Kernel/Variables/BooleanVariable.cpp +++ b/Kernel/FileSystem/SysFS/Subsystems/Kernel/Variables/BooleanVariable.cpp @@ -5,6 +5,7 @@ */ #include +#include #include namespace Kernel { @@ -16,18 +17,26 @@ ErrorOr SysFSSystemBoolean::try_generate(KBufferBuilder& builder) ErrorOr SysFSSystemBoolean::write_bytes(off_t, size_t count, UserOrKernelBuffer const& buffer, OpenFileDescription*) { - if (count != 1) - return EINVAL; MutexLocker locker(m_refresh_lock); + // Note: We do all of this code before taking the spinlock because then we disable + // interrupts so page faults will not work. char value = 0; TRY(buffer.read(&value, 1)); - if (value == '0') - set_value(false); - else if (value == '1') - set_value(true); - else - return EINVAL; - return 1; + + return Process::current().jail().with([&](auto& my_jail) -> ErrorOr { + // Note: If we are in a jail, don't let the current process to change the variable. + if (my_jail) + return Error::from_errno(EPERM); + if (count != 1) + return Error::from_errno(EINVAL); + if (value == '0') + set_value(false); + else if (value == '1') + set_value(true); + else + return Error::from_errno(EINVAL); + return 1; + }); } ErrorOr SysFSSystemBoolean::truncate(u64 size) diff --git a/Kernel/FileSystem/SysFS/Subsystems/Kernel/Variables/CapsLockRemap.cpp b/Kernel/FileSystem/SysFS/Subsystems/Kernel/Variables/CapsLockRemap.cpp index eec99b37a1..1c74621224 100644 --- a/Kernel/FileSystem/SysFS/Subsystems/Kernel/Variables/CapsLockRemap.cpp +++ b/Kernel/FileSystem/SysFS/Subsystems/Kernel/Variables/CapsLockRemap.cpp @@ -22,12 +22,12 @@ UNMAP_AFTER_INIT NonnullLockRefPtr SysFSCapsLockRemap::must_ bool SysFSCapsLockRemap::value() const { - MutexLocker locker(m_lock); + SpinlockLocker locker(m_lock); return g_caps_lock_remapped_to_ctrl.load(); } void SysFSCapsLockRemap::set_value(bool new_value) { - MutexLocker locker(m_lock); + SpinlockLocker locker(m_lock); g_caps_lock_remapped_to_ctrl.exchange(new_value); } diff --git a/Kernel/FileSystem/SysFS/Subsystems/Kernel/Variables/CapsLockRemap.h b/Kernel/FileSystem/SysFS/Subsystems/Kernel/Variables/CapsLockRemap.h index 3cb0390bd0..effbcd6e49 100644 --- a/Kernel/FileSystem/SysFS/Subsystems/Kernel/Variables/CapsLockRemap.h +++ b/Kernel/FileSystem/SysFS/Subsystems/Kernel/Variables/CapsLockRemap.h @@ -9,6 +9,7 @@ #include #include #include +#include #include namespace Kernel { @@ -24,7 +25,7 @@ private: explicit SysFSCapsLockRemap(SysFSDirectory const&); - mutable Mutex m_lock; + mutable Spinlock m_lock { LockRank::None }; }; } diff --git a/Kernel/FileSystem/SysFS/Subsystems/Kernel/Variables/DumpKmallocStack.cpp b/Kernel/FileSystem/SysFS/Subsystems/Kernel/Variables/DumpKmallocStack.cpp index f1645a1c8e..5464b6ac77 100644 --- a/Kernel/FileSystem/SysFS/Subsystems/Kernel/Variables/DumpKmallocStack.cpp +++ b/Kernel/FileSystem/SysFS/Subsystems/Kernel/Variables/DumpKmallocStack.cpp @@ -22,13 +22,13 @@ UNMAP_AFTER_INIT NonnullLockRefPtr SysFSDumpKmallocStack bool SysFSDumpKmallocStacks::value() const { - MutexLocker locker(m_lock); + SpinlockLocker locker(m_lock); return g_dump_kmalloc_stacks; } void SysFSDumpKmallocStacks::set_value(bool new_value) { - MutexLocker locker(m_lock); + SpinlockLocker locker(m_lock); g_dump_kmalloc_stacks = new_value; } diff --git a/Kernel/FileSystem/SysFS/Subsystems/Kernel/Variables/DumpKmallocStack.h b/Kernel/FileSystem/SysFS/Subsystems/Kernel/Variables/DumpKmallocStack.h index 21719e22f4..7e29ac3385 100644 --- a/Kernel/FileSystem/SysFS/Subsystems/Kernel/Variables/DumpKmallocStack.h +++ b/Kernel/FileSystem/SysFS/Subsystems/Kernel/Variables/DumpKmallocStack.h @@ -9,6 +9,7 @@ #include #include #include +#include #include namespace Kernel { @@ -24,7 +25,7 @@ private: explicit SysFSDumpKmallocStacks(SysFSDirectory const&); - mutable Mutex m_lock; + mutable Spinlock m_lock { LockRank::None }; }; } diff --git a/Kernel/Forward.h b/Kernel/Forward.h index f629292028..ba2c62bb68 100644 --- a/Kernel/Forward.h +++ b/Kernel/Forward.h @@ -28,6 +28,7 @@ class IPv4Socket; class Inode; class InodeIdentifier; class InodeWatcher; +class Jail; class KBuffer; class KString; class LocalSocket; diff --git a/Kernel/Jail.cpp b/Kernel/Jail.cpp new file mode 100644 index 0000000000..faeed507f1 --- /dev/null +++ b/Kernel/Jail.cpp @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2022, Liav A. + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include + +namespace Kernel { + +ErrorOr> Jail::create(Badge, NonnullOwnPtr name, JailIndex index) +{ + return adopt_nonnull_lock_ref_or_enomem(new (nothrow) Jail(move(name), index)); +} + +Jail::Jail(NonnullOwnPtr name, JailIndex index) + : m_name(move(name)) + , m_index(index) +{ +} + +void Jail::detach(Badge) +{ + VERIFY(ref_count() > 0); + m_attach_count.with([&](auto& my_attach_count) { + VERIFY(my_attach_count > 0); + my_attach_count--; + if (my_attach_count == 0) { + m_jail_list_node.remove(); + } + }); +} + +} diff --git a/Kernel/Jail.h b/Kernel/Jail.h new file mode 100644 index 0000000000..ea66839ebd --- /dev/null +++ b/Kernel/Jail.h @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2022, Liav A. + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace Kernel { + +class JailManagement; + +AK_TYPEDEF_DISTINCT_ORDERED_ID(u64, JailIndex); + +class Jail : public RefCounted { + friend class JailManagement; + +public: + static ErrorOr> create(Badge, NonnullOwnPtr, JailIndex); + + StringView name() const { return m_name->view(); } + JailIndex index() const { return m_index; } + + void detach(Badge); + SpinlockProtected& attach_count() { return m_attach_count; } + +private: + Jail(NonnullOwnPtr, JailIndex); + + NonnullOwnPtr m_name; + JailIndex const m_index; + + IntrusiveListNode> m_jail_list_node; + SpinlockProtected m_attach_count { LockRank::None, 0 }; +}; + +} diff --git a/Kernel/JailManagement.cpp b/Kernel/JailManagement.cpp new file mode 100644 index 0000000000..3735c92f73 --- /dev/null +++ b/Kernel/JailManagement.cpp @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2022, Liav A. + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include +#include +#include +#include + +namespace Kernel { + +static Singleton s_the; +static Atomic s_jail_id; + +UNMAP_AFTER_INIT JailManagement::JailManagement() = default; + +JailIndex JailManagement::generate_jail_id() +{ + return s_jail_id.fetch_add(1); +} + +JailManagement& JailManagement::the() +{ + return *s_the; +} + +LockRefPtr JailManagement::find_jail_by_index(JailIndex index) +{ + return m_jails.with([&](auto& list) -> LockRefPtr { + for (auto& jail : list) { + if (jail.index() == index) + return jail; + } + return {}; + }); +} + +ErrorOr JailManagement::for_each_in_same_jail(Function(Jail&)> callback) +{ + return Process::current().jail().with([&](auto& my_jail) -> ErrorOr { + // Note: If we are in a jail, don't reveal anything about the outside world, + // not even the fact that we are in which jail... + if (my_jail) + return {}; + return m_jails.with([&](auto& list) -> ErrorOr { + for (auto& jail : list) { + TRY(callback(jail)); + } + return {}; + }); + }); +} + +LockRefPtr JailManagement::find_first_jail_by_name(StringView name) +{ + return m_jails.with([&](auto& list) -> LockRefPtr { + for (auto& jail : list) { + if (jail.name() == name) + return jail; + } + return {}; + }); +} + +ErrorOr> JailManagement::create_jail(NonnullOwnPtr name) +{ + return m_jails.with([&](auto& list) -> ErrorOr> { + auto jail = TRY(Jail::create({}, move(name), generate_jail_id())); + list.append(jail); + return jail; + }); +} + +} diff --git a/Kernel/JailManagement.h b/Kernel/JailManagement.h new file mode 100644 index 0000000000..9f363bed66 --- /dev/null +++ b/Kernel/JailManagement.h @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2022, Liav A. + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace Kernel { + +class JailManagement { + +public: + JailManagement(); + static JailManagement& the(); + + LockRefPtr find_jail_by_index(JailIndex); + LockRefPtr find_first_jail_by_name(StringView); + + ErrorOr> create_jail(NonnullOwnPtr name); + + ErrorOr for_each_in_same_jail(Function(Jail&)>); + +private: + JailIndex generate_jail_id(); + + SpinlockProtected> m_jails { LockRank::None }; +}; + +} diff --git a/Kernel/Memory/MemoryManager.cpp b/Kernel/Memory/MemoryManager.cpp index 945ba0c67c..3fb5d53769 100644 --- a/Kernel/Memory/MemoryManager.cpp +++ b/Kernel/Memory/MemoryManager.cpp @@ -847,7 +847,7 @@ ErrorOr MemoryManager::commit_physical_pages(size_t pa return CommittedPhysicalPageSet { {}, page_count }; }); if (result.is_error()) { - Process::for_each([&](Process const& process) { + Process::for_each_ignoring_jails([&](Process const& process) { size_t amount_resident = 0; size_t amount_shared = 0; size_t amount_virtual = 0; diff --git a/Kernel/Process.cpp b/Kernel/Process.cpp index dc7ccb6e9e..5346a4880e 100644 --- a/Kernel/Process.cpp +++ b/Kernel/Process.cpp @@ -63,6 +63,95 @@ SpinlockProtected& Process::all_instances() return *s_all_instances; } +ErrorOr Process::for_each_in_same_jail(Function(Process&)> callback) +{ + ErrorOr result {}; + Process::all_instances().with([&](auto const& list) { + Process::current().jail().with([&](auto my_jail) { + for (auto& process : list) { + if (!my_jail) { + result = callback(process); + } else { + // Note: Don't acquire the process jail spinlock twice if it's the same process + // we are currently inspecting. + if (&Process::current() == &process) { + result = callback(process); + } else { + process.jail().with([&](auto& their_jail) { + if (their_jail.ptr() == my_jail.ptr()) + result = callback(process); + }); + } + } + if (result.is_error()) + break; + } + }); + }); + return result; +} + +ErrorOr Process::for_each_child_in_same_jail(Function(Process&)> callback) +{ + ProcessID my_pid = pid(); + ErrorOr result {}; + Process::all_instances().with([&](auto const& list) { + jail().with([&](auto my_jail) { + for (auto& process : list) { + if (!my_jail) { + if (process.ppid() == my_pid || process.has_tracee_thread(pid())) + result = callback(process); + } else { + // FIXME: Is it possible to have a child process being pointing to itself + // as the parent process under normal conditions? + // Note: Don't acquire the process jail spinlock twice if it's the same process + // we are currently inspecting. + if (&Process::current() == &process && (process.ppid() == my_pid || process.has_tracee_thread(pid()))) { + result = callback(process); + } else { + process.jail().with([&](auto& their_jail) { + if ((their_jail.ptr() == my_jail.ptr()) && (process.ppid() == my_pid || process.has_tracee_thread(pid()))) + result = callback(process); + }); + } + } + if (result.is_error()) + break; + } + }); + }); + return result; +} + +ErrorOr Process::for_each_in_pgrp_in_same_jail(ProcessGroupID pgid, Function(Process&)> callback) +{ + ErrorOr result {}; + Process::all_instances().with([&](auto const& list) { + jail().with([&](auto my_jail) { + for (auto& process : list) { + if (!my_jail) { + if (!process.is_dead() && process.pgid() == pgid) + result = callback(process); + } else { + // Note: Don't acquire the process jail spinlock twice if it's the same process + // we are currently inspecting. + if (&Process::current() == &process && !process.is_dead() && process.pgid() == pgid) { + result = callback(process); + } else { + process.jail().with([&](auto& their_jail) { + if ((their_jail.ptr() == my_jail.ptr()) && !process.is_dead() && process.pgid() == pgid) + result = callback(process); + }); + } + } + if (result.is_error()) + break; + } + }); + }); + return result; +} + ProcessID Process::allocate_pid() { // Overflow is UB, and negative PIDs wreck havoc. @@ -426,7 +515,33 @@ void Process::crash(int signal, FlatPtr ip, bool out_of_memory) VERIFY_NOT_REACHED(); } -LockRefPtr Process::from_pid(ProcessID pid) +LockRefPtr Process::from_pid_in_same_jail(ProcessID pid) +{ + return Process::current().jail().with([&](auto& my_jail) -> LockRefPtr { + return all_instances().with([&](auto const& list) -> LockRefPtr { + if (!my_jail) { + for (auto& process : list) { + if (process.pid() == pid) { + return process; + } + } + } else { + for (auto& process : list) { + if (process.pid() == pid) { + return process.jail().with([&](auto& other_process_jail) -> LockRefPtr { + if (other_process_jail.ptr() == my_jail.ptr()) + return process; + return {}; + }); + } + } + } + return {}; + }); + }); +} + +LockRefPtr Process::from_pid_ignoring_jails(ProcessID pid) { return all_instances().with([&](auto const& list) -> LockRefPtr { for (auto const& process : list) { @@ -657,20 +772,25 @@ void Process::finalize() m_fds.with_exclusive([](auto& fds) { fds.clear(); }); m_tty = nullptr; m_executable.with([](auto& executable) { executable = nullptr; }); + m_attached_jail.with([](auto& jail) { + if (jail) + jail->detach({}); + jail = nullptr; + }); m_arguments.clear(); m_environment.clear(); m_state.store(State::Dead, AK::MemoryOrder::memory_order_release); { - if (auto parent_process = Process::from_pid(ppid())) { + if (auto parent_process = Process::from_pid_ignoring_jails(ppid())) { if (parent_process->is_user_process() && (parent_process->m_signal_action_data[SIGCHLD].flags & SA_NOCLDWAIT) != SA_NOCLDWAIT) (void)parent_process->send_signal(SIGCHLD, this); } } if (!!ppid()) { - if (auto parent = Process::from_pid(ppid())) { + if (auto parent = Process::from_pid_ignoring_jails(ppid())) { parent->m_ticks_in_user_for_dead_children += m_ticks_in_user + m_ticks_in_user_for_dead_children; parent->m_ticks_in_kernel_for_dead_children += m_ticks_in_kernel + m_ticks_in_kernel_for_dead_children; } @@ -697,9 +817,9 @@ void Process::unblock_waiters(Thread::WaitBlocker::UnblockFlags flags, u8 signal { LockRefPtr waiter_process; if (auto* my_tracer = tracer()) - waiter_process = Process::from_pid(my_tracer->tracer_pid()); + waiter_process = Process::from_pid_ignoring_jails(my_tracer->tracer_pid()); else - waiter_process = Process::from_pid(ppid()); + waiter_process = Process::from_pid_ignoring_jails(ppid()); if (waiter_process) waiter_process->m_wait_blocker_set.unblock(*this, flags, signal); diff --git a/Kernel/Process.h b/Kernel/Process.h index e84a82d890..a5bfa6ae90 100644 --- a/Kernel/Process.h +++ b/Kernel/Process.h @@ -24,6 +24,7 @@ #include #include #include +#include #include #include #include @@ -70,6 +71,7 @@ Time kgettimeofday(); __ENUMERATE_PLEDGE_PROMISE(prot_exec) \ __ENUMERATE_PLEDGE_PROMISE(map_fixed) \ __ENUMERATE_PLEDGE_PROMISE(getkeymap) \ + __ENUMERATE_PLEDGE_PROMISE(jail) \ __ENUMERATE_PLEDGE_PROMISE(no_error) enum class Pledge : u32 { @@ -213,7 +215,8 @@ public: bool is_kernel_process() const { return m_is_kernel_process; } bool is_user_process() const { return !m_is_kernel_process; } - static LockRefPtr from_pid(ProcessID); + static LockRefPtr from_pid_in_same_jail(ProcessID); + static LockRefPtr from_pid_ignoring_jails(ProcessID); static SessionID get_sid_from_pgid(ProcessGroupID pgid); StringView name() const { return m_name->view(); } @@ -233,6 +236,8 @@ public: return with_protected_data([](auto& protected_data) { return protected_data.ppid; }); } + SpinlockProtected>& jail() { return m_attached_jail; } + NonnullRefPtr credentials() const; bool is_dumpable() const @@ -248,11 +253,11 @@ public: // Breakable iteration functions template Callback> - static void for_each(Callback); - template Callback> - static void for_each_in_pgrp(ProcessGroupID, Callback); - template Callback> - void for_each_child(Callback); + static void for_each_ignoring_jails(Callback); + + static ErrorOr for_each_in_same_jail(Function(Process&)>); + ErrorOr for_each_in_pgrp_in_same_jail(ProcessGroupID, Function(Process&)>); + ErrorOr for_each_child_in_same_jail(Function(Process&)>); template Callback> IterationDecision for_each_thread(Callback); @@ -262,11 +267,7 @@ public: // Non-breakable iteration functions template Callback> - static void for_each(Callback); - template Callback> - static void for_each_in_pgrp(ProcessGroupID, Callback); - template Callback> - void for_each_child(Callback); + static void for_each_ignoring_jails(Callback); template Callback> IterationDecision for_each_thread(Callback); @@ -437,6 +438,8 @@ public: ErrorOr sys$statvfs(Userspace user_params); ErrorOr sys$fstatvfs(int fd, statvfs* buf); ErrorOr sys$map_time_page(); + ErrorOr sys$jail_create(Userspace user_params); + ErrorOr sys$jail_attach(Userspace user_params); template ErrorOr get_sock_or_peer_name(Params const&); @@ -862,6 +865,10 @@ private: LockRefPtr m_tty; LockWeakPtr m_master_tls_region; + + IntrusiveListNode m_jail_list_node; + SpinlockProtected> m_attached_jail { LockRank::Process }; + size_t m_master_tls_size { 0 }; size_t m_master_tls_alignment { 0 }; @@ -914,48 +921,6 @@ static_assert(AssertSize()); extern RecursiveSpinlock g_profiling_lock; -template Callback> -inline void Process::for_each(Callback callback) -{ - Process::all_instances().with([&](auto const& list) { - for (auto it = list.begin(); it != list.end();) { - auto& process = *it; - ++it; - if (callback(process) == IterationDecision::Break) - break; - } - }); -} - -template Callback> -inline void Process::for_each_child(Callback callback) -{ - ProcessID my_pid = pid(); - Process::all_instances().with([&](auto const& list) { - for (auto it = list.begin(); it != list.end();) { - auto& process = *it; - ++it; - if (process.ppid() == my_pid || process.has_tracee_thread(pid())) { - if (callback(process) == IterationDecision::Break) - break; - } - } - }); -} - -template Callback> -inline IterationDecision Process::for_each_thread(Callback callback) const -{ - return thread_list().with([&](auto& thread_list) -> IterationDecision { - for (auto& thread : thread_list) { - IterationDecision decision = callback(thread); - if (decision != IterationDecision::Continue) - return decision; - } - return IterationDecision::Continue; - }); -} - template Callback> inline IterationDecision Process::for_each_thread(Callback callback) { @@ -970,34 +935,27 @@ inline IterationDecision Process::for_each_thread(Callback callback) } template Callback> -inline void Process::for_each_in_pgrp(ProcessGroupID pgid, Callback callback) +inline void Process::for_each_ignoring_jails(Callback callback) { Process::all_instances().with([&](auto const& list) { for (auto it = list.begin(); it != list.end();) { auto& process = *it; ++it; - if (!process.is_dead() && process.pgid() == pgid) { - if (callback(process) == IterationDecision::Break) - break; - } + if (callback(process) == IterationDecision::Break) + break; } }); } -template Callback> -inline void Process::for_each(Callback callback) +template Callback> +inline IterationDecision Process::for_each_thread(Callback callback) const { - return for_each([&](auto& item) { - callback(item); - return IterationDecision::Continue; - }); -} - -template Callback> -inline void Process::for_each_child(Callback callback) -{ - return for_each_child([&](auto& item) { - callback(item); + return thread_list().with([&](auto& thread_list) -> IterationDecision { + for (auto& thread : thread_list) { + IterationDecision decision = callback(thread); + if (decision != IterationDecision::Continue) + return decision; + } return IterationDecision::Continue; }); } @@ -1031,15 +989,6 @@ inline IterationDecision Process::for_each_thread(Callback callback) return IterationDecision::Continue; } -template Callback> -inline void Process::for_each_in_pgrp(ProcessGroupID pgid, Callback callback) -{ - return for_each_in_pgrp(pgid, [&](auto& item) { - callback(item); - return IterationDecision::Continue; - }); -} - inline ProcessID Thread::pid() const { return m_process->pid(); diff --git a/Kernel/ProcessExposed.cpp b/Kernel/ProcessExposed.cpp index 09a0de906c..1891dd8567 100644 --- a/Kernel/ProcessExposed.cpp +++ b/Kernel/ProcessExposed.cpp @@ -206,14 +206,12 @@ ErrorOr ProcFSRootDirectory::traverse_as_directory(FileSystemID fsid, Func TRY(callback({ component.name(), identifier, 0 })); } - return Process::all_instances().with([&](auto& list) -> ErrorOr { - for (auto& process : list) { - VERIFY(!(process.pid() < 0)); - u64 process_id = (u64)process.pid().value(); - InodeIdentifier identifier = { fsid, static_cast(process_id << 36) }; - auto process_id_string = TRY(KString::formatted("{:d}", process_id)); - TRY(callback({ process_id_string->view(), identifier, 0 })); - } + return Process::for_each_in_same_jail([&](Process& process) -> ErrorOr { + VERIFY(!(process.pid() < 0)); + u64 process_id = (u64)process.pid().value(); + InodeIdentifier identifier = { fsid, static_cast(process_id << 36) }; + auto process_id_string = TRY(KString::formatted("{:d}", process_id)); + TRY(callback({ process_id_string->view(), identifier, 0 })); return {}; }); } @@ -234,7 +232,7 @@ ErrorOr> ProcFSRootDirectory::lookup(S return ESRCH; auto actual_pid = pid.value(); - if (auto maybe_process = Process::from_pid(actual_pid)) + if (auto maybe_process = Process::from_pid_in_same_jail(actual_pid)) return maybe_process->procfs_traits(); return ENOENT; diff --git a/Kernel/ProcessSpecificExposed.cpp b/Kernel/ProcessSpecificExposed.cpp index a0855478f3..19b5b09286 100644 --- a/Kernel/ProcessSpecificExposed.cpp +++ b/Kernel/ProcessSpecificExposed.cpp @@ -85,13 +85,11 @@ ErrorOr Process::traverse_children_directory(FileSystemID fsid, Functioncomponent_index() }, 0 })); - return Process::all_instances().with([&](auto& processes) -> ErrorOr { - for (auto& process : processes) { - if (process.ppid() == pid()) { - StringBuilder builder; - builder.appendff("{}", process.pid()); - TRY(callback({ builder.string_view(), { fsid, SegmentedProcFSIndex::build_segmented_index_for_children(pid(), process.pid()) }, DT_LNK })); - } + return Process::for_each_in_same_jail([&](Process& process) -> ErrorOr { + if (process.ppid() == pid()) { + StringBuilder builder; + builder.appendff("{}", process.pid()); + TRY(callback({ builder.string_view(), { fsid, SegmentedProcFSIndex::build_segmented_index_for_children(pid(), process.pid()) }, DT_LNK })); } return {}; }); @@ -103,7 +101,7 @@ ErrorOr> Process::lookup_children_directory(ProcFS cons if (!maybe_pid.has_value()) return ENOENT; - auto child_process = Process::from_pid(*maybe_pid); + auto child_process = Process::from_pid_in_same_jail(*maybe_pid); if (!child_process || child_process->ppid() != pid()) return ENOENT; diff --git a/Kernel/Syscalls/disown.cpp b/Kernel/Syscalls/disown.cpp index 55c5f3d05f..0be9c99ef2 100644 --- a/Kernel/Syscalls/disown.cpp +++ b/Kernel/Syscalls/disown.cpp @@ -12,7 +12,7 @@ ErrorOr Process::sys$disown(ProcessID pid) { VERIFY_PROCESS_BIG_LOCK_ACQUIRED(this); TRY(require_promise(Pledge::proc)); - auto process = Process::from_pid(pid); + auto process = Process::from_pid_in_same_jail(pid); if (!process) return ESRCH; if (process->ppid() != this->pid()) diff --git a/Kernel/Syscalls/execve.cpp b/Kernel/Syscalls/execve.cpp index c8420fa0df..713e1b8832 100644 --- a/Kernel/Syscalls/execve.cpp +++ b/Kernel/Syscalls/execve.cpp @@ -495,6 +495,7 @@ ErrorOr Process::do_exec(NonnullLockRefPtr main_progr auto old_credentials = this->credentials(); auto new_credentials = old_credentials; + auto old_process_attached_jail = m_attached_jail.with([&](auto& jail) -> RefPtr { return jail; }); bool executable_is_setid = false; @@ -553,6 +554,9 @@ ErrorOr Process::do_exec(NonnullLockRefPtr main_progr m_executable.with([&](auto& executable) { executable = main_program_description->custody(); }); m_arguments = move(arguments); + m_attached_jail.with([&](auto& jail) { + jail = old_process_attached_jail; + }); m_environment = move(environment); TRY(m_unveil_data.with([&](auto& unveil_data) -> ErrorOr { diff --git a/Kernel/Syscalls/fork.cpp b/Kernel/Syscalls/fork.cpp index d91df90824..0fdcd53bd4 100644 --- a/Kernel/Syscalls/fork.cpp +++ b/Kernel/Syscalls/fork.cpp @@ -42,6 +42,26 @@ ErrorOr Process::sys$fork(RegisterState& regs) }); })); + // Note: We take the spinlock of Process::all_instances list because we need + // to ensure that when we take the jail spinlock of two processes that we don't + // run into a deadlock situation because both processes compete over each other Jail's + // spinlock. Such pattern of taking 3 spinlocks in the same order happens in + // Process::for_each* methods. + TRY(Process::all_instances().with([&](auto const&) -> ErrorOr { + TRY(m_attached_jail.with([&](auto& parent_jail) -> ErrorOr { + return child->m_attached_jail.with([&](auto& child_jail) -> ErrorOr { + child_jail = parent_jail; + if (child_jail) { + child_jail->attach_count().with([&](auto& attach_count) { + attach_count++; + }); + } + return {}; + }); + })); + return {}; + })); + TRY(child->m_fds.with_exclusive([&](auto& child_fds) { return m_fds.with_exclusive([&](auto& parent_fds) { return child_fds.try_clone(parent_fds); diff --git a/Kernel/Syscalls/jail.cpp b/Kernel/Syscalls/jail.cpp new file mode 100644 index 0000000000..3ac5453106 --- /dev/null +++ b/Kernel/Syscalls/jail.cpp @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2018-2020, Andreas Kling + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include +#include +#include +#include +#include +#include + +namespace Kernel { + +constexpr size_t jail_name_max_size = 50; + +ErrorOr Process::sys$jail_create(Userspace user_params) +{ + VERIFY_NO_PROCESS_BIG_LOCK(this); + TRY(require_promise(Pledge::jail)); + + auto params = TRY(copy_typed_from_user(user_params)); + auto jail_name = TRY(get_syscall_path_argument(params.name)); + if (jail_name->length() > jail_name_max_size) + return ENAMETOOLONG; + + auto jail = TRY(JailManagement::the().create_jail(move(jail_name))); + params.index = jail->index().value(); + + TRY(copy_to_user(user_params, ¶ms)); + return 0; +} + +ErrorOr Process::sys$jail_attach(Userspace user_params) +{ + VERIFY_NO_PROCESS_BIG_LOCK(this); + TRY(require_promise(Pledge::jail)); + + auto params = TRY(copy_typed_from_user(user_params)); + return m_attached_jail.with([&](auto& my_jail) -> ErrorOr { + // Note: If we are already in a jail, don't let the process escape it even if + // it knows there are other jails. + // Note: To ensure the process doesn't try to maliciously enumerate all jails + // in the system, just return EPERM before doing anything else. + if (my_jail) + return EPERM; + auto jail = JailManagement::the().find_jail_by_index(static_cast(params.index)); + if (!jail) + return EINVAL; + my_jail = *jail; + my_jail->attach_count().with([&](auto& attach_count) { + attach_count++; + }); + return 0; + }); +} + +} diff --git a/Kernel/Syscalls/kill.cpp b/Kernel/Syscalls/kill.cpp index 6a92c01d2d..84291d515e 100644 --- a/Kernel/Syscalls/kill.cpp +++ b/Kernel/Syscalls/kill.cpp @@ -42,7 +42,7 @@ ErrorOr Process::do_killpg(ProcessGroupID pgrp, int signal) bool any_succeeded = false; ErrorOr error; - Process::for_each_in_pgrp(pgrp, [&](auto& process) { + TRY(Process::current().for_each_in_pgrp_in_same_jail(pgrp, [&](auto& process) -> ErrorOr { group_was_empty = false; ErrorOr res = do_kill(process, signal); @@ -50,7 +50,8 @@ ErrorOr Process::do_killpg(ProcessGroupID pgrp, int signal) any_succeeded = true; else error = move(res); - }); + return {}; + })); if (group_was_empty) return ESRCH; @@ -67,7 +68,7 @@ ErrorOr Process::do_killall(int signal) ErrorOr error; // Send the signal to all processes we have access to for. - Process::all_instances().for_each([&](auto& process) { + TRY(Process::for_each_in_same_jail([&](auto& process) -> ErrorOr { ErrorOr res; if (process.pid() == pid()) res = do_killself(signal); @@ -78,7 +79,8 @@ ErrorOr Process::do_killall(int signal) any_succeeded = true; else error = move(res); - }); + return {}; + })); if (any_succeeded) return {}; @@ -122,7 +124,7 @@ ErrorOr Process::sys$kill(pid_t pid_or_pgid, int signal) return 0; } VERIFY(pid_or_pgid >= 0); - auto peer = Process::from_pid(pid_or_pgid); + auto peer = Process::from_pid_in_same_jail(pid_or_pgid); if (!peer) return ESRCH; TRY(do_kill(*peer, signal)); diff --git a/Kernel/Syscalls/profiling.cpp b/Kernel/Syscalls/profiling.cpp index 869ccf7dd2..e8ebd678ac 100644 --- a/Kernel/Syscalls/profiling.cpp +++ b/Kernel/Syscalls/profiling.cpp @@ -53,15 +53,15 @@ ErrorOr Process::profiling_enable(pid_t pid, u64 event_mask) return ENOTSUP; g_profiling_all_threads = true; PerformanceManager::add_process_created_event(*Scheduler::colonel()); - Process::for_each([](auto& process) { + TRY(Process::for_each_in_same_jail([](auto& process) -> ErrorOr { PerformanceManager::add_process_created_event(process); - return IterationDecision::Continue; - }); + return {}; + })); g_profiling_event_mask = event_mask; return 0; } - auto process = Process::from_pid(pid); + auto process = Process::from_pid_in_same_jail(pid); if (!process) return ESRCH; if (process->is_dead()) @@ -101,7 +101,7 @@ ErrorOr Process::sys$profiling_disable(pid_t pid) return 0; } - auto process = Process::from_pid(pid); + auto process = Process::from_pid_in_same_jail(pid); if (!process) return ESRCH; auto credentials = this->credentials(); @@ -140,7 +140,7 @@ ErrorOr Process::sys$profiling_free_buffer(pid_t pid) return 0; } - auto process = Process::from_pid(pid); + auto process = Process::from_pid_in_same_jail(pid); if (!process) return ESRCH; auto credentials = this->credentials(); diff --git a/Kernel/Syscalls/sched.cpp b/Kernel/Syscalls/sched.cpp index f5db4eadbf..a1c854556d 100644 --- a/Kernel/Syscalls/sched.cpp +++ b/Kernel/Syscalls/sched.cpp @@ -38,7 +38,7 @@ ErrorOr> Process::get_thread_from_pid_or_tid(pid_t pid_or_ case Syscall::SchedulerParametersMode::Process: { auto* searched_process = this; if (pid_or_tid != 0) - searched_process = Process::from_pid(pid_or_tid); + searched_process = Process::from_pid_in_same_jail(pid_or_tid); if (searched_process == nullptr) return ESRCH; diff --git a/Kernel/Syscalls/setpgid.cpp b/Kernel/Syscalls/setpgid.cpp index 8ff0b70bbf..4a52aaf9b8 100644 --- a/Kernel/Syscalls/setpgid.cpp +++ b/Kernel/Syscalls/setpgid.cpp @@ -16,7 +16,7 @@ ErrorOr Process::sys$getsid(pid_t pid) TRY(require_promise(Pledge::stdio)); if (pid == 0) return sid().value(); - auto process = Process::from_pid(pid); + auto process = Process::from_pid_in_same_jail(pid); if (!process) return ESRCH; if (sid() != process->sid()) @@ -30,10 +30,10 @@ ErrorOr Process::sys$setsid() TRY(require_promise(Pledge::proc)); InterruptDisabler disabler; bool found_process_with_same_pgid_as_my_pid = false; - Process::for_each_in_pgrp(pid().value(), [&](auto&) { + TRY(Process::for_each_in_pgrp_in_same_jail(pid().value(), [&](auto&) -> ErrorOr { found_process_with_same_pgid_as_my_pid = true; - return IterationDecision::Break; - }); + return {}; + })); if (found_process_with_same_pgid_as_my_pid) return EPERM; // Create a new Session and a new ProcessGroup. @@ -52,7 +52,7 @@ ErrorOr Process::sys$getpgid(pid_t pid) TRY(require_promise(Pledge::stdio)); if (pid == 0) return pgid().value(); - auto process = Process::from_pid(pid); + auto process = Process::from_pid_in_same_jail(pid); if (!process) return ESRCH; return process->pgid().value(); @@ -70,10 +70,10 @@ SessionID Process::get_sid_from_pgid(ProcessGroupID pgid) // FIXME: This xor sys$setsid() uses the wrong locking mechanism. SessionID sid { -1 }; - Process::for_each_in_pgrp(pgid, [&](auto& process) { + MUST(Process::current().for_each_in_pgrp_in_same_jail(pgid, [&](auto& process) -> ErrorOr { sid = process.sid(); - return IterationDecision::Break; - }); + return {}; + })); return sid; } @@ -87,7 +87,7 @@ ErrorOr Process::sys$setpgid(pid_t specified_pid, pid_t specified_pgid) // The value of the pgid argument is less than 0, or is not a value supported by the implementation. return EINVAL; } - auto process = Process::from_pid(pid); + auto process = Process::from_pid_in_same_jail(pid); if (!process) return ESRCH; if (process != this && process->ppid() != this->pid()) { diff --git a/Kernel/Syscalls/waitid.cpp b/Kernel/Syscalls/waitid.cpp index d8f9367d90..8398376658 100644 --- a/Kernel/Syscalls/waitid.cpp +++ b/Kernel/Syscalls/waitid.cpp @@ -30,7 +30,7 @@ ErrorOr Process::sys$waitid(Userspace case P_ALL: break; case P_PID: { - auto waitee_process = Process::from_pid(params.id); + auto waitee_process = Process::from_pid_in_same_jail(params.id); if (!waitee_process) return ECHILD; bool waitee_is_child = waitee_process->ppid() == Process::current().pid(); diff --git a/Kernel/TTY/TTY.cpp b/Kernel/TTY/TTY.cpp index 95d05f8c1d..25b6d71fc0 100644 --- a/Kernel/TTY/TTY.cpp +++ b/Kernel/TTY/TTY.cpp @@ -359,11 +359,12 @@ void TTY::generate_signal(int signal) flush_input(); dbgln_if(TTY_DEBUG, "Send signal {} to everyone in pgrp {}", signal, pgid().value()); InterruptDisabler disabler; // FIXME: Iterate over a set of process handles instead? - Process::for_each_in_pgrp(pgid(), [&](auto& process) { + MUST(Process::current().for_each_in_pgrp_in_same_jail(pgid(), [&](auto& process) -> ErrorOr { dbgln_if(TTY_DEBUG, "Send signal {} to {}", signal, process); // FIXME: Should this error be propagated somehow? [[maybe_unused]] auto rc = process.send_signal(signal, nullptr); - }); + return {}; + })); } void TTY::flush_input() @@ -493,7 +494,7 @@ ErrorOr TTY::ioctl(OpenFileDescription&, unsigned request, Userspacesid() : Process::get_sid_from_pgid(pgid); if (!new_sid || new_sid != current_process.sid()) return EPERM; @@ -502,7 +503,7 @@ ErrorOr TTY::ioctl(OpenFileDescription&, unsigned request, Userspaceppid())) { + if (auto parent = Process::from_pid_ignoring_jails(process->ppid())) { m_original_process_parent = *parent; return {}; } diff --git a/Kernel/Thread.cpp b/Kernel/Thread.cpp index c16bbd98fc..6fbfab58d5 100644 --- a/Kernel/Thread.cpp +++ b/Kernel/Thread.cpp @@ -978,7 +978,7 @@ DispatchSignalResult Thread::dispatch_signal(u8 signal) auto& action = m_process->m_signal_action_data[signal]; auto sender_pid = m_signal_senders[signal]; - auto sender = Process::from_pid(sender_pid); + auto sender = Process::from_pid_ignoring_jails(sender_pid); if (!current_trap() && !action.handler_or_sigaction.is_null()) { // We're trying dispatch a handled signal to a user process that was scheduled @@ -1303,7 +1303,7 @@ void Thread::set_state(State new_state, u8 stop_signal) }); process.unblock_waiters(Thread::WaitBlocker::UnblockFlags::Continued); // Tell the parent process (if any) about this change. - if (auto parent = Process::from_pid(process.ppid())) { + if (auto parent = Process::from_pid_ignoring_jails(process.ppid())) { [[maybe_unused]] auto result = parent->send_signal(SIGCHLD, &process); } } @@ -1327,7 +1327,7 @@ void Thread::set_state(State new_state, u8 stop_signal) }); process.unblock_waiters(Thread::WaitBlocker::UnblockFlags::Stopped, stop_signal); // Tell the parent process (if any) about this change. - if (auto parent = Process::from_pid(process.ppid())) { + if (auto parent = Process::from_pid_ignoring_jails(process.ppid())) { [[maybe_unused]] auto result = parent->send_signal(SIGCHLD, &process); } }