LibCore: Avoid UAF on the array of wake pipes when exit()ing

If exit() is called on a thread with an EventLoop in the stack, the
ThreadData storing the array of wake pipes will be destroyed first.
Threads can still take a strong reference to the EventLoop after that,
and will read the fds from freed memory.

Instead, take a copy of the write fd, and swallow EBADF when writing to
it, since that only indicates that the thread and event loop are
exiting, so there's nothing to do with the wake.
This commit is contained in:
Zaggy1024
2026-02-27 06:45:27 -06:00
committed by Gregory Bertilson
parent 75aac67adb
commit 04e95b7dd1
Notes: github-actions[bot] 2026-03-02 23:09:14 +00:00
2 changed files with 14 additions and 4 deletions

View File

@@ -263,6 +263,9 @@ struct ThreadData {
~ThreadData()
{
close(wake_pipe_fds[0]);
close(wake_pipe_fds[1]);
Threading::RWLockLocker<Threading::LockMode::Write> locker(s_thread_data_lock);
s_thread_data.remove(s_thread_id);
}
@@ -286,8 +289,9 @@ struct ThreadData {
}
EventLoopImplementationUnix::EventLoopImplementationUnix()
: m_wake_pipe_fds(ThreadData::the().wake_pipe_fds)
: m_wake_pipe_write_fd(ThreadData::the().wake_pipe_fds[1])
{
VERIFY(m_wake_pipe_write_fd >= 0);
}
EventLoopImplementationUnix::~EventLoopImplementationUnix() = default;
@@ -317,7 +321,12 @@ void EventLoopImplementationUnix::quit(int code)
void EventLoopImplementationUnix::wake()
{
int wake_event = 0;
MUST(Core::System::write(m_wake_pipe_fds[1], { &wake_event, sizeof(wake_event) }));
auto result = Core::System::write(m_wake_pipe_write_fd, { &wake_event, sizeof(wake_event) });
// EBADF here just indicates that the ThreadData is destroyed, so we must be exiting the thread.
// Ignore it.
if (result.is_error() && result.error().code() == EBADF)
return;
MUST(move(result));
}
void EventLoopManagerUnix::wait_for_events(EventLoopImplementation::PumpMode mode)