1. 09 Jul, 2024 4 commits
    • Frederic Weisbecker's avatar
      perf: Fix event leak upon exec and file release · 3a546541
      Frederic Weisbecker authored
      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: 517e6a30 ("perf: Fix perf_pending_task() UaF")
      Signed-off-by: default avatarFrederic Weisbecker <frederic@kernel.org>
      Signed-off-by: default avatarPeter Zijlstra (Intel) <peterz@infradead.org>
      Cc: stable@vger.kernel.org
      Link: https://lore.kernel.org/r/20240621091601.18227-5-frederic@kernel.org
      3a546541
    • Frederic Weisbecker's avatar
      perf: Fix event leak upon exit · 2fd5ad3f
      Frederic Weisbecker authored
      When a task is scheduled out, pending sigtrap deliveries are deferred
      to the target task upon resume to userspace via task_work.
      
      However failures while adding an event's callback to the task_work
      engine are ignored. And since the last call for events exit happen
      after task work is eventually closed, there is a small window during
      which pending sigtrap can be queued though ignored, leaking the event
      refcount addition such as in the following scenario:
      
          TASK A
          -----
      
          do_exit()
             exit_task_work(tsk);
      
             <IRQ>
             perf_event_overflow()
                event->pending_sigtrap = pending_id;
                irq_work_queue(&event->pending_irq);
             </IRQ>
          =========> PREEMPTION: TASK A -> TASK B
             event_sched_out()
                event->pending_sigtrap = 0;
                atomic_long_inc_not_zero(&event->refcount)
                // FAILS: task work has exited
                task_work_add(&event->pending_task)
             [...]
             <IRQ WORK>
             perf_pending_irq()
                // early return: event->oncpu = -1
             </IRQ WORK>
             [...]
          =========> TASK B -> TASK A
             perf_event_exit_task(tsk)
                perf_event_exit_event()
                   free_event()
                      WARN(atomic_long_cmpxchg(&event->refcount, 1, 0) != 1)
                      // leak event due to unexpected refcount == 2
      
      As a result the event is never released while the task exits.
      
      Fix this with appropriate task_work_add()'s error handling.
      
      Fixes: 517e6a30 ("perf: Fix perf_pending_task() UaF")
      Signed-off-by: default avatarFrederic Weisbecker <frederic@kernel.org>
      Signed-off-by: default avatarPeter Zijlstra (Intel) <peterz@infradead.org>
      Cc: stable@vger.kernel.org
      Link: https://lore.kernel.org/r/20240621091601.18227-4-frederic@kernel.org
      2fd5ad3f
    • Frederic Weisbecker's avatar
      task_work: Introduce task_work_cancel() again · f409530e
      Frederic Weisbecker authored
      Re-introduce task_work_cancel(), this time to cancel an actual callback
      and not *any* callback pointing to a given function. This is going to be
      needed for perf events event freeing.
      Signed-off-by: default avatarFrederic Weisbecker <frederic@kernel.org>
      Signed-off-by: default avatarPeter Zijlstra (Intel) <peterz@infradead.org>
      Cc: stable@vger.kernel.org
      Link: https://lore.kernel.org/r/20240621091601.18227-3-frederic@kernel.org
      f409530e
    • Frederic Weisbecker's avatar
      task_work: s/task_work_cancel()/task_work_cancel_func()/ · 68cbd415
      Frederic Weisbecker authored
      A proper task_work_cancel() API that actually cancels a callback and not
      *any* callback pointing to a given function is going to be needed for
      perf events event freeing. Do the appropriate rename to prepare for
      that.
      Signed-off-by: default avatarFrederic Weisbecker <frederic@kernel.org>
      Signed-off-by: default avatarPeter Zijlstra (Intel) <peterz@infradead.org>
      Cc: stable@vger.kernel.org
      Link: https://lore.kernel.org/r/20240621091601.18227-2-frederic@kernel.org
      68cbd415
  2. 04 Jul, 2024 21 commits
  3. 29 Jun, 2024 1 commit
  4. 20 Jun, 2024 1 commit
  5. 17 Jun, 2024 8 commits
  6. 13 Jun, 2024 1 commit
  7. 02 Jun, 2024 1 commit
  8. 28 May, 2024 3 commits