diff options
author | Liav A <liavalb@gmail.com> | 2022-11-02 22:26:02 +0200 |
---|---|---|
committer | Andrew Kaster <andrewdkaster@gmail.com> | 2022-11-05 18:00:58 -0600 |
commit | 5e062414c11df31ed595c363990005eef00fa263 (patch) | |
tree | 62281b52f5408e4b3b814553e9cf18a234cc001e /Kernel/FileSystem | |
parent | d69a0380e1558e82a6a0bda71e66eab121cdcda4 (diff) | |
download | serenity-5e062414c11df31ed595c363990005eef00fa263.zip |
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.
Diffstat (limited to 'Kernel/FileSystem')
10 files changed, 106 insertions, 27 deletions
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<void> 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<size_t> ProcFSProcessDirectoryInode::read_bytes_locked(off_t, size_t, Us ErrorOr<void> ProcFSProcessDirectoryInode::traverse_as_directory(Function<ErrorOr<void>(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<void> ProcFSProcessDirectoryInode::traverse_as_directory(Function<ErrorO ErrorOr<NonnullLockRefPtr<Inode>> 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<void> ProcFSProcessSubDirectoryInode::traverse_as_directory(Function<ErrorOr<void>(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<void> ProcFSProcessSubDirectoryInode::traverse_as_directory(Function<Err ErrorOr<NonnullLockRefPtr<Inode>> 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<size_t> 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<void> 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 <Kernel/FileSystem/SysFS/Subsystems/Kernel/DiskUsage.h> #include <Kernel/FileSystem/SysFS/Subsystems/Kernel/GlobalInformation.h> #include <Kernel/FileSystem/SysFS/Subsystems/Kernel/Interrupts.h> +#include <Kernel/FileSystem/SysFS/Subsystems/Kernel/Jails.h> #include <Kernel/FileSystem/SysFS/Subsystems/Kernel/Keymap.h> #include <Kernel/FileSystem/SysFS/Subsystems/Kernel/LoadBase.h> #include <Kernel/FileSystem/SysFS/Subsystems/Kernel/Log.h> @@ -46,6 +47,7 @@ UNMAP_AFTER_INIT NonnullLockRefPtr<SysFSGlobalKernelStatsDirectory> 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. <liavalb@hotmail.co.il> + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include <AK/JsonObjectSerializer.h> +#include <Kernel/FileSystem/SysFS/Subsystems/Kernel/Jails.h> +#include <Kernel/JailManagement.h> +#include <Kernel/Sections.h> + +namespace Kernel { + +UNMAP_AFTER_INIT SysFSJails::SysFSJails(SysFSDirectory const& parent_directory) + : SysFSGlobalInformation(parent_directory) +{ +} + +UNMAP_AFTER_INIT NonnullLockRefPtr<SysFSJails> SysFSJails::must_create(SysFSDirectory const& parent_directory) +{ + return adopt_lock_ref_if_nonnull(new (nothrow) SysFSJails(parent_directory)).release_nonnull(); +} + +ErrorOr<void> SysFSJails::try_generate(KBufferBuilder& builder) +{ + auto array = TRY(JsonArraySerializer<>::try_create(builder)); + TRY(JailManagement::the().for_each_in_same_jail([&array](Jail& jail) -> ErrorOr<void> { + 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. <liavalb@hotmail.co.il> + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#pragma once + +#include <AK/Types.h> +#include <Kernel/FileSystem/SysFS/Subsystems/Kernel/GlobalInformation.h> +#include <Kernel/KBufferBuilder.h> +#include <Kernel/Library/LockRefPtr.h> +#include <Kernel/UserOrKernelBuffer.h> + +namespace Kernel { + +class SysFSJails final : public SysFSGlobalInformation { +public: + virtual StringView name() const override { return "jails"sv; } + + static NonnullLockRefPtr<SysFSJails> must_create(SysFSDirectory const& parent_directory); + +private: + explicit SysFSJails(SysFSDirectory const& parent_directory); + virtual ErrorOr<void> 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<void> 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<void> { - for (auto& process : processes) - TRY(build_process(array, process)); + TRY(Process::for_each_in_same_jail([&](Process& process) -> ErrorOr<void> { + 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 <Kernel/FileSystem/SysFS/Subsystems/Kernel/Variables/BooleanVariable.h> +#include <Kernel/Process.h> #include <Kernel/Sections.h> namespace Kernel { @@ -16,18 +17,26 @@ ErrorOr<void> SysFSSystemBoolean::try_generate(KBufferBuilder& builder) ErrorOr<size_t> 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<size_t> { + // 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<void> 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> 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 <AK/Types.h> #include <Kernel/FileSystem/SysFS/Subsystems/Kernel/Variables/BooleanVariable.h> #include <Kernel/Library/LockRefPtr.h> +#include <Kernel/Locking/Spinlock.h> #include <Kernel/UserOrKernelBuffer.h> 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<SysFSDumpKmallocStacks> 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 <AK/Types.h> #include <Kernel/FileSystem/SysFS/Subsystems/Kernel/Variables/BooleanVariable.h> #include <Kernel/Library/LockRefPtr.h> +#include <Kernel/Locking/Spinlock.h> #include <Kernel/UserOrKernelBuffer.h> namespace Kernel { @@ -24,7 +25,7 @@ private: explicit SysFSDumpKmallocStacks(SysFSDirectory const&); - mutable Mutex m_lock; + mutable Spinlock m_lock { LockRank::None }; }; } |