mirror of
https://github.com/SerenityOS/serenity
synced 2024-07-23 02:55:15 +00:00
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.
This commit is contained in:
parent
d69a0380e1
commit
5e062414c1
|
@ -107,6 +107,8 @@ enum class NeedsBigProcessLock {
|
||||||
S(inode_watcher_remove_watch, NeedsBigProcessLock::Yes) \
|
S(inode_watcher_remove_watch, NeedsBigProcessLock::Yes) \
|
||||||
S(ioctl, NeedsBigProcessLock::Yes) \
|
S(ioctl, NeedsBigProcessLock::Yes) \
|
||||||
S(join_thread, NeedsBigProcessLock::Yes) \
|
S(join_thread, NeedsBigProcessLock::Yes) \
|
||||||
|
S(jail_create, NeedsBigProcessLock::No) \
|
||||||
|
S(jail_attach, NeedsBigProcessLock::No) \
|
||||||
S(kill, NeedsBigProcessLock::Yes) \
|
S(kill, NeedsBigProcessLock::Yes) \
|
||||||
S(kill_thread, NeedsBigProcessLock::Yes) \
|
S(kill_thread, NeedsBigProcessLock::Yes) \
|
||||||
S(killpg, NeedsBigProcessLock::Yes) \
|
S(killpg, NeedsBigProcessLock::Yes) \
|
||||||
|
@ -329,6 +331,15 @@ struct SC_setkeymap_params {
|
||||||
StringArgument map_name;
|
StringArgument map_name;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct SC_jail_create_params {
|
||||||
|
u64 index;
|
||||||
|
StringArgument name;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct SC_jail_attach_params {
|
||||||
|
u64 index;
|
||||||
|
};
|
||||||
|
|
||||||
struct SC_getkeymap_params {
|
struct SC_getkeymap_params {
|
||||||
u32* map;
|
u32* map;
|
||||||
u32* shift_map;
|
u32* shift_map;
|
||||||
|
|
|
@ -129,6 +129,7 @@ extern "C" [[noreturn]] void init()
|
||||||
dmesgln("Initialize MMU");
|
dmesgln("Initialize MMU");
|
||||||
Memory::MemoryManager::initialize(0);
|
Memory::MemoryManager::initialize(0);
|
||||||
DeviceManagement::initialize();
|
DeviceManagement::initialize();
|
||||||
|
JailManagement::the();
|
||||||
|
|
||||||
// Invoke all static global constructors in the kernel.
|
// Invoke all static global constructors in the kernel.
|
||||||
// Note that we want to do this as early as possible.
|
// Note that we want to do this as early as possible.
|
||||||
|
|
|
@ -39,6 +39,7 @@
|
||||||
#include <Kernel/Graphics/Console/VGATextModeConsole.h>
|
#include <Kernel/Graphics/Console/VGATextModeConsole.h>
|
||||||
#include <Kernel/Graphics/GraphicsManagement.h>
|
#include <Kernel/Graphics/GraphicsManagement.h>
|
||||||
#include <Kernel/Heap/kmalloc.h>
|
#include <Kernel/Heap/kmalloc.h>
|
||||||
|
#include <Kernel/JailManagement.h>
|
||||||
#include <Kernel/KSyms.h>
|
#include <Kernel/KSyms.h>
|
||||||
#include <Kernel/Memory/MemoryManager.h>
|
#include <Kernel/Memory/MemoryManager.h>
|
||||||
#include <Kernel/Multiboot.h>
|
#include <Kernel/Multiboot.h>
|
||||||
|
@ -237,6 +238,7 @@ extern "C" [[noreturn]] UNMAP_AFTER_INIT void init(BootInfo const& boot_info)
|
||||||
__stack_chk_guard = get_fast_random<size_t>();
|
__stack_chk_guard = get_fast_random<size_t>();
|
||||||
|
|
||||||
ProcFSComponentRegistry::initialize();
|
ProcFSComponentRegistry::initialize();
|
||||||
|
JailManagement::the();
|
||||||
Process::initialize();
|
Process::initialize();
|
||||||
|
|
||||||
Scheduler::initialize();
|
Scheduler::initialize();
|
||||||
|
|
|
@ -84,6 +84,8 @@ set(KERNEL_SOURCES
|
||||||
Graphics/VirtIOGPU/GPU3DDevice.cpp
|
Graphics/VirtIOGPU/GPU3DDevice.cpp
|
||||||
Graphics/VirtIOGPU/GraphicsAdapter.cpp
|
Graphics/VirtIOGPU/GraphicsAdapter.cpp
|
||||||
IOWindow.cpp
|
IOWindow.cpp
|
||||||
|
Jail.cpp
|
||||||
|
JailManagement.cpp
|
||||||
SanCov.cpp
|
SanCov.cpp
|
||||||
Storage/ATA/AHCI/Controller.cpp
|
Storage/ATA/AHCI/Controller.cpp
|
||||||
Storage/ATA/AHCI/Port.cpp
|
Storage/ATA/AHCI/Port.cpp
|
||||||
|
@ -153,6 +155,7 @@ set(KERNEL_SOURCES
|
||||||
FileSystem/SysFS/Subsystems/Kernel/Interrupts.cpp
|
FileSystem/SysFS/Subsystems/Kernel/Interrupts.cpp
|
||||||
FileSystem/SysFS/Subsystems/Kernel/Processes.cpp
|
FileSystem/SysFS/Subsystems/Kernel/Processes.cpp
|
||||||
FileSystem/SysFS/Subsystems/Kernel/CPUInfo.cpp
|
FileSystem/SysFS/Subsystems/Kernel/CPUInfo.cpp
|
||||||
|
FileSystem/SysFS/Subsystems/Kernel/Jails.cpp
|
||||||
FileSystem/SysFS/Subsystems/Kernel/Keymap.cpp
|
FileSystem/SysFS/Subsystems/Kernel/Keymap.cpp
|
||||||
FileSystem/SysFS/Subsystems/Kernel/Profile.cpp
|
FileSystem/SysFS/Subsystems/Kernel/Profile.cpp
|
||||||
FileSystem/SysFS/Subsystems/Kernel/Directory.cpp
|
FileSystem/SysFS/Subsystems/Kernel/Directory.cpp
|
||||||
|
@ -262,6 +265,7 @@ set(KERNEL_SOURCES
|
||||||
Syscalls/getuid.cpp
|
Syscalls/getuid.cpp
|
||||||
Syscalls/hostname.cpp
|
Syscalls/hostname.cpp
|
||||||
Syscalls/ioctl.cpp
|
Syscalls/ioctl.cpp
|
||||||
|
Syscalls/jail.cpp
|
||||||
Syscalls/keymap.cpp
|
Syscalls/keymap.cpp
|
||||||
Syscalls/kill.cpp
|
Syscalls/kill.cpp
|
||||||
Syscalls/link.cpp
|
Syscalls/link.cpp
|
||||||
|
|
|
@ -256,7 +256,7 @@ ErrorOr<void> ProcFSProcessDirectoryInode::attach(OpenFileDescription&)
|
||||||
InodeMetadata ProcFSProcessDirectoryInode::metadata() const
|
InodeMetadata ProcFSProcessDirectoryInode::metadata() const
|
||||||
{
|
{
|
||||||
MutexLocker locker(m_inode_lock);
|
MutexLocker locker(m_inode_lock);
|
||||||
auto process = Process::from_pid(associated_pid());
|
auto process = Process::from_pid_in_same_jail(associated_pid());
|
||||||
if (!process)
|
if (!process)
|
||||||
return {};
|
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
|
ErrorOr<void> ProcFSProcessDirectoryInode::traverse_as_directory(Function<ErrorOr<void>(FileSystem::DirectoryEntryView const&)> callback) const
|
||||||
{
|
{
|
||||||
MutexLocker locker(procfs().m_lock);
|
MutexLocker locker(procfs().m_lock);
|
||||||
auto process = Process::from_pid(associated_pid());
|
auto process = Process::from_pid_in_same_jail(associated_pid());
|
||||||
if (!process)
|
if (!process)
|
||||||
return EINVAL;
|
return EINVAL;
|
||||||
return process->procfs_traits()->traverse_as_directory(procfs().fsid(), move(callback));
|
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)
|
ErrorOr<NonnullLockRefPtr<Inode>> ProcFSProcessDirectoryInode::lookup(StringView name)
|
||||||
{
|
{
|
||||||
MutexLocker locker(procfs().m_lock);
|
MutexLocker locker(procfs().m_lock);
|
||||||
auto process = Process::from_pid(associated_pid());
|
auto process = Process::from_pid_in_same_jail(associated_pid());
|
||||||
if (!process)
|
if (!process)
|
||||||
return ESRCH;
|
return ESRCH;
|
||||||
if (name == "fd"sv)
|
if (name == "fd"sv)
|
||||||
|
@ -345,7 +345,7 @@ void ProcFSProcessSubDirectoryInode::did_seek(OpenFileDescription&, off_t)
|
||||||
InodeMetadata ProcFSProcessSubDirectoryInode::metadata() const
|
InodeMetadata ProcFSProcessSubDirectoryInode::metadata() const
|
||||||
{
|
{
|
||||||
MutexLocker locker(m_inode_lock);
|
MutexLocker locker(m_inode_lock);
|
||||||
auto process = Process::from_pid(associated_pid());
|
auto process = Process::from_pid_in_same_jail(associated_pid());
|
||||||
if (!process)
|
if (!process)
|
||||||
return {};
|
return {};
|
||||||
|
|
||||||
|
@ -363,7 +363,7 @@ InodeMetadata ProcFSProcessSubDirectoryInode::metadata() const
|
||||||
ErrorOr<void> ProcFSProcessSubDirectoryInode::traverse_as_directory(Function<ErrorOr<void>(FileSystem::DirectoryEntryView const&)> callback) const
|
ErrorOr<void> ProcFSProcessSubDirectoryInode::traverse_as_directory(Function<ErrorOr<void>(FileSystem::DirectoryEntryView const&)> callback) const
|
||||||
{
|
{
|
||||||
MutexLocker locker(procfs().m_lock);
|
MutexLocker locker(procfs().m_lock);
|
||||||
auto process = Process::from_pid(associated_pid());
|
auto process = Process::from_pid_in_same_jail(associated_pid());
|
||||||
if (!process)
|
if (!process)
|
||||||
return EINVAL;
|
return EINVAL;
|
||||||
switch (m_sub_directory_type) {
|
switch (m_sub_directory_type) {
|
||||||
|
@ -382,7 +382,7 @@ ErrorOr<void> ProcFSProcessSubDirectoryInode::traverse_as_directory(Function<Err
|
||||||
ErrorOr<NonnullLockRefPtr<Inode>> ProcFSProcessSubDirectoryInode::lookup(StringView name)
|
ErrorOr<NonnullLockRefPtr<Inode>> ProcFSProcessSubDirectoryInode::lookup(StringView name)
|
||||||
{
|
{
|
||||||
MutexLocker locker(procfs().m_lock);
|
MutexLocker locker(procfs().m_lock);
|
||||||
auto process = Process::from_pid(associated_pid());
|
auto process = Process::from_pid_in_same_jail(associated_pid());
|
||||||
if (!process)
|
if (!process)
|
||||||
return ESRCH;
|
return ESRCH;
|
||||||
switch (m_sub_directory_type) {
|
switch (m_sub_directory_type) {
|
||||||
|
@ -472,7 +472,7 @@ static mode_t determine_procfs_process_inode_mode(SegmentedProcFSIndex::ProcessS
|
||||||
InodeMetadata ProcFSProcessPropertyInode::metadata() const
|
InodeMetadata ProcFSProcessPropertyInode::metadata() const
|
||||||
{
|
{
|
||||||
MutexLocker locker(m_inode_lock);
|
MutexLocker locker(m_inode_lock);
|
||||||
auto process = Process::from_pid(associated_pid());
|
auto process = Process::from_pid_in_same_jail(associated_pid());
|
||||||
if (!process)
|
if (!process)
|
||||||
return {};
|
return {};
|
||||||
|
|
||||||
|
@ -499,7 +499,7 @@ ErrorOr<size_t> ProcFSProcessPropertyInode::read_bytes_locked(off_t offset, size
|
||||||
|
|
||||||
if (!description) {
|
if (!description) {
|
||||||
auto builder = TRY(KBufferBuilder::try_create());
|
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)
|
if (!process)
|
||||||
return Error::from_errno(ESRCH);
|
return Error::from_errno(ESRCH);
|
||||||
TRY(try_to_acquire_data(*process, builder));
|
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
|
// For process-specific inodes, hold the process's ptrace lock across refresh
|
||||||
// and refuse to load data if the process is not dumpable.
|
// 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.
|
// 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)
|
if (!process)
|
||||||
return Error::from_errno(ESRCH);
|
return Error::from_errno(ESRCH);
|
||||||
process->ptrace_lock().lock();
|
process->ptrace_lock().lock();
|
||||||
|
|
|
@ -13,6 +13,7 @@
|
||||||
#include <Kernel/FileSystem/SysFS/Subsystems/Kernel/DiskUsage.h>
|
#include <Kernel/FileSystem/SysFS/Subsystems/Kernel/DiskUsage.h>
|
||||||
#include <Kernel/FileSystem/SysFS/Subsystems/Kernel/GlobalInformation.h>
|
#include <Kernel/FileSystem/SysFS/Subsystems/Kernel/GlobalInformation.h>
|
||||||
#include <Kernel/FileSystem/SysFS/Subsystems/Kernel/Interrupts.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/Keymap.h>
|
||||||
#include <Kernel/FileSystem/SysFS/Subsystems/Kernel/LoadBase.h>
|
#include <Kernel/FileSystem/SysFS/Subsystems/Kernel/LoadBase.h>
|
||||||
#include <Kernel/FileSystem/SysFS/Subsystems/Kernel/Log.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(SysFSProfile::must_create(*global_kernel_stats_directory));
|
||||||
list.append(SysFSKernelLoadBase::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(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(SysFSGlobalNetworkStatsDirectory::must_create(*global_kernel_stats_directory));
|
||||||
list.append(SysFSGlobalKernelVariablesDirectory::must_create(*global_kernel_stats_directory));
|
list.append(SysFSGlobalKernelVariablesDirectory::must_create(*global_kernel_stats_directory));
|
||||||
|
|
38
Kernel/FileSystem/SysFS/Subsystems/Kernel/Jails.cpp
Normal file
38
Kernel/FileSystem/SysFS/Subsystems/Kernel/Jails.cpp
Normal file
|
@ -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
Kernel/FileSystem/SysFS/Subsystems/Kernel/Jails.h
Normal file
28
Kernel/FileSystem/SysFS/Subsystems/Kernel/Jails.h
Normal file
|
@ -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;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
|
@ -141,10 +141,10 @@ ErrorOr<void> SysFSOverallProcesses::try_generate(KBufferBuilder& builder)
|
||||||
|
|
||||||
{
|
{
|
||||||
auto array = TRY(json.add_array("processes"sv));
|
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(build_process(array, *Scheduler::colonel()));
|
||||||
TRY(Process::all_instances().with([&](auto& processes) -> ErrorOr<void> {
|
TRY(Process::for_each_in_same_jail([&](Process& process) -> ErrorOr<void> {
|
||||||
for (auto& process : processes)
|
TRY(build_process(array, process));
|
||||||
TRY(build_process(array, process));
|
|
||||||
return {};
|
return {};
|
||||||
}));
|
}));
|
||||||
TRY(array.finish());
|
TRY(array.finish());
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <Kernel/FileSystem/SysFS/Subsystems/Kernel/Variables/BooleanVariable.h>
|
#include <Kernel/FileSystem/SysFS/Subsystems/Kernel/Variables/BooleanVariable.h>
|
||||||
|
#include <Kernel/Process.h>
|
||||||
#include <Kernel/Sections.h>
|
#include <Kernel/Sections.h>
|
||||||
|
|
||||||
namespace Kernel {
|
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*)
|
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);
|
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;
|
char value = 0;
|
||||||
TRY(buffer.read(&value, 1));
|
TRY(buffer.read(&value, 1));
|
||||||
if (value == '0')
|
|
||||||
set_value(false);
|
return Process::current().jail().with([&](auto& my_jail) -> ErrorOr<size_t> {
|
||||||
else if (value == '1')
|
// Note: If we are in a jail, don't let the current process to change the variable.
|
||||||
set_value(true);
|
if (my_jail)
|
||||||
else
|
return Error::from_errno(EPERM);
|
||||||
return EINVAL;
|
if (count != 1)
|
||||||
return 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)
|
ErrorOr<void> SysFSSystemBoolean::truncate(u64 size)
|
||||||
|
|
|
@ -22,12 +22,12 @@ UNMAP_AFTER_INIT NonnullLockRefPtr<SysFSCapsLockRemap> SysFSCapsLockRemap::must_
|
||||||
|
|
||||||
bool SysFSCapsLockRemap::value() const
|
bool SysFSCapsLockRemap::value() const
|
||||||
{
|
{
|
||||||
MutexLocker locker(m_lock);
|
SpinlockLocker locker(m_lock);
|
||||||
return g_caps_lock_remapped_to_ctrl.load();
|
return g_caps_lock_remapped_to_ctrl.load();
|
||||||
}
|
}
|
||||||
void SysFSCapsLockRemap::set_value(bool new_value)
|
void SysFSCapsLockRemap::set_value(bool new_value)
|
||||||
{
|
{
|
||||||
MutexLocker locker(m_lock);
|
SpinlockLocker locker(m_lock);
|
||||||
g_caps_lock_remapped_to_ctrl.exchange(new_value);
|
g_caps_lock_remapped_to_ctrl.exchange(new_value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -9,6 +9,7 @@
|
||||||
#include <AK/Types.h>
|
#include <AK/Types.h>
|
||||||
#include <Kernel/FileSystem/SysFS/Subsystems/Kernel/Variables/BooleanVariable.h>
|
#include <Kernel/FileSystem/SysFS/Subsystems/Kernel/Variables/BooleanVariable.h>
|
||||||
#include <Kernel/Library/LockRefPtr.h>
|
#include <Kernel/Library/LockRefPtr.h>
|
||||||
|
#include <Kernel/Locking/Spinlock.h>
|
||||||
#include <Kernel/UserOrKernelBuffer.h>
|
#include <Kernel/UserOrKernelBuffer.h>
|
||||||
|
|
||||||
namespace Kernel {
|
namespace Kernel {
|
||||||
|
@ -24,7 +25,7 @@ private:
|
||||||
|
|
||||||
explicit SysFSCapsLockRemap(SysFSDirectory const&);
|
explicit SysFSCapsLockRemap(SysFSDirectory const&);
|
||||||
|
|
||||||
mutable Mutex m_lock;
|
mutable Spinlock m_lock { LockRank::None };
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,13 +22,13 @@ UNMAP_AFTER_INIT NonnullLockRefPtr<SysFSDumpKmallocStacks> SysFSDumpKmallocStack
|
||||||
|
|
||||||
bool SysFSDumpKmallocStacks::value() const
|
bool SysFSDumpKmallocStacks::value() const
|
||||||
{
|
{
|
||||||
MutexLocker locker(m_lock);
|
SpinlockLocker locker(m_lock);
|
||||||
return g_dump_kmalloc_stacks;
|
return g_dump_kmalloc_stacks;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SysFSDumpKmallocStacks::set_value(bool new_value)
|
void SysFSDumpKmallocStacks::set_value(bool new_value)
|
||||||
{
|
{
|
||||||
MutexLocker locker(m_lock);
|
SpinlockLocker locker(m_lock);
|
||||||
g_dump_kmalloc_stacks = new_value;
|
g_dump_kmalloc_stacks = new_value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -9,6 +9,7 @@
|
||||||
#include <AK/Types.h>
|
#include <AK/Types.h>
|
||||||
#include <Kernel/FileSystem/SysFS/Subsystems/Kernel/Variables/BooleanVariable.h>
|
#include <Kernel/FileSystem/SysFS/Subsystems/Kernel/Variables/BooleanVariable.h>
|
||||||
#include <Kernel/Library/LockRefPtr.h>
|
#include <Kernel/Library/LockRefPtr.h>
|
||||||
|
#include <Kernel/Locking/Spinlock.h>
|
||||||
#include <Kernel/UserOrKernelBuffer.h>
|
#include <Kernel/UserOrKernelBuffer.h>
|
||||||
|
|
||||||
namespace Kernel {
|
namespace Kernel {
|
||||||
|
@ -24,7 +25,7 @@ private:
|
||||||
|
|
||||||
explicit SysFSDumpKmallocStacks(SysFSDirectory const&);
|
explicit SysFSDumpKmallocStacks(SysFSDirectory const&);
|
||||||
|
|
||||||
mutable Mutex m_lock;
|
mutable Spinlock m_lock { LockRank::None };
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,6 +28,7 @@ class IPv4Socket;
|
||||||
class Inode;
|
class Inode;
|
||||||
class InodeIdentifier;
|
class InodeIdentifier;
|
||||||
class InodeWatcher;
|
class InodeWatcher;
|
||||||
|
class Jail;
|
||||||
class KBuffer;
|
class KBuffer;
|
||||||
class KString;
|
class KString;
|
||||||
class LocalSocket;
|
class LocalSocket;
|
||||||
|
|
34
Kernel/Jail.cpp
Normal file
34
Kernel/Jail.cpp
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2022, Liav A. <liavalb@hotmail.co.il>
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: BSD-2-Clause
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <Kernel/Jail.h>
|
||||||
|
|
||||||
|
namespace Kernel {
|
||||||
|
|
||||||
|
ErrorOr<NonnullLockRefPtr<Jail>> Jail::create(Badge<JailManagement>, NonnullOwnPtr<KString> name, JailIndex index)
|
||||||
|
{
|
||||||
|
return adopt_nonnull_lock_ref_or_enomem(new (nothrow) Jail(move(name), index));
|
||||||
|
}
|
||||||
|
|
||||||
|
Jail::Jail(NonnullOwnPtr<KString> name, JailIndex index)
|
||||||
|
: m_name(move(name))
|
||||||
|
, m_index(index)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void Jail::detach(Badge<Process>)
|
||||||
|
{
|
||||||
|
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();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
48
Kernel/Jail.h
Normal file
48
Kernel/Jail.h
Normal file
|
@ -0,0 +1,48 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2022, Liav A. <liavalb@hotmail.co.il>
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: BSD-2-Clause
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <AK/DistinctNumeric.h>
|
||||||
|
#include <AK/Error.h>
|
||||||
|
#include <AK/IntrusiveList.h>
|
||||||
|
#include <AK/OwnPtr.h>
|
||||||
|
#include <AK/RefPtr.h>
|
||||||
|
#include <AK/Try.h>
|
||||||
|
#include <AK/Types.h>
|
||||||
|
#include <Kernel/KString.h>
|
||||||
|
#include <Kernel/Library/LockRefPtr.h>
|
||||||
|
#include <Kernel/Locking/SpinlockProtected.h>
|
||||||
|
|
||||||
|
namespace Kernel {
|
||||||
|
|
||||||
|
class JailManagement;
|
||||||
|
|
||||||
|
AK_TYPEDEF_DISTINCT_ORDERED_ID(u64, JailIndex);
|
||||||
|
|
||||||
|
class Jail : public RefCounted<Jail> {
|
||||||
|
friend class JailManagement;
|
||||||
|
|
||||||
|
public:
|
||||||
|
static ErrorOr<NonnullLockRefPtr<Jail>> create(Badge<JailManagement>, NonnullOwnPtr<KString>, JailIndex);
|
||||||
|
|
||||||
|
StringView name() const { return m_name->view(); }
|
||||||
|
JailIndex index() const { return m_index; }
|
||||||
|
|
||||||
|
void detach(Badge<Process>);
|
||||||
|
SpinlockProtected<size_t>& attach_count() { return m_attach_count; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
Jail(NonnullOwnPtr<KString>, JailIndex);
|
||||||
|
|
||||||
|
NonnullOwnPtr<KString> m_name;
|
||||||
|
JailIndex const m_index;
|
||||||
|
|
||||||
|
IntrusiveListNode<Jail, NonnullLockRefPtr<Jail>> m_jail_list_node;
|
||||||
|
SpinlockProtected<size_t> m_attach_count { LockRank::None, 0 };
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
76
Kernel/JailManagement.cpp
Normal file
76
Kernel/JailManagement.cpp
Normal file
|
@ -0,0 +1,76 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2022, Liav A. <liavalb@hotmail.co.il>
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: BSD-2-Clause
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <AK/Singleton.h>
|
||||||
|
#include <Kernel/JailManagement.h>
|
||||||
|
#include <Kernel/Process.h>
|
||||||
|
#include <Kernel/Sections.h>
|
||||||
|
|
||||||
|
namespace Kernel {
|
||||||
|
|
||||||
|
static Singleton<JailManagement> s_the;
|
||||||
|
static Atomic<u64> 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<Jail> JailManagement::find_jail_by_index(JailIndex index)
|
||||||
|
{
|
||||||
|
return m_jails.with([&](auto& list) -> LockRefPtr<Jail> {
|
||||||
|
for (auto& jail : list) {
|
||||||
|
if (jail.index() == index)
|
||||||
|
return jail;
|
||||||
|
}
|
||||||
|
return {};
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
ErrorOr<void> JailManagement::for_each_in_same_jail(Function<ErrorOr<void>(Jail&)> callback)
|
||||||
|
{
|
||||||
|
return Process::current().jail().with([&](auto& my_jail) -> ErrorOr<void> {
|
||||||
|
// 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<void> {
|
||||||
|
for (auto& jail : list) {
|
||||||
|
TRY(callback(jail));
|
||||||
|
}
|
||||||
|
return {};
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
LockRefPtr<Jail> JailManagement::find_first_jail_by_name(StringView name)
|
||||||
|
{
|
||||||
|
return m_jails.with([&](auto& list) -> LockRefPtr<Jail> {
|
||||||
|
for (auto& jail : list) {
|
||||||
|
if (jail.name() == name)
|
||||||
|
return jail;
|
||||||
|
}
|
||||||
|
return {};
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
ErrorOr<NonnullLockRefPtr<Jail>> JailManagement::create_jail(NonnullOwnPtr<KString> name)
|
||||||
|
{
|
||||||
|
return m_jails.with([&](auto& list) -> ErrorOr<NonnullLockRefPtr<Jail>> {
|
||||||
|
auto jail = TRY(Jail::create({}, move(name), generate_jail_id()));
|
||||||
|
list.append(jail);
|
||||||
|
return jail;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
42
Kernel/JailManagement.h
Normal file
42
Kernel/JailManagement.h
Normal file
|
@ -0,0 +1,42 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2022, Liav A. <liavalb@hotmail.co.il>
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: BSD-2-Clause
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <AK/DistinctNumeric.h>
|
||||||
|
#include <AK/Error.h>
|
||||||
|
#include <AK/IntrusiveList.h>
|
||||||
|
#include <AK/OwnPtr.h>
|
||||||
|
#include <AK/RefPtr.h>
|
||||||
|
#include <AK/Try.h>
|
||||||
|
#include <AK/Types.h>
|
||||||
|
#include <Kernel/Jail.h>
|
||||||
|
#include <Kernel/KString.h>
|
||||||
|
#include <Kernel/Library/LockRefPtr.h>
|
||||||
|
#include <Kernel/Locking/SpinlockProtected.h>
|
||||||
|
|
||||||
|
namespace Kernel {
|
||||||
|
|
||||||
|
class JailManagement {
|
||||||
|
|
||||||
|
public:
|
||||||
|
JailManagement();
|
||||||
|
static JailManagement& the();
|
||||||
|
|
||||||
|
LockRefPtr<Jail> find_jail_by_index(JailIndex);
|
||||||
|
LockRefPtr<Jail> find_first_jail_by_name(StringView);
|
||||||
|
|
||||||
|
ErrorOr<NonnullLockRefPtr<Jail>> create_jail(NonnullOwnPtr<KString> name);
|
||||||
|
|
||||||
|
ErrorOr<void> for_each_in_same_jail(Function<ErrorOr<void>(Jail&)>);
|
||||||
|
|
||||||
|
private:
|
||||||
|
JailIndex generate_jail_id();
|
||||||
|
|
||||||
|
SpinlockProtected<IntrusiveList<&Jail::m_jail_list_node>> m_jails { LockRank::None };
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
|
@ -847,7 +847,7 @@ ErrorOr<CommittedPhysicalPageSet> MemoryManager::commit_physical_pages(size_t pa
|
||||||
return CommittedPhysicalPageSet { {}, page_count };
|
return CommittedPhysicalPageSet { {}, page_count };
|
||||||
});
|
});
|
||||||
if (result.is_error()) {
|
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_resident = 0;
|
||||||
size_t amount_shared = 0;
|
size_t amount_shared = 0;
|
||||||
size_t amount_virtual = 0;
|
size_t amount_virtual = 0;
|
||||||
|
|
|
@ -63,6 +63,95 @@ SpinlockProtected<Process::List>& Process::all_instances()
|
||||||
return *s_all_instances;
|
return *s_all_instances;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ErrorOr<void> Process::for_each_in_same_jail(Function<ErrorOr<void>(Process&)> callback)
|
||||||
|
{
|
||||||
|
ErrorOr<void> 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<void> Process::for_each_child_in_same_jail(Function<ErrorOr<void>(Process&)> callback)
|
||||||
|
{
|
||||||
|
ProcessID my_pid = pid();
|
||||||
|
ErrorOr<void> 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<void> Process::for_each_in_pgrp_in_same_jail(ProcessGroupID pgid, Function<ErrorOr<void>(Process&)> callback)
|
||||||
|
{
|
||||||
|
ErrorOr<void> 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()
|
ProcessID Process::allocate_pid()
|
||||||
{
|
{
|
||||||
// Overflow is UB, and negative PIDs wreck havoc.
|
// 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();
|
VERIFY_NOT_REACHED();
|
||||||
}
|
}
|
||||||
|
|
||||||
LockRefPtr<Process> Process::from_pid(ProcessID pid)
|
LockRefPtr<Process> Process::from_pid_in_same_jail(ProcessID pid)
|
||||||
|
{
|
||||||
|
return Process::current().jail().with([&](auto& my_jail) -> LockRefPtr<Process> {
|
||||||
|
return all_instances().with([&](auto const& list) -> LockRefPtr<Process> {
|
||||||
|
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<Process> {
|
||||||
|
if (other_process_jail.ptr() == my_jail.ptr())
|
||||||
|
return process;
|
||||||
|
return {};
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return {};
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
LockRefPtr<Process> Process::from_pid_ignoring_jails(ProcessID pid)
|
||||||
{
|
{
|
||||||
return all_instances().with([&](auto const& list) -> LockRefPtr<Process> {
|
return all_instances().with([&](auto const& list) -> LockRefPtr<Process> {
|
||||||
for (auto const& process : list) {
|
for (auto const& process : list) {
|
||||||
|
@ -657,20 +772,25 @@ void Process::finalize()
|
||||||
m_fds.with_exclusive([](auto& fds) { fds.clear(); });
|
m_fds.with_exclusive([](auto& fds) { fds.clear(); });
|
||||||
m_tty = nullptr;
|
m_tty = nullptr;
|
||||||
m_executable.with([](auto& executable) { executable = nullptr; });
|
m_executable.with([](auto& executable) { executable = nullptr; });
|
||||||
|
m_attached_jail.with([](auto& jail) {
|
||||||
|
if (jail)
|
||||||
|
jail->detach({});
|
||||||
|
jail = nullptr;
|
||||||
|
});
|
||||||
m_arguments.clear();
|
m_arguments.clear();
|
||||||
m_environment.clear();
|
m_environment.clear();
|
||||||
|
|
||||||
m_state.store(State::Dead, AK::MemoryOrder::memory_order_release);
|
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)
|
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);
|
(void)parent_process->send_signal(SIGCHLD, this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!!ppid()) {
|
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_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;
|
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<Process> waiter_process;
|
LockRefPtr<Process> waiter_process;
|
||||||
if (auto* my_tracer = tracer())
|
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
|
else
|
||||||
waiter_process = Process::from_pid(ppid());
|
waiter_process = Process::from_pid_ignoring_jails(ppid());
|
||||||
|
|
||||||
if (waiter_process)
|
if (waiter_process)
|
||||||
waiter_process->m_wait_blocker_set.unblock(*this, flags, signal);
|
waiter_process->m_wait_blocker_set.unblock(*this, flags, signal);
|
||||||
|
|
109
Kernel/Process.h
109
Kernel/Process.h
|
@ -24,6 +24,7 @@
|
||||||
#include <Kernel/FileSystem/UnveilNode.h>
|
#include <Kernel/FileSystem/UnveilNode.h>
|
||||||
#include <Kernel/Forward.h>
|
#include <Kernel/Forward.h>
|
||||||
#include <Kernel/FutexQueue.h>
|
#include <Kernel/FutexQueue.h>
|
||||||
|
#include <Kernel/Jail.h>
|
||||||
#include <Kernel/Library/LockWeakPtr.h>
|
#include <Kernel/Library/LockWeakPtr.h>
|
||||||
#include <Kernel/Library/LockWeakable.h>
|
#include <Kernel/Library/LockWeakable.h>
|
||||||
#include <Kernel/Library/NonnullLockRefPtrVector.h>
|
#include <Kernel/Library/NonnullLockRefPtrVector.h>
|
||||||
|
@ -70,6 +71,7 @@ Time kgettimeofday();
|
||||||
__ENUMERATE_PLEDGE_PROMISE(prot_exec) \
|
__ENUMERATE_PLEDGE_PROMISE(prot_exec) \
|
||||||
__ENUMERATE_PLEDGE_PROMISE(map_fixed) \
|
__ENUMERATE_PLEDGE_PROMISE(map_fixed) \
|
||||||
__ENUMERATE_PLEDGE_PROMISE(getkeymap) \
|
__ENUMERATE_PLEDGE_PROMISE(getkeymap) \
|
||||||
|
__ENUMERATE_PLEDGE_PROMISE(jail) \
|
||||||
__ENUMERATE_PLEDGE_PROMISE(no_error)
|
__ENUMERATE_PLEDGE_PROMISE(no_error)
|
||||||
|
|
||||||
enum class Pledge : u32 {
|
enum class Pledge : u32 {
|
||||||
|
@ -213,7 +215,8 @@ public:
|
||||||
bool is_kernel_process() const { return m_is_kernel_process; }
|
bool is_kernel_process() const { return m_is_kernel_process; }
|
||||||
bool is_user_process() const { return !m_is_kernel_process; }
|
bool is_user_process() const { return !m_is_kernel_process; }
|
||||||
|
|
||||||
static LockRefPtr<Process> from_pid(ProcessID);
|
static LockRefPtr<Process> from_pid_in_same_jail(ProcessID);
|
||||||
|
static LockRefPtr<Process> from_pid_ignoring_jails(ProcessID);
|
||||||
static SessionID get_sid_from_pgid(ProcessGroupID pgid);
|
static SessionID get_sid_from_pgid(ProcessGroupID pgid);
|
||||||
|
|
||||||
StringView name() const { return m_name->view(); }
|
StringView name() const { return m_name->view(); }
|
||||||
|
@ -233,6 +236,8 @@ public:
|
||||||
return with_protected_data([](auto& protected_data) { return protected_data.ppid; });
|
return with_protected_data([](auto& protected_data) { return protected_data.ppid; });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SpinlockProtected<RefPtr<Jail>>& jail() { return m_attached_jail; }
|
||||||
|
|
||||||
NonnullRefPtr<Credentials> credentials() const;
|
NonnullRefPtr<Credentials> credentials() const;
|
||||||
|
|
||||||
bool is_dumpable() const
|
bool is_dumpable() const
|
||||||
|
@ -248,11 +253,11 @@ public:
|
||||||
|
|
||||||
// Breakable iteration functions
|
// Breakable iteration functions
|
||||||
template<IteratorFunction<Process&> Callback>
|
template<IteratorFunction<Process&> Callback>
|
||||||
static void for_each(Callback);
|
static void for_each_ignoring_jails(Callback);
|
||||||
template<IteratorFunction<Process&> Callback>
|
|
||||||
static void for_each_in_pgrp(ProcessGroupID, Callback);
|
static ErrorOr<void> for_each_in_same_jail(Function<ErrorOr<void>(Process&)>);
|
||||||
template<IteratorFunction<Process&> Callback>
|
ErrorOr<void> for_each_in_pgrp_in_same_jail(ProcessGroupID, Function<ErrorOr<void>(Process&)>);
|
||||||
void for_each_child(Callback);
|
ErrorOr<void> for_each_child_in_same_jail(Function<ErrorOr<void>(Process&)>);
|
||||||
|
|
||||||
template<IteratorFunction<Thread&> Callback>
|
template<IteratorFunction<Thread&> Callback>
|
||||||
IterationDecision for_each_thread(Callback);
|
IterationDecision for_each_thread(Callback);
|
||||||
|
@ -262,11 +267,7 @@ public:
|
||||||
|
|
||||||
// Non-breakable iteration functions
|
// Non-breakable iteration functions
|
||||||
template<VoidFunction<Process&> Callback>
|
template<VoidFunction<Process&> Callback>
|
||||||
static void for_each(Callback);
|
static void for_each_ignoring_jails(Callback);
|
||||||
template<VoidFunction<Process&> Callback>
|
|
||||||
static void for_each_in_pgrp(ProcessGroupID, Callback);
|
|
||||||
template<VoidFunction<Process&> Callback>
|
|
||||||
void for_each_child(Callback);
|
|
||||||
|
|
||||||
template<VoidFunction<Thread&> Callback>
|
template<VoidFunction<Thread&> Callback>
|
||||||
IterationDecision for_each_thread(Callback);
|
IterationDecision for_each_thread(Callback);
|
||||||
|
@ -437,6 +438,8 @@ public:
|
||||||
ErrorOr<FlatPtr> sys$statvfs(Userspace<Syscall::SC_statvfs_params const*> user_params);
|
ErrorOr<FlatPtr> sys$statvfs(Userspace<Syscall::SC_statvfs_params const*> user_params);
|
||||||
ErrorOr<FlatPtr> sys$fstatvfs(int fd, statvfs* buf);
|
ErrorOr<FlatPtr> sys$fstatvfs(int fd, statvfs* buf);
|
||||||
ErrorOr<FlatPtr> sys$map_time_page();
|
ErrorOr<FlatPtr> sys$map_time_page();
|
||||||
|
ErrorOr<FlatPtr> sys$jail_create(Userspace<Syscall::SC_jail_create_params*> user_params);
|
||||||
|
ErrorOr<FlatPtr> sys$jail_attach(Userspace<Syscall::SC_jail_attach_params const*> user_params);
|
||||||
|
|
||||||
template<bool sockname, typename Params>
|
template<bool sockname, typename Params>
|
||||||
ErrorOr<void> get_sock_or_peer_name(Params const&);
|
ErrorOr<void> get_sock_or_peer_name(Params const&);
|
||||||
|
@ -862,6 +865,10 @@ private:
|
||||||
LockRefPtr<TTY> m_tty;
|
LockRefPtr<TTY> m_tty;
|
||||||
|
|
||||||
LockWeakPtr<Memory::Region> m_master_tls_region;
|
LockWeakPtr<Memory::Region> m_master_tls_region;
|
||||||
|
|
||||||
|
IntrusiveListNode<Process> m_jail_list_node;
|
||||||
|
SpinlockProtected<RefPtr<Jail>> m_attached_jail { LockRank::Process };
|
||||||
|
|
||||||
size_t m_master_tls_size { 0 };
|
size_t m_master_tls_size { 0 };
|
||||||
size_t m_master_tls_alignment { 0 };
|
size_t m_master_tls_alignment { 0 };
|
||||||
|
|
||||||
|
@ -914,48 +921,6 @@ static_assert(AssertSize<Process, (PAGE_SIZE * 2)>());
|
||||||
|
|
||||||
extern RecursiveSpinlock g_profiling_lock;
|
extern RecursiveSpinlock g_profiling_lock;
|
||||||
|
|
||||||
template<IteratorFunction<Process&> 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<IteratorFunction<Process&> 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<IteratorFunction<Thread&> 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<IteratorFunction<Thread&> Callback>
|
template<IteratorFunction<Thread&> Callback>
|
||||||
inline IterationDecision Process::for_each_thread(Callback callback)
|
inline IterationDecision Process::for_each_thread(Callback callback)
|
||||||
{
|
{
|
||||||
|
@ -970,34 +935,27 @@ inline IterationDecision Process::for_each_thread(Callback callback)
|
||||||
}
|
}
|
||||||
|
|
||||||
template<IteratorFunction<Process&> Callback>
|
template<IteratorFunction<Process&> 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) {
|
Process::all_instances().with([&](auto const& list) {
|
||||||
for (auto it = list.begin(); it != list.end();) {
|
for (auto it = list.begin(); it != list.end();) {
|
||||||
auto& process = *it;
|
auto& process = *it;
|
||||||
++it;
|
++it;
|
||||||
if (!process.is_dead() && process.pgid() == pgid) {
|
if (callback(process) == IterationDecision::Break)
|
||||||
if (callback(process) == IterationDecision::Break)
|
break;
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
template<VoidFunction<Process&> Callback>
|
template<IteratorFunction<Thread&> Callback>
|
||||||
inline void Process::for_each(Callback callback)
|
inline IterationDecision Process::for_each_thread(Callback callback) const
|
||||||
{
|
{
|
||||||
return for_each([&](auto& item) {
|
return thread_list().with([&](auto& thread_list) -> IterationDecision {
|
||||||
callback(item);
|
for (auto& thread : thread_list) {
|
||||||
return IterationDecision::Continue;
|
IterationDecision decision = callback(thread);
|
||||||
});
|
if (decision != IterationDecision::Continue)
|
||||||
}
|
return decision;
|
||||||
|
}
|
||||||
template<VoidFunction<Process&> Callback>
|
|
||||||
inline void Process::for_each_child(Callback callback)
|
|
||||||
{
|
|
||||||
return for_each_child([&](auto& item) {
|
|
||||||
callback(item);
|
|
||||||
return IterationDecision::Continue;
|
return IterationDecision::Continue;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -1031,15 +989,6 @@ inline IterationDecision Process::for_each_thread(Callback callback)
|
||||||
return IterationDecision::Continue;
|
return IterationDecision::Continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<VoidFunction<Process&> 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
|
inline ProcessID Thread::pid() const
|
||||||
{
|
{
|
||||||
return m_process->pid();
|
return m_process->pid();
|
||||||
|
|
|
@ -206,14 +206,12 @@ ErrorOr<void> ProcFSRootDirectory::traverse_as_directory(FileSystemID fsid, Func
|
||||||
TRY(callback({ component.name(), identifier, 0 }));
|
TRY(callback({ component.name(), identifier, 0 }));
|
||||||
}
|
}
|
||||||
|
|
||||||
return Process::all_instances().with([&](auto& list) -> ErrorOr<void> {
|
return Process::for_each_in_same_jail([&](Process& process) -> ErrorOr<void> {
|
||||||
for (auto& process : list) {
|
VERIFY(!(process.pid() < 0));
|
||||||
VERIFY(!(process.pid() < 0));
|
u64 process_id = (u64)process.pid().value();
|
||||||
u64 process_id = (u64)process.pid().value();
|
InodeIdentifier identifier = { fsid, static_cast<InodeIndex>(process_id << 36) };
|
||||||
InodeIdentifier identifier = { fsid, static_cast<InodeIndex>(process_id << 36) };
|
auto process_id_string = TRY(KString::formatted("{:d}", process_id));
|
||||||
auto process_id_string = TRY(KString::formatted("{:d}", process_id));
|
TRY(callback({ process_id_string->view(), identifier, 0 }));
|
||||||
TRY(callback({ process_id_string->view(), identifier, 0 }));
|
|
||||||
}
|
|
||||||
return {};
|
return {};
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -234,7 +232,7 @@ ErrorOr<NonnullLockRefPtr<ProcFSExposedComponent>> ProcFSRootDirectory::lookup(S
|
||||||
return ESRCH;
|
return ESRCH;
|
||||||
auto actual_pid = pid.value();
|
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 maybe_process->procfs_traits();
|
||||||
|
|
||||||
return ENOENT;
|
return ENOENT;
|
||||||
|
|
|
@ -85,13 +85,11 @@ ErrorOr<void> Process::traverse_children_directory(FileSystemID fsid, Function<E
|
||||||
{
|
{
|
||||||
TRY(callback({ "."sv, { fsid, SegmentedProcFSIndex::build_segmented_index_for_sub_directory(pid(), SegmentedProcFSIndex::ProcessSubDirectory::Children) }, 0 }));
|
TRY(callback({ "."sv, { fsid, SegmentedProcFSIndex::build_segmented_index_for_sub_directory(pid(), SegmentedProcFSIndex::ProcessSubDirectory::Children) }, 0 }));
|
||||||
TRY(callback({ ".."sv, { fsid, m_procfs_traits->component_index() }, 0 }));
|
TRY(callback({ ".."sv, { fsid, m_procfs_traits->component_index() }, 0 }));
|
||||||
return Process::all_instances().with([&](auto& processes) -> ErrorOr<void> {
|
return Process::for_each_in_same_jail([&](Process& process) -> ErrorOr<void> {
|
||||||
for (auto& process : processes) {
|
if (process.ppid() == pid()) {
|
||||||
if (process.ppid() == pid()) {
|
StringBuilder builder;
|
||||||
StringBuilder builder;
|
builder.appendff("{}", process.pid());
|
||||||
builder.appendff("{}", process.pid());
|
TRY(callback({ builder.string_view(), { fsid, SegmentedProcFSIndex::build_segmented_index_for_children(pid(), process.pid()) }, DT_LNK }));
|
||||||
TRY(callback({ builder.string_view(), { fsid, SegmentedProcFSIndex::build_segmented_index_for_children(pid(), process.pid()) }, DT_LNK }));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return {};
|
return {};
|
||||||
});
|
});
|
||||||
|
@ -103,7 +101,7 @@ ErrorOr<NonnullLockRefPtr<Inode>> Process::lookup_children_directory(ProcFS cons
|
||||||
if (!maybe_pid.has_value())
|
if (!maybe_pid.has_value())
|
||||||
return ENOENT;
|
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())
|
if (!child_process || child_process->ppid() != pid())
|
||||||
return ENOENT;
|
return ENOENT;
|
||||||
|
|
||||||
|
|
|
@ -12,7 +12,7 @@ ErrorOr<FlatPtr> Process::sys$disown(ProcessID pid)
|
||||||
{
|
{
|
||||||
VERIFY_PROCESS_BIG_LOCK_ACQUIRED(this);
|
VERIFY_PROCESS_BIG_LOCK_ACQUIRED(this);
|
||||||
TRY(require_promise(Pledge::proc));
|
TRY(require_promise(Pledge::proc));
|
||||||
auto process = Process::from_pid(pid);
|
auto process = Process::from_pid_in_same_jail(pid);
|
||||||
if (!process)
|
if (!process)
|
||||||
return ESRCH;
|
return ESRCH;
|
||||||
if (process->ppid() != this->pid())
|
if (process->ppid() != this->pid())
|
||||||
|
|
|
@ -495,6 +495,7 @@ ErrorOr<void> Process::do_exec(NonnullLockRefPtr<OpenFileDescription> main_progr
|
||||||
|
|
||||||
auto old_credentials = this->credentials();
|
auto old_credentials = this->credentials();
|
||||||
auto new_credentials = old_credentials;
|
auto new_credentials = old_credentials;
|
||||||
|
auto old_process_attached_jail = m_attached_jail.with([&](auto& jail) -> RefPtr<Jail> { return jail; });
|
||||||
|
|
||||||
bool executable_is_setid = false;
|
bool executable_is_setid = false;
|
||||||
|
|
||||||
|
@ -553,6 +554,9 @@ ErrorOr<void> Process::do_exec(NonnullLockRefPtr<OpenFileDescription> main_progr
|
||||||
|
|
||||||
m_executable.with([&](auto& executable) { executable = main_program_description->custody(); });
|
m_executable.with([&](auto& executable) { executable = main_program_description->custody(); });
|
||||||
m_arguments = move(arguments);
|
m_arguments = move(arguments);
|
||||||
|
m_attached_jail.with([&](auto& jail) {
|
||||||
|
jail = old_process_attached_jail;
|
||||||
|
});
|
||||||
m_environment = move(environment);
|
m_environment = move(environment);
|
||||||
|
|
||||||
TRY(m_unveil_data.with([&](auto& unveil_data) -> ErrorOr<void> {
|
TRY(m_unveil_data.with([&](auto& unveil_data) -> ErrorOr<void> {
|
||||||
|
|
|
@ -42,6 +42,26 @@ ErrorOr<FlatPtr> 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<void> {
|
||||||
|
TRY(m_attached_jail.with([&](auto& parent_jail) -> ErrorOr<void> {
|
||||||
|
return child->m_attached_jail.with([&](auto& child_jail) -> ErrorOr<void> {
|
||||||
|
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) {
|
TRY(child->m_fds.with_exclusive([&](auto& child_fds) {
|
||||||
return m_fds.with_exclusive([&](auto& parent_fds) {
|
return m_fds.with_exclusive([&](auto& parent_fds) {
|
||||||
return child_fds.try_clone(parent_fds);
|
return child_fds.try_clone(parent_fds);
|
||||||
|
|
59
Kernel/Syscalls/jail.cpp
Normal file
59
Kernel/Syscalls/jail.cpp
Normal file
|
@ -0,0 +1,59 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: BSD-2-Clause
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <AK/Userspace.h>
|
||||||
|
#include <Kernel/Jail.h>
|
||||||
|
#include <Kernel/JailManagement.h>
|
||||||
|
#include <Kernel/Process.h>
|
||||||
|
#include <Kernel/StdLib.h>
|
||||||
|
#include <LibC/sys/ioctl_numbers.h>
|
||||||
|
|
||||||
|
namespace Kernel {
|
||||||
|
|
||||||
|
constexpr size_t jail_name_max_size = 50;
|
||||||
|
|
||||||
|
ErrorOr<FlatPtr> Process::sys$jail_create(Userspace<Syscall::SC_jail_create_params*> 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<FlatPtr> Process::sys$jail_attach(Userspace<Syscall::SC_jail_attach_params const*> 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<FlatPtr> {
|
||||||
|
// 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<JailIndex>(params.index));
|
||||||
|
if (!jail)
|
||||||
|
return EINVAL;
|
||||||
|
my_jail = *jail;
|
||||||
|
my_jail->attach_count().with([&](auto& attach_count) {
|
||||||
|
attach_count++;
|
||||||
|
});
|
||||||
|
return 0;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -42,7 +42,7 @@ ErrorOr<void> Process::do_killpg(ProcessGroupID pgrp, int signal)
|
||||||
bool any_succeeded = false;
|
bool any_succeeded = false;
|
||||||
ErrorOr<void> error;
|
ErrorOr<void> error;
|
||||||
|
|
||||||
Process::for_each_in_pgrp(pgrp, [&](auto& process) {
|
TRY(Process::current().for_each_in_pgrp_in_same_jail(pgrp, [&](auto& process) -> ErrorOr<void> {
|
||||||
group_was_empty = false;
|
group_was_empty = false;
|
||||||
|
|
||||||
ErrorOr<void> res = do_kill(process, signal);
|
ErrorOr<void> res = do_kill(process, signal);
|
||||||
|
@ -50,7 +50,8 @@ ErrorOr<void> Process::do_killpg(ProcessGroupID pgrp, int signal)
|
||||||
any_succeeded = true;
|
any_succeeded = true;
|
||||||
else
|
else
|
||||||
error = move(res);
|
error = move(res);
|
||||||
});
|
return {};
|
||||||
|
}));
|
||||||
|
|
||||||
if (group_was_empty)
|
if (group_was_empty)
|
||||||
return ESRCH;
|
return ESRCH;
|
||||||
|
@ -67,7 +68,7 @@ ErrorOr<void> Process::do_killall(int signal)
|
||||||
ErrorOr<void> error;
|
ErrorOr<void> error;
|
||||||
|
|
||||||
// Send the signal to all processes we have access to for.
|
// 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<void> {
|
||||||
ErrorOr<void> res;
|
ErrorOr<void> res;
|
||||||
if (process.pid() == pid())
|
if (process.pid() == pid())
|
||||||
res = do_killself(signal);
|
res = do_killself(signal);
|
||||||
|
@ -78,7 +79,8 @@ ErrorOr<void> Process::do_killall(int signal)
|
||||||
any_succeeded = true;
|
any_succeeded = true;
|
||||||
else
|
else
|
||||||
error = move(res);
|
error = move(res);
|
||||||
});
|
return {};
|
||||||
|
}));
|
||||||
|
|
||||||
if (any_succeeded)
|
if (any_succeeded)
|
||||||
return {};
|
return {};
|
||||||
|
@ -122,7 +124,7 @@ ErrorOr<FlatPtr> Process::sys$kill(pid_t pid_or_pgid, int signal)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
VERIFY(pid_or_pgid >= 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)
|
if (!peer)
|
||||||
return ESRCH;
|
return ESRCH;
|
||||||
TRY(do_kill(*peer, signal));
|
TRY(do_kill(*peer, signal));
|
||||||
|
|
|
@ -53,15 +53,15 @@ ErrorOr<FlatPtr> Process::profiling_enable(pid_t pid, u64 event_mask)
|
||||||
return ENOTSUP;
|
return ENOTSUP;
|
||||||
g_profiling_all_threads = true;
|
g_profiling_all_threads = true;
|
||||||
PerformanceManager::add_process_created_event(*Scheduler::colonel());
|
PerformanceManager::add_process_created_event(*Scheduler::colonel());
|
||||||
Process::for_each([](auto& process) {
|
TRY(Process::for_each_in_same_jail([](auto& process) -> ErrorOr<void> {
|
||||||
PerformanceManager::add_process_created_event(process);
|
PerformanceManager::add_process_created_event(process);
|
||||||
return IterationDecision::Continue;
|
return {};
|
||||||
});
|
}));
|
||||||
g_profiling_event_mask = event_mask;
|
g_profiling_event_mask = event_mask;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto process = Process::from_pid(pid);
|
auto process = Process::from_pid_in_same_jail(pid);
|
||||||
if (!process)
|
if (!process)
|
||||||
return ESRCH;
|
return ESRCH;
|
||||||
if (process->is_dead())
|
if (process->is_dead())
|
||||||
|
@ -101,7 +101,7 @@ ErrorOr<FlatPtr> Process::sys$profiling_disable(pid_t pid)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto process = Process::from_pid(pid);
|
auto process = Process::from_pid_in_same_jail(pid);
|
||||||
if (!process)
|
if (!process)
|
||||||
return ESRCH;
|
return ESRCH;
|
||||||
auto credentials = this->credentials();
|
auto credentials = this->credentials();
|
||||||
|
@ -140,7 +140,7 @@ ErrorOr<FlatPtr> Process::sys$profiling_free_buffer(pid_t pid)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto process = Process::from_pid(pid);
|
auto process = Process::from_pid_in_same_jail(pid);
|
||||||
if (!process)
|
if (!process)
|
||||||
return ESRCH;
|
return ESRCH;
|
||||||
auto credentials = this->credentials();
|
auto credentials = this->credentials();
|
||||||
|
|
|
@ -38,7 +38,7 @@ ErrorOr<NonnullRefPtr<Thread>> Process::get_thread_from_pid_or_tid(pid_t pid_or_
|
||||||
case Syscall::SchedulerParametersMode::Process: {
|
case Syscall::SchedulerParametersMode::Process: {
|
||||||
auto* searched_process = this;
|
auto* searched_process = this;
|
||||||
if (pid_or_tid != 0)
|
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)
|
if (searched_process == nullptr)
|
||||||
return ESRCH;
|
return ESRCH;
|
||||||
|
|
|
@ -16,7 +16,7 @@ ErrorOr<FlatPtr> Process::sys$getsid(pid_t pid)
|
||||||
TRY(require_promise(Pledge::stdio));
|
TRY(require_promise(Pledge::stdio));
|
||||||
if (pid == 0)
|
if (pid == 0)
|
||||||
return sid().value();
|
return sid().value();
|
||||||
auto process = Process::from_pid(pid);
|
auto process = Process::from_pid_in_same_jail(pid);
|
||||||
if (!process)
|
if (!process)
|
||||||
return ESRCH;
|
return ESRCH;
|
||||||
if (sid() != process->sid())
|
if (sid() != process->sid())
|
||||||
|
@ -30,10 +30,10 @@ ErrorOr<FlatPtr> Process::sys$setsid()
|
||||||
TRY(require_promise(Pledge::proc));
|
TRY(require_promise(Pledge::proc));
|
||||||
InterruptDisabler disabler;
|
InterruptDisabler disabler;
|
||||||
bool found_process_with_same_pgid_as_my_pid = false;
|
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<void> {
|
||||||
found_process_with_same_pgid_as_my_pid = true;
|
found_process_with_same_pgid_as_my_pid = true;
|
||||||
return IterationDecision::Break;
|
return {};
|
||||||
});
|
}));
|
||||||
if (found_process_with_same_pgid_as_my_pid)
|
if (found_process_with_same_pgid_as_my_pid)
|
||||||
return EPERM;
|
return EPERM;
|
||||||
// Create a new Session and a new ProcessGroup.
|
// Create a new Session and a new ProcessGroup.
|
||||||
|
@ -52,7 +52,7 @@ ErrorOr<FlatPtr> Process::sys$getpgid(pid_t pid)
|
||||||
TRY(require_promise(Pledge::stdio));
|
TRY(require_promise(Pledge::stdio));
|
||||||
if (pid == 0)
|
if (pid == 0)
|
||||||
return pgid().value();
|
return pgid().value();
|
||||||
auto process = Process::from_pid(pid);
|
auto process = Process::from_pid_in_same_jail(pid);
|
||||||
if (!process)
|
if (!process)
|
||||||
return ESRCH;
|
return ESRCH;
|
||||||
return process->pgid().value();
|
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.
|
// FIXME: This xor sys$setsid() uses the wrong locking mechanism.
|
||||||
|
|
||||||
SessionID sid { -1 };
|
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<void> {
|
||||||
sid = process.sid();
|
sid = process.sid();
|
||||||
return IterationDecision::Break;
|
return {};
|
||||||
});
|
}));
|
||||||
|
|
||||||
return sid;
|
return sid;
|
||||||
}
|
}
|
||||||
|
@ -87,7 +87,7 @@ ErrorOr<FlatPtr> 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.
|
// The value of the pgid argument is less than 0, or is not a value supported by the implementation.
|
||||||
return EINVAL;
|
return EINVAL;
|
||||||
}
|
}
|
||||||
auto process = Process::from_pid(pid);
|
auto process = Process::from_pid_in_same_jail(pid);
|
||||||
if (!process)
|
if (!process)
|
||||||
return ESRCH;
|
return ESRCH;
|
||||||
if (process != this && process->ppid() != this->pid()) {
|
if (process != this && process->ppid() != this->pid()) {
|
||||||
|
|
|
@ -30,7 +30,7 @@ ErrorOr<FlatPtr> Process::sys$waitid(Userspace<Syscall::SC_waitid_params const*>
|
||||||
case P_ALL:
|
case P_ALL:
|
||||||
break;
|
break;
|
||||||
case P_PID: {
|
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)
|
if (!waitee_process)
|
||||||
return ECHILD;
|
return ECHILD;
|
||||||
bool waitee_is_child = waitee_process->ppid() == Process::current().pid();
|
bool waitee_is_child = waitee_process->ppid() == Process::current().pid();
|
||||||
|
|
|
@ -359,11 +359,12 @@ void TTY::generate_signal(int signal)
|
||||||
flush_input();
|
flush_input();
|
||||||
dbgln_if(TTY_DEBUG, "Send signal {} to everyone in pgrp {}", signal, pgid().value());
|
dbgln_if(TTY_DEBUG, "Send signal {} to everyone in pgrp {}", signal, pgid().value());
|
||||||
InterruptDisabler disabler; // FIXME: Iterate over a set of process handles instead?
|
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<void> {
|
||||||
dbgln_if(TTY_DEBUG, "Send signal {} to {}", signal, process);
|
dbgln_if(TTY_DEBUG, "Send signal {} to {}", signal, process);
|
||||||
// FIXME: Should this error be propagated somehow?
|
// FIXME: Should this error be propagated somehow?
|
||||||
[[maybe_unused]] auto rc = process.send_signal(signal, nullptr);
|
[[maybe_unused]] auto rc = process.send_signal(signal, nullptr);
|
||||||
});
|
return {};
|
||||||
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
void TTY::flush_input()
|
void TTY::flush_input()
|
||||||
|
@ -493,7 +494,7 @@ ErrorOr<void> TTY::ioctl(OpenFileDescription&, unsigned request, Userspace<void*
|
||||||
if (!process_group)
|
if (!process_group)
|
||||||
return EINVAL;
|
return EINVAL;
|
||||||
|
|
||||||
auto process = Process::from_pid(ProcessID(pgid.value()));
|
auto process = Process::from_pid_in_same_jail(ProcessID(pgid.value()));
|
||||||
SessionID new_sid = process ? process->sid() : Process::get_sid_from_pgid(pgid);
|
SessionID new_sid = process ? process->sid() : Process::get_sid_from_pgid(pgid);
|
||||||
if (!new_sid || new_sid != current_process.sid())
|
if (!new_sid || new_sid != current_process.sid())
|
||||||
return EPERM;
|
return EPERM;
|
||||||
|
@ -502,7 +503,7 @@ ErrorOr<void> TTY::ioctl(OpenFileDescription&, unsigned request, Userspace<void*
|
||||||
m_pg = process_group;
|
m_pg = process_group;
|
||||||
|
|
||||||
if (process) {
|
if (process) {
|
||||||
if (auto parent = Process::from_pid(process->ppid())) {
|
if (auto parent = Process::from_pid_ignoring_jails(process->ppid())) {
|
||||||
m_original_process_parent = *parent;
|
m_original_process_parent = *parent;
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
|
@ -978,7 +978,7 @@ DispatchSignalResult Thread::dispatch_signal(u8 signal)
|
||||||
|
|
||||||
auto& action = m_process->m_signal_action_data[signal];
|
auto& action = m_process->m_signal_action_data[signal];
|
||||||
auto sender_pid = m_signal_senders[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()) {
|
if (!current_trap() && !action.handler_or_sigaction.is_null()) {
|
||||||
// We're trying dispatch a handled signal to a user process that was scheduled
|
// 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);
|
process.unblock_waiters(Thread::WaitBlocker::UnblockFlags::Continued);
|
||||||
// Tell the parent process (if any) about this change.
|
// 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);
|
[[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);
|
process.unblock_waiters(Thread::WaitBlocker::UnblockFlags::Stopped, stop_signal);
|
||||||
// Tell the parent process (if any) about this change.
|
// 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);
|
[[maybe_unused]] auto result = parent->send_signal(SIGCHLD, &process);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue