Skip to content

Commit

Permalink
Kernel: Add support for jails
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
supercomputer7 authored and ADKaster committed Nov 6, 2022
1 parent d69a038 commit 5e06241
Show file tree
Hide file tree
Showing 35 changed files with 609 additions and 160 deletions.
11 changes: 11 additions & 0 deletions Kernel/API/Syscall.h
Expand Up @@ -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) \
Expand Down Expand Up @@ -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;
Expand Down
1 change: 1 addition & 0 deletions Kernel/Arch/aarch64/init.cpp
Expand Up @@ -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.
Expand Down
2 changes: 2 additions & 0 deletions Kernel/Arch/x86/init.cpp
Expand Up @@ -39,6 +39,7 @@
#include <Kernel/Graphics/Console/VGATextModeConsole.h>
#include <Kernel/Graphics/GraphicsManagement.h>
#include <Kernel/Heap/kmalloc.h>
#include <Kernel/JailManagement.h>
#include <Kernel/KSyms.h>
#include <Kernel/Memory/MemoryManager.h>
#include <Kernel/Multiboot.h>
Expand Down Expand Up @@ -237,6 +238,7 @@ extern "C" [[noreturn]] UNMAP_AFTER_INIT void init(BootInfo const& boot_info)
__stack_chk_guard = get_fast_random<size_t>();

ProcFSComponentRegistry::initialize();
JailManagement::the();
Process::initialize();

Scheduler::initialize();
Expand Down
4 changes: 4 additions & 0 deletions Kernel/CMakeLists.txt
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down
18 changes: 9 additions & 9 deletions Kernel/FileSystem/ProcFS.cpp
Expand Up @@ -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 {};

Expand All @@ -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));
Expand All @@ -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)
Expand Down Expand Up @@ -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 {};

Expand All @@ -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) {
Expand All @@ -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) {
Expand Down Expand Up @@ -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 {};

Expand All @@ -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));
Expand Down Expand Up @@ -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();
Expand Down
2 changes: 2 additions & 0 deletions Kernel/FileSystem/SysFS/Subsystems/Kernel/Directory.cpp
Expand Up @@ -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>
Expand Down Expand Up @@ -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));
Expand Down
38 changes: 38 additions & 0 deletions 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 {};
}

}
28 changes: 28 additions & 0 deletions 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;
};

}
6 changes: 3 additions & 3 deletions Kernel/FileSystem/SysFS/Subsystems/Kernel/Processes.cpp
Expand Up @@ -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());
Expand Down
Expand Up @@ -5,6 +5,7 @@
*/

#include <Kernel/FileSystem/SysFS/Subsystems/Kernel/Variables/BooleanVariable.h>
#include <Kernel/Process.h>
#include <Kernel/Sections.h>

namespace Kernel {
Expand All @@ -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)
Expand Down
Expand Up @@ -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);
}

Expand Down
Expand Up @@ -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 {
Expand All @@ -24,7 +25,7 @@ class SysFSCapsLockRemap final : public SysFSSystemBoolean {

explicit SysFSCapsLockRemap(SysFSDirectory const&);

mutable Mutex m_lock;
mutable Spinlock m_lock { LockRank::None };
};

}
Expand Up @@ -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;
}

Expand Down
Expand Up @@ -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 {
Expand All @@ -24,7 +25,7 @@ class SysFSDumpKmallocStacks final : public SysFSSystemBoolean {

explicit SysFSDumpKmallocStacks(SysFSDirectory const&);

mutable Mutex m_lock;
mutable Spinlock m_lock { LockRank::None };
};

}
1 change: 1 addition & 0 deletions Kernel/Forward.h
Expand Up @@ -28,6 +28,7 @@ class IPv4Socket;
class Inode;
class InodeIdentifier;
class InodeWatcher;
class Jail;
class KBuffer;
class KString;
class LocalSocket;
Expand Down

0 comments on commit 5e06241

Please sign in to comment.