Re: [PATCH 4/4] perf: Fix event leak upon exec and file release

From: Peter Zijlstra
Date: Thu May 16 2024 - 05:41:55 EST


On Wed, May 15, 2024 at 04:43:11PM +0200, Frederic Weisbecker wrote:
> The perf pending task work is never waited upon the matching event
> release. In the case of a child event, released via free_event()
> directly, this can potentially result in a leaked event, such as in the
> following scenario that doesn't even require a weak IRQ work
> implementation to trigger:
>
> schedule()
> prepare_task_switch()
> =======> <NMI>
> perf_event_overflow()
> event->pending_sigtrap = ...
> irq_work_queue(&event->pending_irq)
> <======= </NMI>
> perf_event_task_sched_out()
> event_sched_out()
> event->pending_sigtrap = 0;
> atomic_long_inc_not_zero(&event->refcount)
> task_work_add(&event->pending_task)
> finish_lock_switch()
> =======> <IRQ>
> perf_pending_irq()
> //do nothing, rely on pending task work
> <======= </IRQ>
>
> begin_new_exec()
> perf_event_exit_task()
> perf_event_exit_event()
> // If is child event
> free_event()
> WARN(atomic_long_cmpxchg(&event->refcount, 1, 0) != 1)
> // event is leaked
>
> Similar scenarios can also happen with perf_event_remove_on_exec() or
> simply against concurrent perf_event_release().
>
> Fix this with synchonizing against the possibly remaining pending task
> work while freeing the event, just like is done with remaining pending
> IRQ work. This means that the pending task callback neither need nor
> should hold a reference to the event, preventing it from ever beeing
> freed.
>
> Fixes: 517e6a301f34 ("perf: Fix perf_pending_task() UaF")
> Signed-off-by: Frederic Weisbecker <frederic@xxxxxxxxxx>

Yeah, I suppose this'll do. Thanks!