1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-07-25 19:17:44 +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

@ -135,20 +135,19 @@ public:
friend class Thread;
friend class Coredump;
// Helper class to temporarily unprotect a process's protected data so you can write to it.
class ProtectedDataMutationScope {
public:
explicit ProtectedDataMutationScope(Process& process)
: m_process(process)
{
m_process.unprotect_data();
}
auto with_protected_data(auto&& callback) const
{
SpinlockLocker locker(m_protected_data_lock);
return callback(m_protected_values_do_not_access_directly);
}
~ProtectedDataMutationScope() { m_process.protect_data(); }
private:
Process& m_process;
};
auto with_mutable_protected_data(auto&& callback)
{
SpinlockLocker locker(m_protected_data_lock);
unprotect_data();
auto guard = ScopeGuard([&] { protect_data(); });
return callback(m_protected_values_do_not_access_directly);
}
enum class State : u8 {
Running = 0,
@ -218,12 +217,21 @@ public:
static SessionID get_sid_from_pgid(ProcessGroupID pgid);
StringView name() const { return m_name->view(); }
ProcessID pid() const { return m_protected_values.pid; }
SessionID sid() const { return m_protected_values.sid; }
ProcessID pid() const
{
return with_protected_data([](auto& protected_data) { return protected_data.pid; });
}
SessionID sid() const
{
return with_protected_data([](auto& protected_data) { return protected_data.sid; });
}
bool is_session_leader() const { return sid().value() == pid().value(); }
ProcessGroupID pgid() const { return m_pg ? m_pg->pgid() : 0; }
bool is_group_leader() const { return pgid().value() == pid().value(); }
ProcessID ppid() const { return m_protected_values.ppid; }
ProcessID ppid() const
{
return with_protected_data([](auto& protected_data) { return protected_data.ppid; });
}
NonnullRefPtr<Credentials> credentials() const;
@ -234,10 +242,16 @@ public:
UserID suid() const;
GroupID sgid() const;
bool is_dumpable() const { return m_protected_values.dumpable; }
bool is_dumpable() const
{
return with_protected_data([](auto& protected_data) { return protected_data.dumpable; });
}
void set_dumpable(bool);
mode_t umask() const { return m_protected_values.umask; }
mode_t umask() const
{
return with_protected_data([](auto& protected_data) { return protected_data.umask; });
}
bool in_group(GroupID) const;
@ -467,19 +481,37 @@ public:
void terminate_due_to_signal(u8 signal);
ErrorOr<void> send_signal(u8 signal, Process* sender);
u8 termination_signal() const { return m_protected_values.termination_signal; }
u8 termination_status() const { return m_protected_values.termination_status; }
u8 termination_signal() const
{
return with_protected_data([](auto& protected_data) -> u8 {
return protected_data.termination_signal;
});
}
u8 termination_status() const
{
return with_protected_data([](auto& protected_data) { return protected_data.termination_status; });
}
u16 thread_count() const
{
return m_protected_values.thread_count.load(AK::MemoryOrder::memory_order_relaxed);
return with_protected_data([](auto& protected_data) {
return protected_data.thread_count.load(AK::MemoryOrder::memory_order_relaxed);
});
}
Mutex& big_lock() { return m_big_lock; }
Mutex& ptrace_lock() { return m_ptrace_lock; }
bool has_promises() const { return m_protected_values.has_promises; }
bool has_promised(Pledge pledge) const { return (m_protected_values.promises & (1U << (u32)pledge)) != 0; }
bool has_promises() const
{
return with_protected_data([](auto& protected_data) { return protected_data.has_promises.load(); });
}
bool has_promised(Pledge pledge) const
{
return with_protected_data([&](auto& protected_data) {
return (protected_data.promises & (1U << (u32)pledge)) != 0;
});
}
VeilState veil_state() const
{
@ -539,7 +571,10 @@ public:
Memory::AddressSpace& address_space() { return *m_space; }
Memory::AddressSpace const& address_space() const { return *m_space; }
VirtualAddress signal_trampoline() const { return m_protected_values.signal_trampoline; }
VirtualAddress signal_trampoline() const
{
return with_protected_data([](auto& protected_data) { return protected_data.signal_trampoline; });
}
ErrorOr<void> require_promise(Pledge);
ErrorOr<void> require_no_promises() const;
@ -635,6 +670,7 @@ private:
LockRefPtr<ProcessGroup> m_pg;
RecursiveSpinlock mutable m_protected_data_lock;
AtomicEdgeAction<u32> m_protected_data_refs;
void protect_data();
void unprotect_data();
@ -870,7 +906,7 @@ private:
Array<SignalActionData, NSIG> m_signal_action_data;
static_assert(sizeof(ProtectedValues) < (PAGE_SIZE));
alignas(4096) ProtectedValues m_protected_values;
alignas(4096) ProtectedValues m_protected_values_do_not_access_directly;
u8 m_protected_values_padding[PAGE_SIZE - sizeof(ProtectedValues)];
public: