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); } }