ladybird/Libraries/LibCore/EventLoopImplementationUnix.h
Zaggy1024 04e95b7dd1 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.
2026-03-02 17:06:39 -06:00

65 lines
1.9 KiB
C++

/*
* Copyright (c) 2023, Andreas Kling <andreas@ladybird.org>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#pragma once
#include <AK/NonnullOwnPtr.h>
#include <AK/Time.h>
#include <LibCore/EventLoopImplementation.h>
namespace Core {
class EventLoopManagerUnix final : public EventLoopManager {
public:
virtual ~EventLoopManagerUnix() override;
virtual NonnullOwnPtr<EventLoopImplementation> make_implementation() override;
virtual intptr_t register_timer(EventReceiver&, int milliseconds, bool should_reload) override;
virtual void unregister_timer(intptr_t timer_id) override;
virtual void register_notifier(Notifier&) override;
virtual void unregister_notifier(Notifier&) override;
virtual void did_post_event() override;
virtual int register_signal(int signal_number, Function<void(int)> handler) override;
virtual void unregister_signal(int handler_id) override;
void wait_for_events(EventLoopImplementation::PumpMode);
static Optional<MonotonicTime> get_next_timer_expiration();
private:
void dispatch_signal(int signal_number);
static void handle_signal(int signal_number);
};
class EventLoopImplementationUnix final : public EventLoopImplementation {
public:
static NonnullOwnPtr<EventLoopImplementationUnix> create() { return make<EventLoopImplementationUnix>(); }
EventLoopImplementationUnix();
virtual ~EventLoopImplementationUnix();
virtual int exec() override;
virtual size_t pump(PumpMode) override;
virtual void quit(int) override;
virtual bool was_exit_requested() const override { return m_exit_requested; }
virtual void wake() override;
private:
bool m_exit_requested { false };
int m_exit_code { 0 };
// The write end of the wake pipe, copied by value so it remains valid even
// if ThreadData is destroyed before this event loop (e.g. during exit()).
int m_wake_pipe_write_fd;
};
using EventLoopManagerPlatform = EventLoopManagerUnix;
}