1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-05-31 09:48:11 +00:00

Kernel: Guard Process "protected data" with a spinlock

This ensures that both mutable and immutable access to the protected
data of a process is serialized.

Note that there may still be multiple TOCTOU issues around this, as we
have a bunch of convenience accessors that make it easy to introduce
them. We'll need to audit those as well.
This commit is contained in:
Andreas Kling 2022-08-21 12:18:26 +02:00
parent 728c3fbd14
commit 8ed06ad814
11 changed files with 348 additions and 300 deletions

View file

@ -211,14 +211,14 @@ LockRefPtr<Process> Process::create_kernel_process(LockRefPtr<Thread>& first_thr
void Process::protect_data()
{
m_protected_data_refs.unref([&]() {
MM.set_page_writable_direct(VirtualAddress { &this->m_protected_values }, false);
MM.set_page_writable_direct(VirtualAddress { &this->m_protected_values_do_not_access_directly }, false);
});
}
void Process::unprotect_data()
{
m_protected_data_refs.ref([&]() {
MM.set_page_writable_direct(VirtualAddress { &this->m_protected_values }, true);
MM.set_page_writable_direct(VirtualAddress { &this->m_protected_values_do_not_access_directly }, true);
});
}
@ -234,6 +234,7 @@ ErrorOr<NonnullLockRefPtr<Process>> Process::try_create(LockRefPtr<Thread>& firs
Process::Process(NonnullOwnPtr<KString> name, NonnullRefPtr<Credentials> credentials, ProcessID ppid, bool is_kernel_process, RefPtr<Custody> current_directory, RefPtr<Custody> executable, TTY* tty, UnveilNode unveil_tree)
: m_name(move(name))
, m_protected_data_lock(LockRank::None)
, m_is_kernel_process(is_kernel_process)
, m_executable(LockRank::None, move(executable))
, m_current_directory(LockRank::None, move(current_directory))
@ -242,11 +243,11 @@ Process::Process(NonnullOwnPtr<KString> name, NonnullRefPtr<Credentials> credent
, m_wait_blocker_set(*this)
{
// Ensure that we protect the process data when exiting the constructor.
ProtectedDataMutationScope scope { *this };
m_protected_values.pid = allocate_pid();
m_protected_values.ppid = ppid;
m_protected_values.credentials = move(credentials);
with_mutable_protected_data([&](auto& protected_data) {
protected_data.pid = allocate_pid();
protected_data.ppid = ppid;
protected_data.credentials = move(credentials);
});
dbgln_if(PROCESS_DEBUG, "Created new process {}({})", m_name, this->pid().value());
}
@ -402,10 +403,9 @@ void Process::crash(int signal, FlatPtr ip, bool out_of_memory)
}
dump_backtrace();
}
{
ProtectedDataMutationScope scope { *this };
m_protected_values.termination_signal = signal;
}
with_mutable_protected_data([&](auto& protected_data) {
protected_data.termination_signal = signal;
});
set_should_generate_coredump(!out_of_memory);
address_space().dump_regions();
VERIFY(is_user_process());
@ -527,13 +527,15 @@ siginfo_t Process::wait_info() const
siginfo.si_pid = pid().value();
siginfo.si_uid = uid().value();
if (m_protected_values.termination_signal != 0) {
siginfo.si_status = m_protected_values.termination_signal;
siginfo.si_code = CLD_KILLED;
} else {
siginfo.si_status = m_protected_values.termination_status;
siginfo.si_code = CLD_EXITED;
}
with_protected_data([&](auto& protected_data) {
if (protected_data.termination_signal != 0) {
siginfo.si_status = protected_data.termination_signal;
siginfo.si_code = CLD_KILLED;
} else {
siginfo.si_status = protected_data.termination_status;
siginfo.si_code = CLD_EXITED;
}
});
return siginfo;
}
@ -619,7 +621,7 @@ void Process::finalize()
dbgln("\x1b[01;31mProcess '{}' exited with the veil left open\x1b[0m", name());
if (g_init_pid != 0 && pid() == g_init_pid)
PANIC("Init process quit unexpectedly. Exit code: {}", m_protected_values.termination_status);
PANIC("Init process quit unexpectedly. Exit code: {}", termination_status());
if (is_dumpable()) {
if (m_should_generate_coredump) {
@ -741,11 +743,10 @@ void Process::terminate_due_to_signal(u8 signal)
VERIFY(signal < NSIG);
VERIFY(&Process::current() == this);
dbgln("Terminating {} due to signal {}", *this, signal);
{
ProtectedDataMutationScope scope { *this };
m_protected_values.termination_status = 0;
m_protected_values.termination_signal = signal;
}
with_mutable_protected_data([&](auto& protected_data) {
protected_data.termination_status = 0;
protected_data.termination_signal = signal;
});
die();
}
@ -851,31 +852,34 @@ void Process::delete_perf_events_buffer()
bool Process::remove_thread(Thread& thread)
{
ProtectedDataMutationScope scope { *this };
auto thread_cnt_before = m_protected_values.thread_count.fetch_sub(1, AK::MemoryOrder::memory_order_acq_rel);
VERIFY(thread_cnt_before != 0);
u32 thread_count_before = 0;
thread_list().with([&](auto& thread_list) {
thread_list.remove(thread);
with_mutable_protected_data([&](auto& protected_data) {
thread_count_before = protected_data.thread_count.fetch_sub(1, AK::MemoryOrder::memory_order_acq_rel);
VERIFY(thread_count_before != 0);
});
});
return thread_cnt_before == 1;
return thread_count_before == 1;
}
bool Process::add_thread(Thread& thread)
{
ProtectedDataMutationScope scope { *this };
bool is_first = m_protected_values.thread_count.fetch_add(1, AK::MemoryOrder::memory_order_relaxed) == 0;
bool is_first = false;
thread_list().with([&](auto& thread_list) {
thread_list.append(thread);
with_mutable_protected_data([&](auto& protected_data) {
is_first = protected_data.thread_count.fetch_add(1, AK::MemoryOrder::memory_order_relaxed) == 0;
});
});
return is_first;
}
void Process::set_dumpable(bool dumpable)
{
if (dumpable == m_protected_values.dumpable)
return;
ProtectedDataMutationScope scope { *this };
m_protected_values.dumpable = dumpable;
with_mutable_protected_data([&](auto& protected_data) {
protected_data.dumpable = dumpable;
});
}
ErrorOr<void> Process::set_coredump_property(NonnullOwnPtr<KString> key, NonnullOwnPtr<KString> value)
@ -968,7 +972,9 @@ GroupID Process::sgid() const
NonnullRefPtr<Credentials> Process::credentials() const
{
return *m_protected_values.credentials;
return with_protected_data([&](auto& protected_data) -> NonnullRefPtr<Credentials> {
return *protected_data.credentials;
});
}
RefPtr<Custody> Process::executable()