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:
parent
728c3fbd14
commit
8ed06ad814
11 changed files with 348 additions and 300 deletions
|
@ -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()
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue