diff options
| author | Mani Tofigh <mt4022@columbia.edu> | 2026-10-27 13:03:42 -0400 |
|---|---|---|
| committer | Alexei Starovoitov <ast@kernel.org> | 2026-10-27 19:32:26 +0000 |
| commit | 815a0a2a40d6c5985a153041231731651bc4024b (patch) | |
| tree | 0befb4da6164fdb887336d18f1c3ddf3bc125a22 /include/linux/timerqueue.h | |
| parent | 9ce722236a20e7a913b54df8b6098ec6324ba58a (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
