Kernel: Introduce the HostnameContext class

Similarly to VFSRootContext and ScopedProcessList, this class intends
to form resource isolation as well.
We add this class as an infrastructure preparation of hostname contexts
which should allow processes to obtain different hostnames on the same
machine.
This commit is contained in:
Liav A. 2024-02-02 18:38:14 +02:00 committed by Tim Schumacher
parent 3692af528e
commit e52abd4c09
10 changed files with 210 additions and 42 deletions

View file

@ -56,6 +56,7 @@
#include <Kernel/Sections.h>
#include <Kernel/Security/Random.h>
#include <Kernel/Tasks/FinalizerTask.h>
#include <Kernel/Tasks/HostnameContext.h>
#include <Kernel/Tasks/Process.h>
#include <Kernel/Tasks/Scheduler.h>
#include <Kernel/Tasks/SyncTask.h>
@ -470,6 +471,11 @@ void init_stage2(void*)
// NOTE: Everything in the .ksyms section becomes read-only after this point.
MM.protect_ksyms_after_init();
auto hostname_context_or_error = HostnameContext::create_initial();
if (hostname_context_or_error.is_error())
PANIC("init_stage2: Error creating initial hostname context: {}", hostname_context_or_error.error());
auto hostname_context = hostname_context_or_error.release_value();
// NOTE: Everything marked UNMAP_AFTER_INIT becomes inaccessible after this point.
MM.unmap_text_after_init();
@ -478,7 +484,8 @@ void init_stage2(void*)
dmesgln("Running first user process: {}", userspace_init);
dmesgln("Init (first) process args: {}", init_args);
auto init_or_error = Process::create_user_process(userspace_init, UserID(0), GroupID(0), move(init_args), {}, move(first_process_vfs_context), tty0);
auto init_or_error = Process::create_user_process(userspace_init, UserID(0), GroupID(0), move(init_args), {}, move(first_process_vfs_context), move(hostname_context), tty0);
if (init_or_error.is_error())
PANIC("init_stage2: Error spawning init process: {}", init_or_error.error());

View file

@ -366,6 +366,7 @@ set(KERNEL_SOURCES
Tasks/CrashHandler.cpp
Tasks/FinalizerTask.cpp
Tasks/FutexQueue.cpp
Tasks/HostnameContext.cpp
Tasks/PerformanceEventBuffer.cpp
Tasks/PowerStateSwitchTask.cpp
Tasks/Process.cpp

View file

@ -29,6 +29,7 @@ class OpenFileDescription;
class DisplayConnector;
class FileSystem;
class FutexQueue;
class HostnameContext;
class IPv4Socket;
class Inode;
class InodeIdentifier;

View file

@ -22,7 +22,7 @@ ErrorOr<FlatPtr> Process::sys$fork(RegisterState& regs)
TRY(require_promise(Pledge::proc));
auto credentials = this->credentials();
auto child_and_first_thread = TRY(Process::create_with_forked_name(credentials->uid(), credentials->gid(), pid(), m_is_kernel_process, vfs_root_context(), current_directory(), executable(), tty(), this));
auto child_and_first_thread = TRY(Process::create_with_forked_name(credentials->uid(), credentials->gid(), pid(), m_is_kernel_process, vfs_root_context(), hostname_context(), current_directory(), executable(), tty(), this));
auto& child = child_and_first_thread.process;
auto& child_first_thread = child_and_first_thread.first_thread;

View file

@ -14,17 +14,19 @@ ErrorOr<FlatPtr> Process::sys$gethostname(Userspace<char*> buffer, size_t size)
TRY(require_promise(Pledge::stdio));
if (size > NumericLimits<ssize_t>::max())
return EINVAL;
return hostname().with_shared([&](auto const& name) -> ErrorOr<FlatPtr> {
// NOTE: To be able to copy a null-terminated string, we need at most
// 65 characters to store and copy and not 64 here, to store the whole
// hostname string + null terminator.
FixedStringBuffer<UTSNAME_ENTRY_LEN> current_hostname {};
current_hostname.store_characters(name.representable_view());
auto name_view = current_hostname.representable_view();
if (size < (name_view.length() + 1))
return ENAMETOOLONG;
TRY(copy_to_user(buffer, name_view.characters_without_null_termination(), name_view.length() + 1));
return 0;
return m_attached_hostname_context.with([&](auto const& hostname_context_ptr) -> ErrorOr<FlatPtr> {
return hostname_context_ptr->buffer().with([&](auto const& name_buffer) -> ErrorOr<FlatPtr> {
// NOTE: To be able to copy a null-terminated string, we need at most
// 65 characters to store and copy and not 64 here, to store the whole
// hostname string + null terminator.
FixedStringBuffer<UTSNAME_ENTRY_LEN> current_hostname {};
current_hostname.store_characters(name_buffer.representable_view());
auto name_view = current_hostname.representable_view();
if (size < (name_view.length() + 1))
return ENAMETOOLONG;
TRY(copy_to_user(buffer, name_view.characters_without_null_termination(), name_view.length() + 1));
return 0;
});
});
}
@ -37,8 +39,10 @@ ErrorOr<FlatPtr> Process::sys$sethostname(Userspace<char const*> buffer, size_t
if (!credentials->is_superuser())
return EPERM;
auto new_hostname = TRY(get_syscall_name_string_fixed_buffer<UTSNAME_ENTRY_LEN - 1>(buffer, length));
hostname().with_exclusive([&](auto& name) {
name.store_characters(new_hostname.representable_view());
m_attached_hostname_context.with([&](auto& hostname_context_ptr) {
hostname_context_ptr->buffer().with([&](auto& name_buffer) {
name_buffer.store_characters(new_hostname.representable_view());
});
});
return 0;
}

View file

@ -41,11 +41,13 @@ ErrorOr<FlatPtr> Process::sys$uname(Userspace<utsname*> user_buf)
AK::TypedTransfer<u8>::copy(reinterpret_cast<u8*>(buf.version), SERENITY_VERSION.bytes().data(), min(SERENITY_VERSION.length(), UTSNAME_ENTRY_LEN - 1));
hostname().with_shared([&](auto const& name) {
auto name_length = name.representable_view().length();
VERIFY(name_length <= (UTSNAME_ENTRY_LEN - 1));
AK::TypedTransfer<char>::copy(reinterpret_cast<char*>(buf.nodename), name.representable_view().characters_without_null_termination(), name_length);
buf.nodename[name_length] = '\0';
m_attached_hostname_context.with([&](auto const& hostname_context_ptr) {
hostname_context_ptr->buffer().with([&](auto& name_buffer) {
auto name_length = name_buffer.representable_view().length();
VERIFY(name_length <= (UTSNAME_ENTRY_LEN - 1));
AK::TypedTransfer<char>::copy(reinterpret_cast<char*>(buf.nodename), name_buffer.representable_view().characters_without_null_termination(), name_length);
buf.nodename[name_length] = '\0';
});
});
TRY(copy_to_user(user_buf, &buf));

View file

@ -0,0 +1,81 @@
/*
* Copyright (c) 2024, Liav A. <liavalb@hotmail.co.il>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <AK/Atomic.h>
#include <AK/Singleton.h>
#include <Kernel/Sections.h>
#include <Kernel/Tasks/HostnameContext.h>
namespace Kernel {
static Atomic<u64> s_hostname_context_id = 0;
static Singleton<SpinlockProtected<HostnameContext::List, LockRank::None>> s_all_instances {};
UNMAP_AFTER_INIT ErrorOr<NonnullRefPtr<HostnameContext>> HostnameContext::create_initial()
{
return create_with_name("courage"sv);
}
ErrorOr<NonnullRefPtr<HostnameContext>> HostnameContext::create_with_name(StringView name)
{
return s_all_instances->with([&](auto& list) -> ErrorOr<NonnullRefPtr<HostnameContext>> {
auto hostname_context = TRY(adopt_nonnull_ref_or_enomem(new (nothrow) HostnameContext(name)));
list.append(hostname_context);
return hostname_context;
});
}
ErrorOr<NonnullRefPtr<HostnameContext>> HostnameContext::hostname_context_for_id(int id)
{
if (id < 0)
return Error::from_errno(EINVAL);
auto index = static_cast<IndexID>(id);
return s_all_instances->with([&](auto& list) -> ErrorOr<NonnullRefPtr<HostnameContext>> {
for (auto& hostname_context : list) {
if (hostname_context.id() == index)
return hostname_context;
}
return Error::from_errno(ESRCNOTFOUND);
});
}
void HostnameContext::set_attached(Badge<Process>)
{
m_attach_count.with([&](auto& my_attach_count) {
my_attach_count++;
s_all_instances->with([&](auto& list) {
// NOTE: It could happen that we have been detached from the
// global list but a Process got a reference and wants to
// attach so now re-attach this context.
if (!list.contains(*this))
list.append(*this);
});
});
}
void HostnameContext::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) {
s_all_instances->with([&](auto&) {
m_list_node.remove();
});
}
});
}
HostnameContext::HostnameContext(StringView name)
: m_id(s_hostname_context_id.fetch_add(1))
{
m_buffer.with([name](auto& buffer) {
buffer.store_characters(name);
});
}
}

View file

@ -0,0 +1,56 @@
/*
* Copyright (c) 2024, Liav A. <liavalb@hotmail.co.il>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#pragma once
#include <AK/AtomicRefCounted.h>
#include <AK/FixedStringBuffer.h>
#include <AK/IntrusiveList.h>
#include <AK/IntrusiveListRelaxedConst.h>
#include <AK/Noncopyable.h>
#include <AK/RefPtr.h>
#include <Kernel/API/POSIX/sys/utsname.h>
#include <Kernel/Forward.h>
#include <Kernel/Locking/SpinlockProtected.h>
namespace Kernel {
class HostnameContext : public AtomicRefCounted<HostnameContext> {
AK_MAKE_NONCOPYABLE(HostnameContext);
AK_MAKE_NONMOVABLE(HostnameContext);
friend class Process;
public:
AK_TYPEDEF_DISTINCT_ORDERED_ID(u64, IndexID);
static ErrorOr<NonnullRefPtr<HostnameContext>> create_initial();
static ErrorOr<NonnullRefPtr<HostnameContext>> create_with_name(StringView name);
static ErrorOr<NonnullRefPtr<HostnameContext>> hostname_context_for_id(int id);
SpinlockProtected<FixedStringBuffer<UTSNAME_ENTRY_LEN - 1>, LockRank::None>& buffer() { return m_buffer; }
SpinlockProtected<FixedStringBuffer<UTSNAME_ENTRY_LEN - 1>, LockRank::None> const& buffer() const { return m_buffer; }
IndexID id() const { return m_id; }
void detach(Badge<Process>);
void set_attached(Badge<Process>);
private:
HostnameContext(StringView name);
IntrusiveListNode<HostnameContext, NonnullRefPtr<HostnameContext>> m_list_node;
SpinlockProtected<size_t, LockRank::None> m_attach_count { 0 };
SpinlockProtected<FixedStringBuffer<UTSNAME_ENTRY_LEN - 1>, LockRank::None> m_buffer;
IndexID m_id;
public:
using List = IntrusiveListRelaxedConst<&HostnameContext::m_list_node>;
};
}

View file

@ -31,6 +31,7 @@
#include <Kernel/Sections.h>
#include <Kernel/Security/Credentials.h>
#include <Kernel/Tasks/Coredump.h>
#include <Kernel/Tasks/HostnameContext.h>
#include <Kernel/Tasks/PerformanceEventBuffer.h>
#include <Kernel/Tasks/PerformanceManager.h>
#include <Kernel/Tasks/Process.h>
@ -54,12 +55,7 @@ static Atomic<pid_t> next_pid;
static Singleton<SpinlockProtected<Process::AllProcessesList, LockRank::None>> s_all_instances;
READONLY_AFTER_INIT Memory::Region* g_signal_trampoline_region;
static Singleton<MutexProtected<FixedStringBuffer<UTSNAME_ENTRY_LEN - 1>>> s_hostname;
MutexProtected<FixedStringBuffer<UTSNAME_ENTRY_LEN - 1>>& hostname()
{
return *s_hostname;
}
static RawPtr<HostnameContext> s_empty_kernel_hostname_context;
SpinlockProtected<Process::AllProcessesList, LockRank::None>& Process::all_instances()
{
@ -160,9 +156,9 @@ UNMAP_AFTER_INIT void Process::initialize()
{
next_pid.store(0, AK::MemoryOrder::memory_order_release);
// Note: This is called before scheduling is initialized, and before APs are booted.
// So we can "safely" bypass the lock here.
reinterpret_cast<FixedStringBuffer<UTSNAME_ENTRY_LEN - 1>&>(hostname()).store_characters("courage"sv);
// NOTE: Initialize an empty hostname context for all kernel processes.
s_empty_kernel_hostname_context = &MUST(HostnameContext::create_with_name(""sv)).leak_ref();
// NOTE: Just allocate the kernel version string here so we never have to worry
// about OOM conditions in the uname syscall.
g_version_string = MUST(KString::formatted("{}.{}-dev", SERENITY_MAJOR_REVISION, SERENITY_MINOR_REVISION)).leak_ptr();
@ -214,7 +210,7 @@ void Process::register_new(Process& process)
});
}
ErrorOr<Process::ProcessAndFirstThread> Process::create_user_process(StringView path, UserID uid, GroupID gid, Vector<NonnullOwnPtr<KString>> arguments, Vector<NonnullOwnPtr<KString>> environment, NonnullRefPtr<VFSRootContext> vfs_root_context, RefPtr<TTY> tty)
ErrorOr<Process::ProcessAndFirstThread> Process::create_user_process(StringView path, UserID uid, GroupID gid, Vector<NonnullOwnPtr<KString>> arguments, Vector<NonnullOwnPtr<KString>> environment, NonnullRefPtr<VFSRootContext> vfs_root_context, NonnullRefPtr<HostnameContext> hostname_context, RefPtr<TTY> tty)
{
auto parts = path.split_view('/');
if (arguments.is_empty()) {
@ -227,7 +223,7 @@ ErrorOr<Process::ProcessAndFirstThread> Process::create_user_process(StringView
auto vfs_root_context_root_custody = vfs_root_context->root_custody().with([](auto& custody) -> NonnullRefPtr<Custody> {
return custody;
});
auto [process, first_thread] = TRY(Process::create(parts.last(), uid, gid, ProcessID(0), false, vfs_root_context, vfs_root_context_root_custody, nullptr, tty));
auto [process, first_thread] = TRY(Process::create(parts.last(), uid, gid, ProcessID(0), false, vfs_root_context, hostname_context, vfs_root_context_root_custody, nullptr, tty));
TRY(process->m_fds.with_exclusive([&](auto& fds) -> ErrorOr<void> {
TRY(fds.try_resize(Process::OpenFileDescriptions::max_open()));
@ -264,7 +260,8 @@ ErrorOr<Process::ProcessAndFirstThread> Process::create_user_process(StringView
ErrorOr<Process::ProcessAndFirstThread> Process::create_kernel_process(StringView name, void (*entry)(void*), void* entry_data, u32 affinity, RegisterProcess do_register)
{
auto process_and_first_thread = TRY(Process::create(name, UserID(0), GroupID(0), ProcessID(0), true, VFSRootContext::empty_context_for_kernel_processes()));
VERIFY(s_empty_kernel_hostname_context);
auto process_and_first_thread = TRY(Process::create(name, UserID(0), GroupID(0), ProcessID(0), true, VFSRootContext::empty_context_for_kernel_processes(), *s_empty_kernel_hostname_context));
auto& process = *process_and_first_thread.process;
auto& thread = *process_and_first_thread.first_thread;
@ -293,22 +290,22 @@ void Process::unprotect_data()
});
}
ErrorOr<Process::ProcessAndFirstThread> Process::create_with_forked_name(UserID uid, GroupID gid, ProcessID ppid, bool is_kernel_process, NonnullRefPtr<VFSRootContext> vfs_root_context, RefPtr<Custody> current_directory, RefPtr<Custody> executable, RefPtr<TTY> tty, Process* fork_parent)
ErrorOr<Process::ProcessAndFirstThread> Process::create_with_forked_name(UserID uid, GroupID gid, ProcessID ppid, bool is_kernel_process, NonnullRefPtr<VFSRootContext> vfs_root_context, NonnullRefPtr<HostnameContext> hostname_context, RefPtr<Custody> current_directory, RefPtr<Custody> executable, RefPtr<TTY> tty, Process* fork_parent)
{
Process::Name name {};
Process::current().name().with([&name](auto& process_name) {
name.store_characters(process_name.representable_view());
});
return TRY(Process::create(name.representable_view(), uid, gid, ppid, is_kernel_process, move(vfs_root_context), current_directory, executable, tty, fork_parent));
return TRY(Process::create(name.representable_view(), uid, gid, ppid, is_kernel_process, move(vfs_root_context), move(hostname_context), current_directory, executable, tty, fork_parent));
}
ErrorOr<Process::ProcessAndFirstThread> Process::create(StringView name, UserID uid, GroupID gid, ProcessID ppid, bool is_kernel_process, NonnullRefPtr<VFSRootContext> vfs_root_context, RefPtr<Custody> current_directory, RefPtr<Custody> executable, RefPtr<TTY> tty, Process* fork_parent)
ErrorOr<Process::ProcessAndFirstThread> Process::create(StringView name, UserID uid, GroupID gid, ProcessID ppid, bool is_kernel_process, NonnullRefPtr<VFSRootContext> vfs_root_context, NonnullRefPtr<HostnameContext> hostname_context, RefPtr<Custody> current_directory, RefPtr<Custody> executable, RefPtr<TTY> tty, Process* fork_parent)
{
auto unveil_tree = UnveilNode { TRY(KString::try_create("/"sv)), UnveilMetadata(TRY(KString::try_create("/"sv))) };
auto exec_unveil_tree = UnveilNode { TRY(KString::try_create("/"sv)), UnveilMetadata(TRY(KString::try_create("/"sv))) };
auto credentials = TRY(Credentials::create(uid, gid, uid, gid, uid, gid, {}, fork_parent ? fork_parent->sid() : 0, fork_parent ? fork_parent->pgid() : 0));
auto process = TRY(adopt_nonnull_ref_or_enomem(new (nothrow) Process(name, move(credentials), ppid, is_kernel_process, move(vfs_root_context), move(current_directory), move(executable), tty, move(unveil_tree), move(exec_unveil_tree), kgettimeofday())));
auto process = TRY(adopt_nonnull_ref_or_enomem(new (nothrow) Process(name, move(credentials), ppid, is_kernel_process, move(vfs_root_context), move(hostname_context), move(current_directory), move(executable), tty, move(unveil_tree), move(exec_unveil_tree), kgettimeofday())));
OwnPtr<Memory::AddressSpace> new_address_space;
if (fork_parent) {
@ -325,12 +322,13 @@ ErrorOr<Process::ProcessAndFirstThread> Process::create(StringView name, UserID
return ProcessAndFirstThread { move(process), move(first_thread) };
}
Process::Process(StringView name, NonnullRefPtr<Credentials> credentials, ProcessID ppid, bool is_kernel_process, NonnullRefPtr<VFSRootContext> vfs_root_context, RefPtr<Custody> current_directory, RefPtr<Custody> executable, RefPtr<TTY> tty, UnveilNode unveil_tree, UnveilNode exec_unveil_tree, UnixDateTime creation_time)
Process::Process(StringView name, NonnullRefPtr<Credentials> credentials, ProcessID ppid, bool is_kernel_process, NonnullRefPtr<VFSRootContext> vfs_root_context, NonnullRefPtr<HostnameContext> hostname_context, RefPtr<Custody> current_directory, RefPtr<Custody> executable, RefPtr<TTY> tty, UnveilNode unveil_tree, UnveilNode exec_unveil_tree, UnixDateTime creation_time)
: m_is_kernel_process(is_kernel_process)
, m_executable(move(executable))
, m_current_directory(move(current_directory))
, m_creation_time(creation_time)
, m_attached_vfs_root_context(move(vfs_root_context))
, m_attached_hostname_context(move(hostname_context))
, m_unveil_data(move(unveil_tree))
, m_exec_unveil_data(move(exec_unveil_tree))
, m_wait_blocker_set(*this)
@ -353,6 +351,10 @@ Process::Process(StringView name, NonnullRefPtr<Credentials> credentials, Proces
m_attached_vfs_root_context.with([](auto& context) {
context->set_attached({});
});
m_attached_hostname_context.with([](auto& context) {
context->set_attached({});
});
}
ErrorOr<NonnullRefPtr<Thread>> Process::attach_resources(NonnullOwnPtr<Memory::AddressSpace>&& preallocated_space, Process* fork_parent)
@ -882,6 +884,11 @@ void Process::finalize()
m_arguments.clear();
m_environment.clear();
m_attached_hostname_context.with([](auto& context) {
context->detach({});
context = nullptr;
});
m_state.store(State::Dead, AK::MemoryOrder::memory_order_release);
{

View file

@ -38,6 +38,7 @@
#include <Kernel/Security/Credentials.h>
#include <Kernel/Tasks/AtomicEdgeAction.h>
#include <Kernel/Tasks/FutexQueue.h>
#include <Kernel/Tasks/HostnameContext.h>
#include <Kernel/Tasks/PerformanceEventBuffer.h>
#include <Kernel/Tasks/ProcessGroup.h>
#include <Kernel/Tasks/Thread.h>
@ -46,7 +47,6 @@
namespace Kernel {
MutexProtected<FixedStringBuffer<UTSNAME_ENTRY_LEN - 1>>& hostname();
UnixDateTime kgettimeofday();
#define ENUMERATE_PLEDGE_PROMISES \
@ -215,7 +215,7 @@ public:
}
static ErrorOr<ProcessAndFirstThread> create_kernel_process(StringView name, void (*entry)(void*), void* entry_data = nullptr, u32 affinity = THREAD_AFFINITY_DEFAULT, RegisterProcess do_register = RegisterProcess::Yes);
static ErrorOr<ProcessAndFirstThread> create_user_process(StringView path, UserID, GroupID, Vector<NonnullOwnPtr<KString>> arguments, Vector<NonnullOwnPtr<KString>> environment, NonnullRefPtr<VFSRootContext>, RefPtr<TTY>);
static ErrorOr<ProcessAndFirstThread> create_user_process(StringView path, UserID, GroupID, Vector<NonnullOwnPtr<KString>> arguments, Vector<NonnullOwnPtr<KString>> environment, NonnullRefPtr<VFSRootContext>, NonnullRefPtr<HostnameContext>, RefPtr<TTY>);
static void register_new(Process&);
~Process();
@ -282,6 +282,13 @@ public:
});
}
NonnullRefPtr<HostnameContext> hostname_context() const
{
return m_attached_hostname_context.with([](auto& context) -> NonnullRefPtr<HostnameContext> {
return *context;
});
}
bool is_jailed() const
{
return with_protected_data([](auto& protected_data) { return protected_data.jailed.was_set(); });
@ -679,9 +686,9 @@ private:
bool add_thread(Thread&);
bool remove_thread(Thread&);
Process(StringView name, NonnullRefPtr<Credentials>, ProcessID ppid, bool is_kernel_process, NonnullRefPtr<VFSRootContext>, RefPtr<Custody> current_directory, RefPtr<Custody> executable, RefPtr<TTY> tty, UnveilNode unveil_tree, UnveilNode exec_unveil_tree, UnixDateTime creation_time);
static ErrorOr<ProcessAndFirstThread> create_with_forked_name(UserID, GroupID, ProcessID ppid, bool is_kernel_process, NonnullRefPtr<VFSRootContext> vfs_root_context, RefPtr<Custody> current_directory = nullptr, RefPtr<Custody> executable = nullptr, RefPtr<TTY> = nullptr, Process* fork_parent = nullptr);
static ErrorOr<ProcessAndFirstThread> create(StringView name, UserID, GroupID, ProcessID ppid, bool is_kernel_process, NonnullRefPtr<VFSRootContext> vfs_root_context, RefPtr<Custody> current_directory = nullptr, RefPtr<Custody> executable = nullptr, RefPtr<TTY> = nullptr, Process* fork_parent = nullptr);
Process(StringView name, NonnullRefPtr<Credentials>, ProcessID ppid, bool is_kernel_process, NonnullRefPtr<VFSRootContext>, NonnullRefPtr<HostnameContext>, RefPtr<Custody> current_directory, RefPtr<Custody> executable, RefPtr<TTY> tty, UnveilNode unveil_tree, UnveilNode exec_unveil_tree, UnixDateTime creation_time);
static ErrorOr<ProcessAndFirstThread> create_with_forked_name(UserID, GroupID, ProcessID ppid, bool is_kernel_process, NonnullRefPtr<VFSRootContext> vfs_root_context, NonnullRefPtr<HostnameContext>, RefPtr<Custody> current_directory = nullptr, RefPtr<Custody> executable = nullptr, RefPtr<TTY> = nullptr, Process* fork_parent = nullptr);
static ErrorOr<ProcessAndFirstThread> create(StringView name, UserID, GroupID, ProcessID ppid, bool is_kernel_process, NonnullRefPtr<VFSRootContext> vfs_root_context, NonnullRefPtr<HostnameContext>, RefPtr<Custody> current_directory = nullptr, RefPtr<Custody> executable = nullptr, RefPtr<TTY> = nullptr, Process* fork_parent = nullptr);
ErrorOr<NonnullRefPtr<Thread>> attach_resources(NonnullOwnPtr<Memory::AddressSpace>&&, Process* fork_parent);
static ProcessID allocate_pid();
@ -980,6 +987,8 @@ private:
SpinlockProtected<RefPtr<VFSRootContext>, LockRank::Process> m_attached_vfs_root_context;
SpinlockProtected<RefPtr<HostnameContext>, LockRank::Process> m_attached_hostname_context;
Mutex m_big_lock { "Process"sv, Mutex::MutexBehavior::BigLock };
Mutex m_ptrace_lock { "ptrace"sv };