* [PATCH bpf-next v1 0/2] Fix unique fields for nested structs in BTF @ 2026-07-19 14:23 Kumar Kartikeya Dwivedi 2026-07-19 14:23 ` [PATCH bpf-next v1 1/2] bpf: Preserve unique-field state across nested structs Kumar Kartikeya Dwivedi 2026-07-19 14:24 ` [PATCH bpf-next v1 2/2] selftests/bpf: Test duplicate unique fields in " Kumar Kartikeya Dwivedi 0 siblings, 2 replies; 7+ messages in thread From: Kumar Kartikeya Dwivedi @ 2026-07-19 14:23 UTC (permalink / raw) To: bpf Cc: Alexei Starovoitov, Andrii Nakryiko, Daniel Borkmann, Eduard Zingerman, Emil Tsalapatis, kkd, kernel-team Fix constraint of certain fields that have to be unique when nested structs are present. See commit logs for details. Kumar Kartikeya Dwivedi (2): bpf: Preserve unique-field state across nested structs selftests/bpf: Test duplicate unique fields in nested structs kernel/bpf/btf.c | 26 +++++++++++--------- tools/testing/selftests/bpf/prog_tests/btf.c | 26 ++++++++++++++++++++ 2 files changed, 40 insertions(+), 12 deletions(-) base-commit: ecf11bc5f56abb3a2219a8c75e8a5b54467d1781 -- 2.53.0 ^ permalink raw reply [flat|nested] 7+ messages in thread
* [PATCH bpf-next v1 1/2] bpf: Preserve unique-field state across nested structs 2026-07-19 14:23 [PATCH bpf-next v1 0/2] Fix unique fields for nested structs in BTF Kumar Kartikeya Dwivedi @ 2026-07-19 14:23 ` Kumar Kartikeya Dwivedi 2026-07-19 14:34 ` sashiko-bot 2026-07-19 14:24 ` [PATCH bpf-next v1 2/2] selftests/bpf: Test duplicate unique fields in " Kumar Kartikeya Dwivedi 1 sibling, 1 reply; 7+ messages in thread From: Kumar Kartikeya Dwivedi @ 2026-07-19 14:23 UTC (permalink / raw) To: bpf Cc: Alexei Starovoitov, Andrii Nakryiko, Daniel Borkmann, Eduard Zingerman, Emil Tsalapatis, kkd, kernel-team btf_find_struct_field() initializes a fresh seen mask for every recursive descent. Unique special fields in different levels of the same aggregate therefore do not see one another. The duplicate fields can reach btf_parse_fields(), where they trigger an invariant WARN_ON_ONCE(). A crafted user BTF can consequently trigger the warning before map creation checks capabilities. Initialize the seen mask once in btf_find_field() and pass the same pointer through struct, datasec, and nested-struct walks. This gives the entire field traversal one shared uniqueness state. Fixes: 64e8ee814819 ("bpf: look into the types of the fields of a struct type recursively.") Signed-off-by: Kumar Kartikeya Dwivedi <memxor@gmail.com> --- kernel/bpf/btf.c | 26 ++++++++++++++------------ 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/kernel/bpf/btf.c b/kernel/bpf/btf.c index cbb1e49b9bcb..8d628552ef99 100644 --- a/kernel/bpf/btf.c +++ b/kernel/bpf/btf.c @@ -3751,7 +3751,7 @@ static int btf_repeat_fields(struct btf_field_info *info, int info_cnt, static int btf_find_struct_field(const struct btf *btf, const struct btf_type *t, u32 field_mask, struct btf_field_info *info, int info_cnt, - u32 level); + u32 level, u32 *seen_mask); /* Find special fields in the struct type of a field. * @@ -3762,7 +3762,7 @@ static int btf_find_struct_field(const struct btf *btf, static int btf_find_nested_struct(const struct btf *btf, const struct btf_type *t, u32 off, u32 nelems, u32 field_mask, struct btf_field_info *info, - int info_cnt, u32 level) + int info_cnt, u32 level, u32 *seen_mask) { int ret, err, i; @@ -3770,7 +3770,7 @@ static int btf_find_nested_struct(const struct btf *btf, const struct btf_type * if (level >= MAX_RESOLVE_DEPTH) return -E2BIG; - ret = btf_find_struct_field(btf, t, field_mask, info, info_cnt, level); + ret = btf_find_struct_field(btf, t, field_mask, info, info_cnt, level, seen_mask); if (ret <= 0) return ret; @@ -3827,7 +3827,7 @@ static int btf_find_field_one(const struct btf *btf, if (expected_size && expected_size != sz * nelems) return 0; ret = btf_find_nested_struct(btf, var_type, off, nelems, field_mask, - &info[0], info_cnt, level); + &info[0], info_cnt, level, seen_mask); return ret; } @@ -3892,11 +3892,11 @@ static int btf_find_field_one(const struct btf *btf, static int btf_find_struct_field(const struct btf *btf, const struct btf_type *t, u32 field_mask, struct btf_field_info *info, int info_cnt, - u32 level) + u32 level, u32 *seen_mask) { int ret, idx = 0; const struct btf_member *member; - u32 i, off, seen_mask = 0; + u32 i, off; for_each_member(i, t, member) { const struct btf_type *member_type = btf_type_by_id(btf, @@ -3910,7 +3910,7 @@ static int btf_find_struct_field(const struct btf *btf, ret = btf_find_field_one(btf, t, member_type, i, off, 0, - field_mask, &seen_mask, + field_mask, seen_mask, &info[idx], info_cnt - idx, level); if (ret < 0) return ret; @@ -3921,11 +3921,11 @@ static int btf_find_struct_field(const struct btf *btf, static int btf_find_datasec_var(const struct btf *btf, const struct btf_type *t, u32 field_mask, struct btf_field_info *info, - int info_cnt, u32 level) + int info_cnt, u32 level, u32 *seen_mask) { int ret, idx = 0; const struct btf_var_secinfo *vsi; - u32 i, off, seen_mask = 0; + u32 i, off; for_each_vsi(i, t, vsi) { const struct btf_type *var = btf_type_by_id(btf, vsi->type); @@ -3933,7 +3933,7 @@ static int btf_find_datasec_var(const struct btf *btf, const struct btf_type *t, off = vsi->offset; ret = btf_find_field_one(btf, var, var_type, -1, off, vsi->size, - field_mask, &seen_mask, + field_mask, seen_mask, &info[idx], info_cnt - idx, level); if (ret < 0) @@ -3947,10 +3947,12 @@ static int btf_find_field(const struct btf *btf, const struct btf_type *t, u32 field_mask, struct btf_field_info *info, int info_cnt) { + u32 seen_mask = 0; + if (__btf_type_is_struct(t)) - return btf_find_struct_field(btf, t, field_mask, info, info_cnt, 0); + return btf_find_struct_field(btf, t, field_mask, info, info_cnt, 0, &seen_mask); else if (btf_type_is_datasec(t)) - return btf_find_datasec_var(btf, t, field_mask, info, info_cnt, 0); + return btf_find_datasec_var(btf, t, field_mask, info, info_cnt, 0, &seen_mask); return -EINVAL; } -- 2.53.0 ^ permalink raw reply related [flat|nested] 7+ messages in thread
* Re: [PATCH bpf-next v1 1/2] bpf: Preserve unique-field state across nested structs 2026-07-19 14:23 ` [PATCH bpf-next v1 1/2] bpf: Preserve unique-field state across nested structs Kumar Kartikeya Dwivedi @ 2026-07-19 14:34 ` sashiko-bot 2026-07-19 15:08 ` Kumar Kartikeya Dwivedi 0 siblings, 1 reply; 7+ messages in thread From: sashiko-bot @ 2026-07-19 14:34 UTC (permalink / raw) To: Kumar Kartikeya Dwivedi; +Cc: bpf Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider: Pre-existing issues: - [High] BPF_REFCOUNT is incorrectly marked as non-unique, allowing users to trigger a WARN_ON_ONCE via duplicate fields. - [High] Typo in BPF_RES_SPIN_LOCK parsing checks the wrong offset, allowing users to trigger a WARN_ON_ONCE. -- --- Patch [1]: [PATCH bpf-next v1 1/2] bpf: Preserve unique-field state across nested structs --- commit cc8eb6296aa42dface6bb303fbfdec9c1e0e7566 Author: Kumar Kartikeya Dwivedi <memxor@gmail.com> bpf: Preserve unique-field state across nested structs This commit addresses an issue where btf_find_struct_field() initialized a fresh seen mask for every recursive descent. By sharing the seen_mask pointer across the traversal, it properly detects duplicate unique fields to prevent an invariant warning during map creation. > btf_find_struct_field() initializes a fresh seen mask for every recursive > descent. Unique special fields in different levels of the same aggregate > therefore do not see one another. The duplicate fields can reach > btf_parse_fields(), where they trigger an invariant WARN_ON_ONCE(). A > crafted user BTF can consequently trigger the warning before map creation > checks capabilities. [Severity: High] This isn't a bug introduced by this patch, but looking at btf_get_field_type() in kernel/bpf/btf.c, BPF_REFCOUNT is defined as non-unique (is_unique = false). If a user creates a BPF map using a BTF struct containing two bpf_refcount fields, they bypass the uniqueness check. When btf_parse_fields() processes them, the second field triggers the invariant check: kernel/bpf/btf.c:btf_parse_fields() { ... case BPF_REFCOUNT: WARN_ON_ONCE(rec->refcount_off >= 0); ... } Can a crafted user BTF still trigger this WARN_ON_ONCE() using duplicate refcount fields? [Severity: High] This is a pre-existing issue, but looking at the BPF_RES_SPIN_LOCK case in btf_parse_fields(), it appears to check the wrong offset: kernel/bpf/btf.c:btf_parse_fields() { ... case BPF_RES_SPIN_LOCK: WARN_ON_ONCE(rec->spin_lock_off >= 0); /* Cache offset for faster lookup at runtime */ rec->res_spin_lock_off = rec->fields[i].offset; break; ... } If a user provides a BTF struct containing both a bpf_spin_lock and a bpf_res_spin_lock, wouldn't this trigger the WARN_ON_ONCE() before reaching the intended graceful rejection? kernel/bpf/btf.c:btf_parse_fields() { ... if (rec->spin_lock_off >= 0 && rec->res_spin_lock_off >= 0) { ret = -EINVAL; goto end; } ... } > diff --git a/kernel/bpf/btf.c b/kernel/bpf/btf.c > index cbb1e49b9bcbf..8d628552ef99e 100644 > --- a/kernel/bpf/btf.c > +++ b/kernel/bpf/btf.c > @@ -3751,7 +3751,7 @@ static int btf_repeat_fields(struct btf_field_info *info, int info_cnt, > static int btf_find_struct_field(const struct btf *btf, > const struct btf_type *t, u32 field_mask, > struct btf_field_info *info, int info_cnt, > - u32 level); > + u32 level, u32 *seen_mask); > [ ... ] -- Sashiko AI review · https://sashiko.dev/#/patchset/20260719142401.2420111-1-memxor@gmail.com?part=1 ^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH bpf-next v1 1/2] bpf: Preserve unique-field state across nested structs 2026-07-19 14:34 ` sashiko-bot @ 2026-07-19 15:08 ` Kumar Kartikeya Dwivedi 0 siblings, 0 replies; 7+ messages in thread From: Kumar Kartikeya Dwivedi @ 2026-07-19 15:08 UTC (permalink / raw) To: sashiko-reviews, Kumar Kartikeya Dwivedi; +Cc: bpf On Sun Jul 19, 2026 at 4:34 PM CEST, sashiko-bot wrote: > Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider: > > Pre-existing issues: > - [High] BPF_REFCOUNT is incorrectly marked as non-unique, allowing users to trigger a WARN_ON_ONCE via duplicate fields. > - [High] Typo in BPF_RES_SPIN_LOCK parsing checks the wrong offset, allowing users to trigger a WARN_ON_ONCE. > -- > > --- Patch [1]: [PATCH bpf-next v1 1/2] bpf: Preserve unique-field state across nested structs --- > commit cc8eb6296aa42dface6bb303fbfdec9c1e0e7566 > Author: Kumar Kartikeya Dwivedi <memxor@gmail.com> > > bpf: Preserve unique-field state across nested structs > > This commit addresses an issue where btf_find_struct_field() initialized a > fresh seen mask for every recursive descent. By sharing the seen_mask pointer > across the traversal, it properly detects duplicate unique fields to prevent > an invariant warning during map creation. > >> btf_find_struct_field() initializes a fresh seen mask for every recursive >> descent. Unique special fields in different levels of the same aggregate >> therefore do not see one another. The duplicate fields can reach >> btf_parse_fields(), where they trigger an invariant WARN_ON_ONCE(). A >> crafted user BTF can consequently trigger the warning before map creation >> checks capabilities. > > [Severity: High] > This isn't a bug introduced by this patch, but looking at > btf_get_field_type() in kernel/bpf/btf.c, BPF_REFCOUNT is defined as > non-unique (is_unique = false). > > If a user creates a BPF map using a BTF struct containing two bpf_refcount > fields, they bypass the uniqueness check. When btf_parse_fields() processes > them, the second field triggers the invariant check: > > kernel/bpf/btf.c:btf_parse_fields() { > ... > case BPF_REFCOUNT: > WARN_ON_ONCE(rec->refcount_off >= 0); > ... > } Will fix and respin. > > Can a crafted user BTF still trigger this WARN_ON_ONCE() using duplicate > refcount fields? > > > [Severity: High] > This is a pre-existing issue, but looking at the BPF_RES_SPIN_LOCK case in > btf_parse_fields(), it appears to check the wrong offset: > > kernel/bpf/btf.c:btf_parse_fields() { > ... > case BPF_RES_SPIN_LOCK: > WARN_ON_ONCE(rec->spin_lock_off >= 0); > /* Cache offset for faster lookup at runtime */ > rec->res_spin_lock_off = rec->fields[i].offset; > break; > ... > } > > If a user provides a BTF struct containing both a bpf_spin_lock and > a bpf_res_spin_lock, wouldn't this trigger the WARN_ON_ONCE() before > reaching the intended graceful rejection? > > kernel/bpf/btf.c:btf_parse_fields() { > ... > if (rec->spin_lock_off >= 0 && rec->res_spin_lock_off >= 0) { > ret = -EINVAL; > goto end; > } > ... > } > Already sent, but will roll the fix for this in this series. >> diff --git a/kernel/bpf/btf.c b/kernel/bpf/btf.c >> index cbb1e49b9bcbf..8d628552ef99e 100644 >> --- a/kernel/bpf/btf.c >> +++ b/kernel/bpf/btf.c >> @@ -3751,7 +3751,7 @@ static int btf_repeat_fields(struct btf_field_info *info, int info_cnt, >> static int btf_find_struct_field(const struct btf *btf, >> const struct btf_type *t, u32 field_mask, >> struct btf_field_info *info, int info_cnt, >> - u32 level); >> + u32 level, u32 *seen_mask); >> > [ ... ] ^ permalink raw reply [flat|nested] 7+ messages in thread
* [PATCH bpf-next v1 2/2] selftests/bpf: Test duplicate unique fields in nested structs 2026-07-19 14:23 [PATCH bpf-next v1 0/2] Fix unique fields for nested structs in BTF Kumar Kartikeya Dwivedi 2026-07-19 14:23 ` [PATCH bpf-next v1 1/2] bpf: Preserve unique-field state across nested structs Kumar Kartikeya Dwivedi @ 2026-07-19 14:24 ` Kumar Kartikeya Dwivedi 2026-07-19 14:30 ` sashiko-bot 2026-07-19 15:17 ` bot+bpf-ci 1 sibling, 2 replies; 7+ messages in thread From: Kumar Kartikeya Dwivedi @ 2026-07-19 14:24 UTC (permalink / raw) To: bpf Cc: Alexei Starovoitov, Andrii Nakryiko, Daniel Borkmann, Eduard Zingerman, Emil Tsalapatis, kkd, kernel-team Add a raw BTF test with a spin lock directly in a struct and another in a nested struct. The duplicate must now be rejected during BTF loading. Signed-off-by: Kumar Kartikeya Dwivedi <memxor@gmail.com> --- tools/testing/selftests/bpf/prog_tests/btf.c | 26 ++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/tools/testing/selftests/bpf/prog_tests/btf.c b/tools/testing/selftests/bpf/prog_tests/btf.c index 66855cbd6b73..02c4c60c841e 100644 --- a/tools/testing/selftests/bpf/prog_tests/btf.c +++ b/tools/testing/selftests/bpf/prog_tests/btf.c @@ -4250,6 +4250,32 @@ static struct btf_raw_test raw_tests[] = { .max_entries = 1, }, +/* struct inner { + * struct bpf_spin_lock lock; + * }; + * + * struct value { + * struct bpf_spin_lock lock; + * struct inner nested; + * }; + */ +{ + .descr = "struct test duplicate nested unique fields", + .raw_types = { + BTF_TYPE_INT_ENC(NAME_TBD, BTF_INT_SIGNED, 0, 32, 4), /* [1] */ + BTF_STRUCT_ENC(NAME_TBD, 1, 4), /* [2] */ + BTF_MEMBER_ENC(NAME_TBD, 1, 0), + BTF_STRUCT_ENC(NAME_TBD, 1, 4), /* [3] */ + BTF_MEMBER_ENC(NAME_TBD, 2, 0), + BTF_STRUCT_ENC(NAME_TBD, 2, 8), /* [4] */ + BTF_MEMBER_ENC(NAME_TBD, 2, 0), + BTF_MEMBER_ENC(NAME_TBD, 3, 32), + BTF_END_RAW, + }, + BTF_STR_SEC("\0int\0bpf_spin_lock\0val\0inner\0lock\0value\0lock\0nested"), + .btf_load_err = true, +}, + { .descr = "struct test repeated fields count overflow", .raw_types = { -- 2.53.0 ^ permalink raw reply related [flat|nested] 7+ messages in thread
* Re: [PATCH bpf-next v1 2/2] selftests/bpf: Test duplicate unique fields in nested structs 2026-07-19 14:24 ` [PATCH bpf-next v1 2/2] selftests/bpf: Test duplicate unique fields in " Kumar Kartikeya Dwivedi @ 2026-07-19 14:30 ` sashiko-bot 2026-07-19 15:17 ` bot+bpf-ci 1 sibling, 0 replies; 7+ messages in thread From: sashiko-bot @ 2026-07-19 14:30 UTC (permalink / raw) To: Kumar Kartikeya Dwivedi; +Cc: bpf Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider: - [Low] Multi-line comment style violates BPF subsystem guidelines. -- --- Patch [2]: [PATCH bpf-next v1 2/2] selftests/bpf: Test duplicate unique fields in nested structs --- commit 9b7a72ba7e7b55aa85d89f130fc6922658c4bcf0 Author: Kumar Kartikeya Dwivedi <memxor@gmail.com> selftests/bpf: Test duplicate unique fields in nested structs This commit adds a raw BTF test with a spin lock directly in a struct and another in a nested struct to ensure duplicates are rejected during BTF loading. > diff --git a/tools/testing/selftests/bpf/prog_tests/btf.c b/tools/testing/selftests/bpf/prog_tests/btf.c > index 66855cbd6b73f..02c4c60c841ee 100644 > --- a/tools/testing/selftests/bpf/prog_tests/btf.c > +++ b/tools/testing/selftests/bpf/prog_tests/btf.c [ ... ] > @@ -4250,6 +4250,32 @@ static struct btf_raw_test raw_tests[] = { > .max_entries = 1, > }, > > +/* struct inner { > + * struct bpf_spin_lock lock; > + * }; [Severity: Low] This isn't a bug, but does this multi-line comment format violate the BPF subsystem style guidelines? The BPF guidelines prefer the opening /* to be on its own line rather than having text on the same line as the opening. -- Sashiko AI review · https://sashiko.dev/#/patchset/20260719142401.2420111-1-memxor@gmail.com?part=2 ^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH bpf-next v1 2/2] selftests/bpf: Test duplicate unique fields in nested structs 2026-07-19 14:24 ` [PATCH bpf-next v1 2/2] selftests/bpf: Test duplicate unique fields in " Kumar Kartikeya Dwivedi 2026-07-19 14:30 ` sashiko-bot @ 2026-07-19 15:17 ` bot+bpf-ci 1 sibling, 0 replies; 7+ messages in thread From: bot+bpf-ci @ 2026-07-19 15:17 UTC (permalink / raw) To: memxor, bpf Cc: ast, andrii, daniel, eddyz87, emil, kkd, kernel-team, ast, andrii, daniel, martin.lau, eddyz87, yonghong.song, clm, ihor.solodrai [-- Attachment #1: Type: text/plain, Size: 1173 bytes --] > selftests/bpf: Test duplicate unique fields in nested structs > > Add a raw BTF test with a spin lock directly in a struct and another in a > nested struct. The duplicate must now be rejected during BTF loading. > > Signed-off-by: Kumar Kartikeya Dwivedi <memxor@gmail.com> This test exercises the case where a duplicate unique special field (bpf_spin_lock) is split across a struct and a nested struct, which before the fix could reach btf_parse_fields() and trip an invariant WARN_ON_ONCE(). The buggy behaviour was introduced when btf_find_nested_struct() began recursing into btf_find_struct_field() with a per-level seen_mask, so uniqueness state was not preserved across nested structs. The companion fix commit already carries this tag, so should this test carry the same one so the two are backported together? Fixes: 64e8ee814819 ("bpf: look into the types of the fields of a struct type recursively.") --- AI reviewed your patch. Please fix the bug or email reply why it's not a bug. See: https://github.com/kernel-patches/vmtest/blob/master/ci/claude/README.md CI run summary: https://github.com/kernel-patches/bpf/actions/runs/29691561692 ^ permalink raw reply [flat|nested] 7+ messages in thread
end of thread, other threads:[~2026-07-19 15:17 UTC | newest] Thread overview: 7+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2026-07-19 14:23 [PATCH bpf-next v1 0/2] Fix unique fields for nested structs in BTF Kumar Kartikeya Dwivedi 2026-07-19 14:23 ` [PATCH bpf-next v1 1/2] bpf: Preserve unique-field state across nested structs Kumar Kartikeya Dwivedi 2026-07-19 14:34 ` sashiko-bot 2026-07-19 15:08 ` Kumar Kartikeya Dwivedi 2026-07-19 14:24 ` [PATCH bpf-next v1 2/2] selftests/bpf: Test duplicate unique fields in " Kumar Kartikeya Dwivedi 2026-07-19 14:30 ` sashiko-bot 2026-07-19 15:17 ` bot+bpf-ci
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox