1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-07-26 02:47:34 +00:00

Kernel: Prevent execve/ptrace race

Add a per-process ptrace lock and use it to prevent ptrace access to a
process after it decides to commit to a new executable in sys$execve().

Fixes #5230.
This commit is contained in:
Andreas Kling 2021-02-08 23:01:53 +01:00
parent 4b7b92c201
commit 4ff0f971f7
3 changed files with 8 additions and 4 deletions

View file

@ -408,10 +408,8 @@ public:
return m_thread_count.load(AK::MemoryOrder::memory_order_relaxed); return m_thread_count.load(AK::MemoryOrder::memory_order_relaxed);
} }
Lock& big_lock() Lock& big_lock() { return m_big_lock; }
{ Lock& ptrace_lock() { return m_ptrace_lock; }
return m_big_lock;
}
Custody& root_directory(); Custody& root_directory();
Custody& root_directory_relative_to_global_root(); Custody& root_directory_relative_to_global_root();
@ -579,6 +577,7 @@ private:
size_t m_master_tls_alignment { 0 }; size_t m_master_tls_alignment { 0 };
Lock m_big_lock { "Process" }; Lock m_big_lock { "Process" };
Lock m_ptrace_lock { "ptrace" };
RefPtr<Timer> m_alarm_timer; RefPtr<Timer> m_alarm_timer;

View file

@ -483,6 +483,9 @@ int Process::do_exec(NonnullRefPtr<FileDescription> main_program_description, Ve
// We commit to the new executable at this point. There is no turning back! // We commit to the new executable at this point. There is no turning back!
// Prevent other processes from attaching to us with ptrace while we're doing this.
Locker ptrace_locker(ptrace_lock());
// Disable profiling temporarily in case it's running on this process. // Disable profiling temporarily in case it's running on this process.
TemporaryChange profiling_disabler(m_profiling, false); TemporaryChange profiling_disabler(m_profiling, false);

View file

@ -57,6 +57,8 @@ static KResultOr<u32> handle_ptrace(const Kernel::Syscall::SC_ptrace_params& par
if (!peer) if (!peer)
return ESRCH; return ESRCH;
Locker ptrace_locker(peer->process().ptrace_lock());
if ((peer->process().uid() != caller.euid()) if ((peer->process().uid() != caller.euid())
|| (peer->process().uid() != peer->process().euid())) // Disallow tracing setuid processes || (peer->process().uid() != peer->process().euid())) // Disallow tracing setuid processes
return EACCES; return EACCES;