summaryrefslogtreecommitdiff
path: root/include/linux/timerqueue.h
diff options
context:
space:
mode:
authorMani Tofigh <mt4022@columbia.edu>2026-10-27 13:03:42 -0400
committerAlexei Starovoitov <ast@kernel.org>2026-10-27 19:32:26 +0000
commit815a0a2a40d6c5985a153041231731651bc4024b (patch)
tree0befb4da6164fdb887336d18f1c3ddf3bc125a22 /include/linux/timerqueue.h
parent9ce722236a20e7a913b54df8b6098ec6324ba58a (diff)
bpf: Fix bpf_timer callback running on a freed map
A bpf_timer in an inner map can fire after the map has been freed, and bpf_timer_cb() then reads the freed map: [ 50.709520] BUG: KASAN: slab-use-after-free in bpf_timer_cb+0x249/0x290 [ 50.709540] Read of size 4 at addr ff11000003bc1030 by task bpftimer/72 ... [ 50.710783] Freed by task 12: ... [ 50.710826] bpf_map_free+0x1a2/0x380 When user space closes the map, its timers are cancelled and their callbacks are cleared. Since commit 1bfbc267ec91 ("bpf: Enable bpf_timer and bpf_wq in any context"), bpf_timer_set_callback() and bpf_timer_start() run without a lock, so a program that found the timer just before the close can still use it afterwards: Task A Task B Task C ------ ------ ------ bpf_timer_start() finds the timer bpf_timer_set_callback() finds the timer close(map_fd) clears the callback cancels the timer sets the callback arms the timer deletes the map from the outer map map is freed the timer fires bpf_timer_cb() reads the freed map The timer is cancelled once more when it is finally freed, but that happens well after the inner map is freed, so a timer started this way can still fire on the freed map. Clear the timer's map pointer in bpf_async_cancel_and_free() before the map can be freed, and make the bpf_timer and bpf_wq callbacks return early when it is NULL. The map is not freed until callbacks that are already running have finished, so a callback either sees the map while it is still valid or sees NULL. The reproducer below calls the two helpers in a loop on two CPUs while a third CPU keeps creating an inner map with a timer, closing it and removing it from the outer map. This bug was identified and confirmed with the help of a deterministic hypervisor currently under development, but the non-deterministic C reproducer can typically trigger it in the 1-50s time range. With the fix, nothing is triggered after 600 seconds. Fixes: 1bfbc267ec91 ("bpf: Enable bpf_timer and bpf_wq in any context") Signed-off-by: Mani Tofigh <mt4022@columbia.edu> Signed-off-by: Alexei Starovoitov <ast@kernel.org> Tested-by: Mahe Tardy <mahe.tardy@gmail.com> Link: https://patch.msgid.link/20261027-bpf-timer-freed-map-v1-1-30402b0ee99b@columbia.edu
Diffstat (limited to 'include/linux/timerqueue.h')
0 files changed, 0 insertions, 0 deletions