Merge branch 'fixes-for-bpf-timer-lockup-and-uaf'
authorAlexei Starovoitov <ast@kernel.org>
Wed, 10 Jul 2024 22:59:45 +0000 (15:59 -0700)
committerAlexei Starovoitov <ast@kernel.org>
Wed, 10 Jul 2024 23:20:16 +0000 (16:20 -0700)
Kumar Kartikeya Dwivedi says:

====================
Fixes for BPF timer lockup and UAF

The following patches contain fixes for timer lockups and a
use-after-free scenario.

This set proposes to fix the following lockup situation for BPF timers.

CPU 1 CPU 2

bpf_timer_cb bpf_timer_cb
  timer_cb1   timer_cb2
    bpf_timer_cancel(timer_cb2)     bpf_timer_cancel(timer_cb1)
      hrtimer_cancel       hrtimer_cancel

In this case, both callbacks will continue waiting for each other to
finish synchronously, causing a lockup.

The proposed fix adds support for tracking in-flight cancellations
*begun by other timer callbacks* for a particular BPF timer.  Whenever
preparing to call hrtimer_cancel, a callback will increment the target
timer's counter, then inspect its in-flight cancellations, and if
non-zero, return -EDEADLK to avoid situations where the target timer's
callback is waiting for its completion.

This does mean that in cases where a callback is fired and cancelled, it
will be unable to cancel any timers in that execution. This can be
alleviated by maintaining the list of waiting callbacks in bpf_hrtimer
and searching through it to avoid interdependencies, but this may
introduce additional delays in bpf_timer_cancel, in addition to
requiring extra state at runtime which may need to be allocated or
reused from bpf_hrtimer storage. Moreover, extra synchronization is
needed to delete these elements from the list of waiting callbacks once
hrtimer_cancel has finished.

The second patch is for a deadlock situation similar to above in
bpf_timer_cancel_and_free, but also a UAF scenario that can occur if
timer is armed before entering it, if hrtimer_running check causes the
hrtimer_cancel call to be skipped.

As seen above, synchronous hrtimer_cancel would lead to deadlock (if
same callback tries to free its timer, or two timers free each other),
therefore we queue work onto the global workqueue to ensure outstanding
timers are cancelled before bpf_hrtimer state is freed.

Further details are in the patches.
====================

Link: https://lore.kernel.org/r/20240709185440.1104957-1-memxor@gmail.com
Signed-off-by: Alexei Starovoitov <ast@kernel.org>

Trivial merge