From: sashiko-bot@kernel.org
To: "Luo Gengkun" <luogengkun2@huawei.com>
Cc: bpf@vger.kernel.org
Subject: Re: [PATCH] bpf: defer freeing htab internal structs to workqueue to fix sleep-in-atomic
Date: Sat, 06 Jun 2026 02:36:47 +0000 [thread overview]
Message-ID: <20260606023647.6D1D11F00893@smtp.kernel.org> (raw)
In-Reply-To: <20260606022827.3553277-1-luogengkun2@huawei.com>
Thank you for your contribution! Sashiko AI review found 4 potential issue(s) to consider:
New issues:
- [Critical] Incorrect `container_of` usage in `htab_map_free_internal_structs_deferred` computes an invalid map pointer, leading to severe memory corruption and kernel panic.
- [High] Unbalanced `bpf_map_inc()` when `schedule_work()` returns false causes a permanent map reference leak.
- [High] Deferring the clearance of hash map internal structs to a workqueue creates a data race where active timers/kptrs can be wrongly destroyed if the map is concurrently resurrected.
Pre-existing issues:
- [High] Unsafe non-RCU list traversal under RCU read lock allows concurrent modifications to cause data races and torn pointers.
--
commit 8d67520d6573d4b74187481274921ee2cb635076
Author: Luo Gengkun <luogengkun2@huawei.com>
bpf: defer freeing htab internal structs to workqueue to fix sleep-in-atomic
This commit reverts commit 4f375ade6aa9 to restore VFS RCU protection, and
defers the freeing of htab internal structs to a workqueue. This avoids a
sleep-in-atomic bug that occurs when calling cond_resched() inside an RCU
grace period.
> diff --git a/kernel/bpf/hashtab.c b/kernel/bpf/hashtab.c
> index 3dd9b4924ae4f..6d6f1faeec67a 100644
> --- a/kernel/bpf/hashtab.c
> +++ b/kernel/bpf/hashtab.c
> @@ -102,6 +102,7 @@ struct bpf_htab {
> u32 n_buckets; /* number of hash buckets */
> u32 elem_size; /* size of each element in bytes */
> u32 hashrnd;
> + struct work_struct work;
> };
[ ... ]
> @@ -1606,18 +1610,27 @@ static void htab_free_malloced_internal_structs(struct bpf_htab *htab)
> rcu_read_unlock();
> }
[Severity: High]
This is a pre-existing issue, but looking at the function
htab_free_malloced_internal_structs() ending here:
Is it safe to use hlist_nulls_for_each_entry() inside the RCU read lock?
While the map's usercnt is zero, attached BPF programs can still execute in
parallel and modify the map. Since hlist_nulls_for_each_entry() does not use
rcu_dereference(), couldn't concurrent modifications cause torn pointers
and lead to data races or infinite loops?
Should this use hlist_nulls_for_each_entry_rcu() instead?
> -static void htab_map_free_internal_structs(struct bpf_map *map)
> +static void htab_map_free_internal_structs_deferred(struct work_struct *work)
> {
> + struct bpf_map *map = container_of(work, struct bpf_map, work);
> struct bpf_htab *htab = container_of(map, struct bpf_htab, map);
[Severity: Critical]
Is the container_of macro calculating the correct map pointer here?
The work item was initialized using &htab->work, but here it is cast via
container_of(work, struct bpf_map, work). Since 'work' is a member of
struct bpf_htab and not struct bpf_map, doesn't this shift the map pointer
into the middle of the struct instead of its start?
Could this lead to memory corruption when bpf_map_put(map) is subsequently
called with the invalid pointer?
Should this be calculated as:
htab = container_of(work, struct bpf_htab, work);
map = &htab->map;
> - /* We only free internal structs on uref dropping to zero */
> - if (!bpf_map_has_internal_structs(map))
> - return;
> -
> if (htab_is_prealloc(htab))
> htab_free_prealloced_internal_structs(htab);
> else
> htab_free_malloced_internal_structs(htab);
> + bpf_map_put(map);
> +}
> +
> +static void htab_map_free_internal_structs(struct bpf_map *map)
> +{
> + struct bpf_htab *htab = container_of(map, struct bpf_htab, map);
> + /* We only free internal structs on uref dropping to zero */
> + if (!bpf_map_has_internal_structs(map))
> + return;
> +
> + bpf_map_inc(map);
> + schedule_work(&htab->work);
[Severity: High]
What happens if schedule_work() returns false?
A userspace program could repeatedly fetch the map via BPF_MAP_GET_FD_BY_ID
and close the file descriptor. Each closure drops usercnt to 0, triggering
this function.
Since bpf_map_inc() is called unconditionally, but schedule_work() returns
false if the work is already pending, won't this result in unbalanced
reference counts and permanently leak the BPF map?
[Severity: High]
Does deferring this operation to a workqueue introduce a race condition?
When usercnt reaches zero, we queue the internal structs (like timers and
kptrs) for deletion. Because map->refcnt can still be positive, can't
userspace immediately resurrect the map via BPF_MAP_GET_FD_BY_ID, bumping
usercnt back above zero?
If new timers or kptrs are then inserted, won't the deferred work eventually
run and indiscriminately destroy the internal structs of a now-active map?
> }
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260606022827.3553277-1-luogengkun2@huawei.com?part=1
next prev parent reply other threads:[~2026-06-06 2:36 UTC|newest]
Thread overview: 5+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-06-06 2:28 [PATCH] bpf: defer freeing htab internal structs to workqueue to fix sleep-in-atomic Luo Gengkun
2026-06-06 2:36 ` sashiko-bot [this message]
2026-06-06 3:25 ` bot+bpf-ci
2026-06-07 19:03 ` Mykyta Yatsenko
2026-06-08 1:25 ` Luo Gengkun
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=20260606023647.6D1D11F00893@smtp.kernel.org \
--to=sashiko-bot@kernel.org \
--cc=bpf@vger.kernel.org \
--cc=luogengkun2@huawei.com \
--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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox