• Peter Zijlstra's avatar
    perf: Fix perf_pending_task() UaF · 517e6a30
    Peter Zijlstra authored
    Per syzbot it is possible for perf_pending_task() to run after the
    event is free()'d. There are two related but distinct cases:
    
     - the task_work was already queued before destroying the event;
     - destroying the event itself queues the task_work.
    
    The first cannot be solved using task_work_cancel() since
    perf_release() itself might be called from a task_work (____fput),
    which means the current->task_works list is already empty and
    task_work_cancel() won't be able to find the perf_pending_task()
    entry.
    
    The simplest alternative is extending the perf_event lifetime to cover
    the task_work.
    
    The second is just silly, queueing a task_work while you know the
    event is going away makes no sense and is easily avoided by
    re-arranging how the event is marked STATE_DEAD and ensuring it goes
    through STATE_OFF on the way down.
    
    Reported-by: syzbot+9228d6098455bb209ec8@syzkaller.appspotmail.com
    Signed-off-by: default avatarPeter Zijlstra (Intel) <peterz@infradead.org>
    Tested-by: default avatarMarco Elver <elver@google.com>
    517e6a30
core.c 327 KB