From: sashiko-bot@kernel.org
To: "Alexei Starovoitov" <alexei.starovoitov@gmail.com>, bpf@vger.kernel.org
Subject: Re: [PATCH bpf-next v2 31/43] bpf: Keep values of a dead owner for sleepable programs
Date: Sat, 17 Oct 2026 17:06:34 +0000 [thread overview]
Message-ID: <sashiko-outbox-175685@kernel.org> (raw)
In-Reply-To: <20261017163745.3341787-32-alexei.starovoitov@gmail.com>
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [High] bpf: special BTF fields leaked in bpf_selem_unlink_nofail() race
--
commit 441f9cc60cc3e26f38a89830b7d3f94a34c7d383
Author: Josef Bacik <josef@toxicpanda.com>
bpf: Keep values of a dead owner for sleepable programs
This commit defers freeing BPF local storage elements and their special BTF
fields until after an RCU Tasks Trace grace period when an owner dies and
the map may be accessed by sleepable BPF programs, including maps that have
been used as inner maps.
> diff --git a/kernel/bpf/bpf_local_storage.c b/kernel/bpf/bpf_local_storage.c
> index 49ea00c993909..699430f971787 100644
> --- a/kernel/bpf/bpf_local_storage.c
> +++ b/kernel/bpf/bpf_local_storage.c
> @@ -352,7 +352,8 @@ int bpf_selem_unlink(struct bpf_local_storage_elem *selem)
> static void bpf_selem_unlink_nofail(struct bpf_local_storage_elem *selem,
> struct bpf_local_storage_map_bucket *b)
> {
> - bool in_map_free = !!b, free_storage = false;
> + bool in_map_free = !!b, free_storage = false, sleepable_users = false;
> + bool keep_fields = false;
> struct bpf_local_storage *local_storage;
> struct bpf_local_storage_map *smap;
> unsigned long flags;
> @@ -362,17 +363,26 @@ static void bpf_selem_unlink_nofail(struct bpf_local_storage_elem *selem,
> smap = rcu_dereference_check(SDATA(selem)->smap, bpf_rcu_lock_held());
>
> if (smap) {
> + /* A map that is freed, or NULL here, has no program left. */
> + sleepable_users = !in_map_free &&
> + (atomic64_read(&smap->map.sleepable_refcnt) ||
> + READ_ONCE(smap->map.was_inner_map));
> b = b ? : select_bucket(smap, local_storage);
> err = raw_res_spin_lock_irqsave(&b->lock, flags);
> if (!err) {
> /*
> * Call bpf_obj_free_fields() under b->lock to make sure it is done
> * exactly once for an selem. Safe to free special fields immediately
> - * as no BPF program should be referencing the selem.
> + * as no BPF program should be referencing the selem, unless it
> + * is sleepable: see below.
> */
> if (likely(selem_linked_to_map(selem))) {
> hlist_del_init_rcu(&selem->map_node);
> - bpf_obj_free_fields(smap->map.record, SDATA(selem)->data);
> + if (sleepable_users)
> + keep_fields = true;
> + else
> + bpf_obj_free_fields(smap->map.record,
> + SDATA(selem)->data);
> unlink++;
> }
> raw_res_spin_unlock_irqrestore(&b->lock, flags);
> @@ -387,7 +397,14 @@ static void bpf_selem_unlink_nofail(struct bpf_local_storage_elem *selem,
> * with selem1 as raw_res_spin_lock_irqsave() returns -ETIMEDOUT.
> */
> WARN_ON_ONCE(err && in_map_free);
> - if (!err || in_map_free)
> + /*
> + * A sleepable program can still use, and fill, the fields of a value
> + * that it got before it let go of the owner. As for bpf_selem_unlink(),
> + * bpf_selem_free_trace_rcu() frees them, and takes smap for that:
> + * map_free() waits for this RCU read side critical section and then
> + * for the callback.
> + */
> + if ((!err && !keep_fields) || in_map_free)
> RCU_INIT_POINTER(SDATA(selem)->smap, NULL);
> }
[Severity: High]
Can this race between bpf_local_storage_destroy() and
bpf_local_storage_map_free() leak the special BTF fields in
SDATA(selem)->data (such as referenced kptrs or pinned uptr pages) when
smap->map.was_inner_map is true?
Once a local storage map has been inserted into an outer map via
bpf_map_fd_get_ptr(), smap->map.was_inner_map remains permanently true even
when bpf_local_storage_map_free() later tears down the map.
If bpf_local_storage_destroy() and bpf_local_storage_map_free() concurrently
call bpf_selem_unlink_nofail() on the same selem and both read a non-NULL
smap before either clears SDATA(selem)->smap:
1. In bpf_local_storage_destroy() (in_map_free is false), sleepable_users
evaluates to true because smap->map.was_inner_map is true. If it acquires
b->lock first, it sees selem_linked_to_map(selem), unlinks selem->map_node,
and sets its local keep_fields = true instead of calling
bpf_obj_free_fields(). It then leaves SDATA(selem)->smap non-NULL so
bpf_selem_free_trace_rcu() can free the fields later.
2. In the racing bpf_local_storage_map_free() (in_map_free is true), after it
acquires b->lock, selem_linked_to_map(selem) is now false, so it also skips
bpf_obj_free_fields(). However, because in_map_free is true (and its local
keep_fields is false), it then executes:
if ((!err && !keep_fields) || in_map_free)
RCU_INIT_POINTER(SDATA(selem)->smap, NULL);
3. When bpf_selem_free_trace_rcu() later runs after the RCU Tasks Trace grace
period:
smap = rcu_dereference_check(SDATA(selem)->smap, 1);
if (smap)
bpf_obj_free_fields(smap->map.record, SDATA(selem)->data);
smap is now NULL, so bpf_obj_free_fields() is skipped there as well and
never runs for selem.
[ ... ]
>
> --
> 2.51.2
>
--
Sashiko AI review · https://sashiko.dev/#/patchset/20261017163745.3341787-1-alexei.starovoitov@gmail.com?part=31
next prev parent reply other threads:[~2026-10-17 17:06 UTC|newest]
Thread overview: 60+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-10-17 16:37 [PATCH bpf-next v2 00/43] bpf: Memory safety, lifetime and locking fixes Alexei Starovoitov
2026-10-17 16:37 ` [PATCH bpf-next v2 01/43] bpf: use the frame mem type in devmap egress XDP Alexei Starovoitov
2026-10-17 16:37 ` [PATCH bpf-next v2 02/43] bpf: forbid sleeping in hash map for_each callbacks Alexei Starovoitov
2026-10-17 16:37 ` [PATCH bpf-next v2 03/43] bpf: don't leak the inode when token creation fails Alexei Starovoitov
2026-10-17 16:37 ` [PATCH bpf-next v2 04/43] bpf: don't hand out a linked element as extra element Alexei Starovoitov
2026-10-17 16:37 ` [PATCH bpf-next v2 05/43] bpf: reject sleepable programs for task_vma iterator Alexei Starovoitov
2026-10-17 17:16 ` bot+bpf-ci
2026-10-17 16:37 ` [PATCH bpf-next v2 06/43] bpf: forbid sleeping in bpf_find_vma() callbacks Alexei Starovoitov
2026-10-17 16:37 ` [PATCH bpf-next v2 07/43] bpf: look at all 64 bits of a BPF_JSET mask on 32-bit Alexei Starovoitov
2026-10-17 16:37 ` [PATCH bpf-next v2 08/43] bpf: don't let bpf_skb_adjust_room() use up the MSS Alexei Starovoitov
2026-10-17 16:37 ` [PATCH bpf-next v2 09/43] bpf: Read the probe of a perf event under event_mutex Alexei Starovoitov
2026-10-17 16:37 ` [PATCH bpf-next v2 10/43] bpf: Don't saturate owner_refcnt on the last unpin Alexei Starovoitov
2026-10-17 16:37 ` [PATCH bpf-next v2 11/43] bpf: Validate the SRH which End.DT6 uncovers in End.BPF Alexei Starovoitov
2026-10-17 16:37 ` [PATCH bpf-next v2 12/43] bpf: Pull the inner header for End.DT6 " Alexei Starovoitov
2026-10-17 16:37 ` [PATCH bpf-next v2 13/43] bpf: Update the SRH state if End.B6 fails late Alexei Starovoitov
2026-10-17 16:37 ` [PATCH bpf-next v2 14/43] bpf: Clear sk_refcnt of a clone before its storage is linked Alexei Starovoitov
2026-10-17 16:37 ` [PATCH bpf-next v2 15/43] bpf: Fix NULL deref in the sk_storage map iterator Alexei Starovoitov
2026-10-17 16:37 ` [PATCH bpf-next v2 16/43] bpf: Link the first element after its storage is published Alexei Starovoitov
2026-10-17 17:17 ` bot+bpf-ci
2026-10-17 16:37 ` [PATCH bpf-next v2 17/43] bpf: Hold the socket in the sk_storage map iterator Alexei Starovoitov
2026-10-17 16:37 ` [PATCH bpf-next v2 18/43] bpf: Bound the nesting that the BTF show code follows Alexei Starovoitov
2026-10-17 16:54 ` sashiko-bot
2026-10-17 16:37 ` [PATCH bpf-next v2 19/43] bpf: Check the new program of an iterator link update Alexei Starovoitov
2026-10-17 16:37 ` [PATCH bpf-next v2 20/43] bpf: Fix stale offload->prog pointer after realloc Alexei Starovoitov
2026-10-17 16:37 ` [PATCH bpf-next v2 21/43] bpf: Don't bind a program to a netdev that goes away Alexei Starovoitov
2026-10-17 16:37 ` [PATCH bpf-next v2 22/43] bpf: Keep a program until its bpf_wq callback has ended Alexei Starovoitov
2026-10-17 16:37 ` [PATCH bpf-next v2 23/43] bpf: Count sleepable callbacks as sleepable map users Alexei Starovoitov
2026-10-17 16:37 ` [PATCH bpf-next v2 24/43] bpf: Check the maps that sleepable callbacks use Alexei Starovoitov
2026-10-17 16:37 ` [PATCH bpf-next v2 25/43] bpf: Assume no bounds for buffers behind a tail call Alexei Starovoitov
2026-10-17 16:37 ` [PATCH bpf-next v2 26/43] bpf: Don't take an extension for an iterator program Alexei Starovoitov
2026-10-17 17:17 ` bot+bpf-ci
2026-10-17 16:37 ` [PATCH bpf-next v2 27/43] bpf: Assume no bounds for a writable tp with tail calls Alexei Starovoitov
2026-10-17 16:37 ` [PATCH bpf-next v2 28/43] bpf: Don't take an extension for a writable raw tracepoint program Alexei Starovoitov
2026-10-17 17:17 ` bot+bpf-ci
2026-10-17 16:37 ` [PATCH bpf-next v2 29/43] bpf: Keep iterator programs off special map fields Alexei Starovoitov
2026-10-17 16:37 ` [PATCH bpf-next v2 30/43] bpf: Free what map_free() unlinks for sleepable readers Alexei Starovoitov
2026-10-17 16:37 ` [PATCH bpf-next v2 31/43] bpf: Keep values of a dead owner for sleepable programs Alexei Starovoitov
2026-10-17 17:06 ` sashiko-bot [this message]
2026-10-17 16:37 ` [PATCH bpf-next v2 32/43] bpf: Don't take an extension for a function that runs sleepable Alexei Starovoitov
2026-10-17 16:37 ` [PATCH bpf-next v2 33/43] bpf: Keep the symbols of a program until it has ended Alexei Starovoitov
2026-10-17 17:17 ` bot+bpf-ci
2026-10-17 16:37 ` [PATCH bpf-next v2 34/43] bpf: Use the socket of a sk_lookup test run under RCU Alexei Starovoitov
2026-10-17 16:37 ` [PATCH bpf-next v2 35/43] bpf, cpumap: Hold the device of frames in the queue Alexei Starovoitov
2026-10-17 17:17 ` bot+bpf-ci
2026-10-17 16:37 ` [PATCH bpf-next v2 36/43] bpf: Drop packet pointers behind kfuncs writing an skb Alexei Starovoitov
2026-10-17 16:37 ` [PATCH bpf-next v2 37/43] bpf: Let bpf_dynptr_write() mark a global function Alexei Starovoitov
2026-10-17 17:04 ` bot+bpf-ci
2026-10-17 16:37 ` [PATCH bpf-next v2 38/43] bpf: Don't take a dynptr argument for a local dynptr Alexei Starovoitov
2026-10-17 17:17 ` bot+bpf-ci
2026-10-17 16:37 ` [PATCH bpf-next v2 39/43] bpf: Refuse the prologue for an extension that cannot take it Alexei Starovoitov
2026-10-17 17:08 ` sashiko-bot
2026-10-17 17:16 ` bot+bpf-ci
2026-10-17 16:37 ` [PATCH bpf-next v2 40/43] bpf: Unclone the skb for kfuncs that write through a dynptr Alexei Starovoitov
2026-10-17 17:17 ` bot+bpf-ci
2026-10-17 16:37 ` [PATCH bpf-next v2 41/43] bpf: Follow the head if an skb is written from a slice Alexei Starovoitov
2026-10-17 16:37 ` [PATCH bpf-next v2 42/43] bpf: Use memmove() to store bytes in an skb Alexei Starovoitov
2026-10-17 17:16 ` bot+bpf-ci
2026-10-17 16:37 ` [PATCH bpf-next v2 43/43] bpf: Refuse packet slices for packet-changing helpers Alexei Starovoitov
2026-10-17 17:17 ` bot+bpf-ci
2026-10-17 22:10 ` [PATCH bpf-next v2 00/43] bpf: Memory safety, lifetime and locking fixes patchwork-bot+netdevbpf
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=sashiko-outbox-175685@kernel.org \
--to=sashiko-bot@kernel.org \
--cc=alexei.starovoitov@gmail.com \
--cc=bpf@vger.kernel.org \
--cc=sashiko-reviews@lists.linux.dev \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.