* [PATCH bpf-next 0/2] bpf: Fix RHash special-field recycling
@ 2026-07-26 15:51 Nuoqi Gui
2026-07-26 15:51 ` [PATCH bpf-next 1/2] bpf: Cancel RHash special fields on value recycle Nuoqi Gui
2026-07-26 15:51 ` [PATCH bpf-next 2/2] selftests/bpf: Cover RHash special-field recycle Nuoqi Gui
0 siblings, 2 replies; 7+ messages in thread
From: Nuoqi Gui @ 2026-07-26 15:51 UTC (permalink / raw)
To: Alexei Starovoitov, Daniel Borkmann, Andrii Nakryiko,
Eduard Zingerman, Kumar Kartikeya Dwivedi
Cc: Martin KaFai Lau, Song Liu, Yonghong Song, Jiri Olsa,
Emil Tsalapatis, Ihor Solodrai, Mykyta Yatsenko, Shuah Khan, bpf,
linux-kernel, linux-kselftest, Nuoqi Gui
Commit 6905f8601298 ("bpf: Allow special fields in resizable hashtab") says
that "kptr semantics under in-place updates are identical to array map."
However, RHash calls bpf_obj_free_fields() after copy_map_value(), dropping
the kptr that the copy preserves.
Use bpf_obj_cancel_fields() in the update and deferred deletion paths, as
hash and array maps do. It cancels timer, workqueue, and task-work state
while the allocator destructor releases kptrs at final reclamation.
Add a selftest that verifies a task kptr survives a BPF_EXIST update and
exercises delayed deletion.
Signed-off-by: Nuoqi Gui <gnq25@mails.tsinghua.edu.cn>
---
Nuoqi Gui (2):
bpf: Cancel RHash special fields on value recycle
selftests/bpf: Cover RHash special-field recycle
kernel/bpf/hashtab.c | 14 ++---
tools/testing/selftests/bpf/prog_tests/rhash.c | 3 +
tools/testing/selftests/bpf/progs/rhash.c | 81 ++++++++++++++++++++++++++
3 files changed, 91 insertions(+), 7 deletions(-)
---
base-commit: a23a71823352e2d792dcaae25f1ebb744acbfc0b
change-id: 20260722-f01-23-rhash-cancel-bpf-next-02a6e7ec115e
Best regards,
--
Nuoqi Gui <gnq25@mails.tsinghua.edu.cn>
^ permalink raw reply [flat|nested] 7+ messages in thread* [PATCH bpf-next 1/2] bpf: Cancel RHash special fields on value recycle 2026-07-26 15:51 [PATCH bpf-next 0/2] bpf: Fix RHash special-field recycling Nuoqi Gui @ 2026-07-26 15:51 ` Nuoqi Gui 2026-07-26 16:17 ` sashiko-bot ` (2 more replies) 2026-07-26 15:51 ` [PATCH bpf-next 2/2] selftests/bpf: Cover RHash special-field recycle Nuoqi Gui 1 sibling, 3 replies; 7+ messages in thread From: Nuoqi Gui @ 2026-07-26 15:51 UTC (permalink / raw) To: Alexei Starovoitov, Daniel Borkmann, Andrii Nakryiko, Eduard Zingerman, Kumar Kartikeya Dwivedi Cc: Martin KaFai Lau, Song Liu, Yonghong Song, Jiri Olsa, Emil Tsalapatis, Ihor Solodrai, Mykyta Yatsenko, Shuah Khan, bpf, linux-kernel, linux-kselftest, Nuoqi Gui Commit 6905f8601298 ("bpf: Allow special fields in resizable hashtab") says that "kptr semantics under in-place updates are identical to array map." However, after copy_map_value() preserves special fields, rhtab_map_update_existing() calls bpf_obj_free_fields() and drops retained kptrs. BPF_EXIST can therefore unexpectedly clear a kptr. Use bpf_obj_cancel_fields() in the update and deferred deletion paths, as hash and array maps do. It cancels timer, workqueue, and task-work state while the allocator destructor releases kptrs at final reclamation. Fixes: 6905f8601298 ("bpf: Allow special fields in resizable hashtab") Signed-off-by: Nuoqi Gui <gnq25@mails.tsinghua.edu.cn> --- kernel/bpf/hashtab.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/kernel/bpf/hashtab.c b/kernel/bpf/hashtab.c index 9f394e1aa2e8..54ea111daa8b 100644 --- a/kernel/bpf/hashtab.c +++ b/kernel/bpf/hashtab.c @@ -2865,14 +2865,14 @@ static int rhtab_map_alloc_check(union bpf_attr *attr) return htab_map_alloc_check(attr); } -static void rhtab_check_and_free_fields(struct bpf_rhtab *rhtab, - struct rhtab_elem *elem) +static void rhtab_check_and_cancel_fields(struct bpf_rhtab *rhtab, + struct rhtab_elem *elem) { if (IS_ERR_OR_NULL(rhtab->map.record)) return; - bpf_obj_free_fields(rhtab->map.record, - rhtab_elem_value(elem, rhtab->map.key_size)); + bpf_obj_cancel_fields(&rhtab->map, + rhtab_elem_value(elem, rhtab->map.key_size)); } static void rhtab_mem_dtor(void *obj, void *ctx) @@ -2964,8 +2964,8 @@ static int rhtab_delete_elem(struct bpf_rhtab *rhtab, struct rhtab_elem *elem, v rhtab_read_elem_value(&rhtab->map, copy, elem, flags); check_and_init_map_value(&rhtab->map, copy); } - /* Release internal structs: kptr, bpf_timer, task_work, wq */ - rhtab_check_and_free_fields(rhtab, elem); + /* Cancel reusable internal structs: bpf_timer, task_work, wq */ + rhtab_check_and_cancel_fields(rhtab, elem); bpf_mem_cache_free_rcu(&rhtab->ma, elem); return 0; } @@ -3027,7 +3027,7 @@ static long rhtab_map_update_existing(struct bpf_map *map, struct rhtab_elem *el * kptrs/etc. still sit in the slot. Cancel them after the copy * to match arraymap's update semantics. */ - rhtab_check_and_free_fields(rhtab, elem); + rhtab_check_and_cancel_fields(rhtab, elem); return 0; } -- 2.34.1 ^ permalink raw reply related [flat|nested] 7+ messages in thread
* Re: [PATCH bpf-next 1/2] bpf: Cancel RHash special fields on value recycle 2026-07-26 15:51 ` [PATCH bpf-next 1/2] bpf: Cancel RHash special fields on value recycle Nuoqi Gui @ 2026-07-26 16:17 ` sashiko-bot 2026-07-27 13:05 ` Mykyta Yatsenko 2026-08-03 0:11 ` Kumar Kartikeya Dwivedi 2 siblings, 0 replies; 7+ messages in thread From: sashiko-bot @ 2026-07-26 16:17 UTC (permalink / raw) To: Nuoqi Gui; +Cc: bpf Thank you for your contribution! Sashiko AI review found 4 potential issue(s) to consider: New issues: - [High] The `rhtab_map_update_existing` function fails to call `bpf_obj_free_fields()` when overwriting an existing map value, explicitly violating BTF special field cleanup rules. Pre-existing issues: - [Critical] Uninitialized spinlock acquired in `alloc_htab_elem` when `BPF_F_LOCK` is used. - [Critical] BTF special field (kptr) leak and dangerous reuse in preallocated hash maps. - [High] Missing field cancellation on locked update in `htab_map_update_elem`. -- --- Patch [1]: [PATCH bpf-next 1/2] bpf: Cancel RHash special fields on value recycle --- commit b285c707d0a30a431d69802916cd425986e713ab Author: Nuoqi Gui <gnq25@mails.tsinghua.edu.cn> bpf: Cancel RHash special fields on value recycle The patch replaces bpf_obj_free_fields() with bpf_obj_cancel_fields() in the update and deferred deletion paths for rhtab. It cancels timers and workqueues while deferring kptr release. > diff --git a/kernel/bpf/hashtab.c b/kernel/bpf/hashtab.c > index 9f394e1aa2e85..54ea111daa8bd 100644 > --- a/kernel/bpf/hashtab.c > +++ b/kernel/bpf/hashtab.c [ ... ] > @@ -3027,7 +3027,7 @@ static long rhtab_map_update_existing(struct bpf_map *map, struct rhtab_elem *el > * kptrs/etc. still sit in the slot. Cancel them after the copy > * to match arraymap's update semantics. > */ > - rhtab_check_and_free_fields(rhtab, elem); > + rhtab_check_and_cancel_fields(rhtab, elem); > return 0; > } [Severity: High] Does replacing bpf_obj_free_fields() with bpf_obj_cancel_fields() violate the subsystem guidelines for map updates? According to the BPF documentation, when overwriting an existing map value with userspace data using copy_map_value(), bpf_obj_free_fields() must be called to release resources held by the old value. Does using bpf_obj_cancel_fields() here instead fail to release resources like kptrs during the update? [Severity: High] This is a pre-existing issue, but are special fields left active during locked updates in htab_map_update_elem()? Looking at kernel/bpf/hashtab.c:htab_map_update_elem(): if (map_flags & BPF_F_LOCK) { ... copy_map_value_locked(map, htab_elem_value(l_old, key_size), value, false); return 0; } When BPF_F_LOCK is used to overwrite an existing element in-place, copy_map_value_locked() is called and the function returns 0. Is the cancellation step skipped here, leaving old special fields like timers or workqueues running indefinitely? [Severity: Critical] This is a pre-existing issue, but could alloc_htab_elem() be acquiring an uninitialized spinlock? Looking at kernel/bpf/hashtab.c:alloc_htab_elem(): l_new = bpf_mem_cache_alloc(&htab->ma); ... if (map_flags & BPF_F_LOCK) copy_map_value_locked(&htab->map, htab_elem_value(l_new, key_size), value, false); When updating a non-preallocated hash map with BPF_F_LOCK for a new key, the new element is allocated but not initialized. Because check_and_init_map_value() is not called before copy_map_value_locked(), will the kernel attempt to lock an uninitialized spinlock in the new memory? [Severity: Critical] This is a pre-existing issue, but can preallocated hash maps leak kptrs and improperly reuse them across elements? When an element is deleted, kernel/bpf/hashtab.c:free_htab_elem() cancels timers but doesn't free fields: check_and_cancel_fields(htab, l); pcpu_freelist_push(&htab->freelist, &l->fnode); Later, kernel/bpf/hashtab.c:alloc_htab_elem() pops the element and skips initialization: l_new = prealloc_lru_pop(htab, key, hash); if (!l_new) ... Because bpf_obj_free_fields() is skipped on deletion and check_and_init_map_value() is skipped on reallocation, would the new element inherit the old kptrs? Might this cause kptr resources to leak or be improperly accessed by the reallocated element? -- Sashiko AI review · https://sashiko.dev/#/patchset/20260726-f01-23-rhash-cancel-bpf-next-v1-0-6e5e1131d885@mails.tsinghua.edu.cn?part=1 ^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH bpf-next 1/2] bpf: Cancel RHash special fields on value recycle 2026-07-26 15:51 ` [PATCH bpf-next 1/2] bpf: Cancel RHash special fields on value recycle Nuoqi Gui 2026-07-26 16:17 ` sashiko-bot @ 2026-07-27 13:05 ` Mykyta Yatsenko 2026-08-03 0:11 ` Kumar Kartikeya Dwivedi 2 siblings, 0 replies; 7+ messages in thread From: Mykyta Yatsenko @ 2026-07-27 13:05 UTC (permalink / raw) To: Nuoqi Gui, Alexei Starovoitov, Daniel Borkmann, Andrii Nakryiko, Eduard Zingerman, Kumar Kartikeya Dwivedi Cc: Martin KaFai Lau, Song Liu, Yonghong Song, Jiri Olsa, Emil Tsalapatis, Ihor Solodrai, Mykyta Yatsenko, Shuah Khan, bpf, linux-kernel, linux-kselftest On 7/26/26 4:51 PM, Nuoqi Gui wrote: > Commit 6905f8601298 ("bpf: Allow special fields in resizable hashtab") says > that "kptr semantics under in-place updates are identical to array map." > However, after copy_map_value() preserves special fields, > rhtab_map_update_existing() calls bpf_obj_free_fields() and drops retained > kptrs. BPF_EXIST can therefore unexpectedly clear a kptr. > > Use bpf_obj_cancel_fields() in the update and deferred deletion paths, as > hash and array maps do. It cancels timer, workqueue, and task-work state > while the allocator destructor releases kptrs at final reclamation. > > Fixes: 6905f8601298 ("bpf: Allow special fields in resizable hashtab") > Signed-off-by: Nuoqi Gui <gnq25@mails.tsinghua.edu.cn> > --- The change looks correct, corresponding htab fix was landed around the same time as rhtab, so it was missed, and not replicated. This patch correctly updates update/deletion callsites, which guarantees that potentially NMI-unsafe kptr destructor is not called from NMI. Final destructor rhtab_mem_dtor() left unchanged. Acked-by: Mykyta Yatsenko <yatsenko@meta.com> > kernel/bpf/hashtab.c | 14 +++++++------- > 1 file changed, 7 insertions(+), 7 deletions(-) > > diff --git a/kernel/bpf/hashtab.c b/kernel/bpf/hashtab.c > index 9f394e1aa2e8..54ea111daa8b 100644 > --- a/kernel/bpf/hashtab.c > +++ b/kernel/bpf/hashtab.c > @@ -2865,14 +2865,14 @@ static int rhtab_map_alloc_check(union bpf_attr *attr) > return htab_map_alloc_check(attr); > } > > -static void rhtab_check_and_free_fields(struct bpf_rhtab *rhtab, > - struct rhtab_elem *elem) > +static void rhtab_check_and_cancel_fields(struct bpf_rhtab *rhtab, > + struct rhtab_elem *elem) > { > if (IS_ERR_OR_NULL(rhtab->map.record)) > return; > > - bpf_obj_free_fields(rhtab->map.record, > - rhtab_elem_value(elem, rhtab->map.key_size)); > + bpf_obj_cancel_fields(&rhtab->map, > + rhtab_elem_value(elem, rhtab->map.key_size)); > } > > static void rhtab_mem_dtor(void *obj, void *ctx) > @@ -2964,8 +2964,8 @@ static int rhtab_delete_elem(struct bpf_rhtab *rhtab, struct rhtab_elem *elem, v > rhtab_read_elem_value(&rhtab->map, copy, elem, flags); > check_and_init_map_value(&rhtab->map, copy); > } > - /* Release internal structs: kptr, bpf_timer, task_work, wq */ > - rhtab_check_and_free_fields(rhtab, elem); > + /* Cancel reusable internal structs: bpf_timer, task_work, wq */ > + rhtab_check_and_cancel_fields(rhtab, elem); > bpf_mem_cache_free_rcu(&rhtab->ma, elem); > return 0; > } > @@ -3027,7 +3027,7 @@ static long rhtab_map_update_existing(struct bpf_map *map, struct rhtab_elem *el > * kptrs/etc. still sit in the slot. Cancel them after the copy > * to match arraymap's update semantics. > */ > - rhtab_check_and_free_fields(rhtab, elem); > + rhtab_check_and_cancel_fields(rhtab, elem); > return 0; > } > > ^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH bpf-next 1/2] bpf: Cancel RHash special fields on value recycle 2026-07-26 15:51 ` [PATCH bpf-next 1/2] bpf: Cancel RHash special fields on value recycle Nuoqi Gui 2026-07-26 16:17 ` sashiko-bot 2026-07-27 13:05 ` Mykyta Yatsenko @ 2026-08-03 0:11 ` Kumar Kartikeya Dwivedi 2 siblings, 0 replies; 7+ messages in thread From: Kumar Kartikeya Dwivedi @ 2026-08-03 0:11 UTC (permalink / raw) To: Nuoqi Gui, Alexei Starovoitov, Daniel Borkmann, Andrii Nakryiko, Eduard Zingerman Cc: Martin KaFai Lau, Song Liu, Yonghong Song, Jiri Olsa, Emil Tsalapatis, Ihor Solodrai, Mykyta Yatsenko, Shuah Khan, bpf, linux-kernel, linux-kselftest On Sun Jul 26, 2026 at 5:51 PM CEST, Nuoqi Gui wrote: > Commit 6905f8601298 ("bpf: Allow special fields in resizable hashtab") says > that "kptr semantics under in-place updates are identical to array map." > However, after copy_map_value() preserves special fields, > rhtab_map_update_existing() calls bpf_obj_free_fields() and drops retained > kptrs. BPF_EXIST can therefore unexpectedly clear a kptr. > > Use bpf_obj_cancel_fields() in the update and deferred deletion paths, as > hash and array maps do. It cancels timer, workqueue, and task-work state > while the allocator destructor releases kptrs at final reclamation. > > Fixes: 6905f8601298 ("bpf: Allow special fields in resizable hashtab") > Signed-off-by: Nuoqi Gui <gnq25@mails.tsinghua.edu.cn> > --- I don't think this is enough. Upon reading the code, I am suspicious about the check_and_init_map_value() in rhtab_map_update_elem() (post this change). It will likely end up zeroing non-zero kptrs and leaking them, since recycled elements will retain the value. Dtor path is fine but that only covers the case where freed element is never reused and only freed on map destruction. It might amount to simply remove that function call from the function. The other user in delete path looks fine since it operates on output buffer. Please make sure to also add tests for such behavior, having a map of at most one element should allow for its reuse, you might have to reinvoke the program, once doing update, then another doing delete, then another doing update to be able to rellocate the same element. I am sure it can be figured out (with AI's help), but please validate it using tests. pw-bot: cr > kernel/bpf/hashtab.c | 14 +++++++------- > 1 file changed, 7 insertions(+), 7 deletions(-) > > diff --git a/kernel/bpf/hashtab.c b/kernel/bpf/hashtab.c > index 9f394e1aa2e8..54ea111daa8b 100644 > --- a/kernel/bpf/hashtab.c > +++ b/kernel/bpf/hashtab.c > @@ -2865,14 +2865,14 @@ static int rhtab_map_alloc_check(union bpf_attr *attr) > return htab_map_alloc_check(attr); > } > > -static void rhtab_check_and_free_fields(struct bpf_rhtab *rhtab, > - struct rhtab_elem *elem) > +static void rhtab_check_and_cancel_fields(struct bpf_rhtab *rhtab, > + struct rhtab_elem *elem) > { > if (IS_ERR_OR_NULL(rhtab->map.record)) > return; > > - bpf_obj_free_fields(rhtab->map.record, > - rhtab_elem_value(elem, rhtab->map.key_size)); > + bpf_obj_cancel_fields(&rhtab->map, > + rhtab_elem_value(elem, rhtab->map.key_size)); > } > > static void rhtab_mem_dtor(void *obj, void *ctx) > @@ -2964,8 +2964,8 @@ static int rhtab_delete_elem(struct bpf_rhtab *rhtab, struct rhtab_elem *elem, v > rhtab_read_elem_value(&rhtab->map, copy, elem, flags); > check_and_init_map_value(&rhtab->map, copy); > } > - /* Release internal structs: kptr, bpf_timer, task_work, wq */ > - rhtab_check_and_free_fields(rhtab, elem); > + /* Cancel reusable internal structs: bpf_timer, task_work, wq */ > + rhtab_check_and_cancel_fields(rhtab, elem); > bpf_mem_cache_free_rcu(&rhtab->ma, elem); > return 0; > } > @@ -3027,7 +3027,7 @@ static long rhtab_map_update_existing(struct bpf_map *map, struct rhtab_elem *el > * kptrs/etc. still sit in the slot. Cancel them after the copy > * to match arraymap's update semantics. > */ > - rhtab_check_and_free_fields(rhtab, elem); > + rhtab_check_and_cancel_fields(rhtab, elem); > return 0; > } > ^ permalink raw reply [flat|nested] 7+ messages in thread
* [PATCH bpf-next 2/2] selftests/bpf: Cover RHash special-field recycle 2026-07-26 15:51 [PATCH bpf-next 0/2] bpf: Fix RHash special-field recycling Nuoqi Gui 2026-07-26 15:51 ` [PATCH bpf-next 1/2] bpf: Cancel RHash special fields on value recycle Nuoqi Gui @ 2026-07-26 15:51 ` Nuoqi Gui 2026-07-26 16:17 ` sashiko-bot 1 sibling, 1 reply; 7+ messages in thread From: Nuoqi Gui @ 2026-07-26 15:51 UTC (permalink / raw) To: Alexei Starovoitov, Daniel Borkmann, Andrii Nakryiko, Eduard Zingerman, Kumar Kartikeya Dwivedi Cc: Martin KaFai Lau, Song Liu, Yonghong Song, Jiri Olsa, Emil Tsalapatis, Ihor Solodrai, Mykyta Yatsenko, Shuah Khan, bpf, linux-kernel, linux-kselftest, Nuoqi Gui Add regression coverage for RHash value recycling with referenced kptrs. Store a referenced task kptr and update the value with BPF_EXIST. Verify that bpf_kptr_xchg() still returns the kptr. Then store another task kptr and delete the element to exercise the delayed reclamation path. Signed-off-by: Nuoqi Gui <gnq25@mails.tsinghua.edu.cn> --- tools/testing/selftests/bpf/prog_tests/rhash.c | 3 + tools/testing/selftests/bpf/progs/rhash.c | 81 ++++++++++++++++++++++++++ 2 files changed, 84 insertions(+) diff --git a/tools/testing/selftests/bpf/prog_tests/rhash.c b/tools/testing/selftests/bpf/prog_tests/rhash.c index 98bb66907b7f..5bf2de828361 100644 --- a/tools/testing/selftests/bpf/prog_tests/rhash.c +++ b/tools/testing/selftests/bpf/prog_tests/rhash.c @@ -180,4 +180,7 @@ void test_rhash(void) if (test__start_subtest("test_rhash_iter")) rhash_iter_test(); + + if (test__start_subtest("test_rhash_special_fields_recycle")) + rhash_run("test_rhash_special_fields_recycle"); } diff --git a/tools/testing/selftests/bpf/progs/rhash.c b/tools/testing/selftests/bpf/progs/rhash.c index fc2dac3a719e..d28d115cb74e 100644 --- a/tools/testing/selftests/bpf/progs/rhash.c +++ b/tools/testing/selftests/bpf/progs/rhash.c @@ -19,6 +19,11 @@ struct elem { int val; }; +struct special_elem { + struct task_struct __kptr * task; + int val; +}; + struct { __uint(type, BPF_MAP_TYPE_RHASH); __uint(map_flags, BPF_F_NO_PREALLOC); @@ -27,6 +32,17 @@ struct { __type(value, struct elem); } rhmap SEC(".maps"); +struct { + __uint(type, BPF_MAP_TYPE_RHASH); + __uint(map_flags, BPF_F_NO_PREALLOC); + __uint(max_entries, 4); + __type(key, int); + __type(value, struct special_elem); +} special_fields SEC(".maps"); + +struct task_struct *bpf_task_acquire(struct task_struct *p) __ksym; +void bpf_task_release(struct task_struct *p) __ksym; + SEC("syscall") int test_rhash_lookup_update(void *ctx) { @@ -246,3 +262,68 @@ int test_rhash_delete_nonexistent(void *ctx) err = 0; return 0; } + +SEC("syscall") +int test_rhash_special_fields_recycle(void *ctx) +{ + struct special_elem val1 = { .val = 1 }; + struct special_elem val2 = { .val = 2 }; + struct task_struct *task, *old; + struct special_elem *elem; + int key = 0; + + err = 1; + if (bpf_map_update_elem(&special_fields, &key, &val1, BPF_NOEXIST)) + return 1; + + err = 2; + elem = bpf_map_lookup_elem(&special_fields, &key); + if (!elem) + return 2; + + err = 3; + task = bpf_task_acquire(bpf_get_current_task_btf()); + if (!task) + return 3; + + err = 4; + old = bpf_kptr_xchg(&elem->task, task); + if (old) { + bpf_task_release(old); + return 4; + } + + err = 5; + if (bpf_map_update_elem(&special_fields, &key, &val2, BPF_EXIST)) + return 5; + + err = 6; + elem = bpf_map_lookup_elem(&special_fields, &key); + if (!elem) + return 6; + + err = 7; + task = bpf_kptr_xchg(&elem->task, NULL); + if (!task) + return 7; + bpf_task_release(task); + + err = 8; + task = bpf_task_acquire(bpf_get_current_task_btf()); + if (!task) + return 8; + + err = 9; + old = bpf_kptr_xchg(&elem->task, task); + if (old) { + bpf_task_release(old); + return 9; + } + + err = 10; + if (bpf_map_delete_elem(&special_fields, &key)) + return 10; + + err = 0; + return 0; +} -- 2.34.1 ^ permalink raw reply related [flat|nested] 7+ messages in thread
* Re: [PATCH bpf-next 2/2] selftests/bpf: Cover RHash special-field recycle 2026-07-26 15:51 ` [PATCH bpf-next 2/2] selftests/bpf: Cover RHash special-field recycle Nuoqi Gui @ 2026-07-26 16:17 ` sashiko-bot 0 siblings, 0 replies; 7+ messages in thread From: sashiko-bot @ 2026-07-26 16:17 UTC (permalink / raw) To: Nuoqi Gui; +Cc: bpf Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider: - [High] The RHash map implementation leaks BTF special fields (such as kptrs) during in-place updates and element recycling by failing to call bpf_obj_free_fields(). - [Medium] The new selftest test_rhash_special_fields_recycle incorrectly asserts and enforces a kernel memory leak regarding BTF special fields. -- --- Patch [2]: [PATCH bpf-next 2/2] selftests/bpf: Cover RHash special-field recycle --- commit d7b4034e22767ea5cd89689a56855953c3b5c45a Author: Nuoqi Gui <gnq25@mails.tsinghua.edu.cn> selftests/bpf: Cover RHash special-field recycle This commit adds regression coverage for RHash value recycling with referenced kptrs. It stores a referenced task kptr and updates the value with BPF_EXIST, then verifies that bpf_kptr_xchg() still returns the kptr. Finally, it deletes the element to exercise the delayed reclamation path. > diff --git a/tools/testing/selftests/bpf/progs/rhash.c b/tools/testing/selftests/bpf/progs/rhash.c > index fc2dac3a719e9..d28d115cb74e7 100644 > --- a/tools/testing/selftests/bpf/progs/rhash.c > +++ b/tools/testing/selftests/bpf/progs/rhash.c [ ... ] > + err = 5; > + if (bpf_map_update_elem(&special_fields, &key, &val2, BPF_EXIST)) > + return 5; > + > + err = 6; > + elem = bpf_map_lookup_elem(&special_fields, &key); > + if (!elem) > + return 6; > + > + err = 7; > + task = bpf_kptr_xchg(&elem->task, NULL); > + if (!task) > + return 7; [Severity: Medium] Is it intentional for this test to codify a kernel memory leak as a valid feature? The test updates the element using bpf_map_update_elem() with val2 (which has no task kptr) but then expects the old kptr to still be present and valid in the map. According to the BPF subsystem guidelines, when a map element is overwritten, bpf_obj_free_fields() must be called to release resources held by the old value. By asserting that the old kptr survives the map update, the test appears to enforce a bug where bpf_obj_free_fields() is missing. [Severity: High] Could this highlight a resource leak in the underlying RHash map implementation? Looking at the RHash implementation in kernel/bpf/hashtab.c, rhtab_map_update_existing() appears to overwrite the old value using copy_map_value() but misses the required bpf_obj_free_fields() call. Additionally, when deleting an element: kernel/bpf/hashtab.c:rhtab_delete_elem() { ... /* Cancel reusable internal structs: bpf_timer, task_work, wq */ rhtab_check_and_cancel_fields(rhtab, elem); ... } It seems to skip freeing kptrs, leaking the references. Should bpf_obj_free_fields() be called during these operations to properly release kernel resources like task_structs? > + bpf_task_release(task); > + > + err = 8; > + task = bpf_task_acquire(bpf_get_current_task_btf()); > + if (!task) > + return 8; -- Sashiko AI review · https://sashiko.dev/#/patchset/20260726-f01-23-rhash-cancel-bpf-next-v1-0-6e5e1131d885@mails.tsinghua.edu.cn?part=2 ^ permalink raw reply [flat|nested] 7+ messages in thread
end of thread, other threads:[~2026-08-03 0:11 UTC | newest] Thread overview: 7+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2026-07-26 15:51 [PATCH bpf-next 0/2] bpf: Fix RHash special-field recycling Nuoqi Gui 2026-07-26 15:51 ` [PATCH bpf-next 1/2] bpf: Cancel RHash special fields on value recycle Nuoqi Gui 2026-07-26 16:17 ` sashiko-bot 2026-07-27 13:05 ` Mykyta Yatsenko 2026-08-03 0:11 ` Kumar Kartikeya Dwivedi 2026-07-26 15:51 ` [PATCH bpf-next 2/2] selftests/bpf: Cover RHash special-field recycle Nuoqi Gui 2026-07-26 16:17 ` sashiko-bot
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox