BPF List
 help / color / mirror / Atom feed
* [PATCH bpf-next v2 0/5] Fix unique field logic in BTF
@ 2026-07-19 15:36 Kumar Kartikeya Dwivedi
  2026-07-19 15:36 ` [PATCH bpf-next v2 1/5] bpf: Fix offset warn check for bpf_res_spin_lock Kumar Kartikeya Dwivedi
                   ` (4 more replies)
  0 siblings, 5 replies; 11+ messages in thread
From: Kumar Kartikeya Dwivedi @ 2026-07-19 15:36 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, BPF_REFCOUNT which should be marked as unique.
See commit logs for details. While at it, fix improper offset check.

Changelog:
----------
v1 -> v2
v1: https://lore.kernel.org/bpf/20260719142401.2420111-1-memxor@gmail.com

 * Add fix for BPF_REFCOUNT not being unique. (Sashiko)
 * Roll improper offset warning check into series. (Sashiko)

Kumar Kartikeya Dwivedi (5):
  bpf: Fix offset warn check for bpf_res_spin_lock
  bpf: Preserve unique-field state across nested structs
  bpf: Mark bpf_refcount field as unique
  selftests/bpf: Test duplicate unique fields in nested structs
  selftests/bpf: Test duplicate bpf_refcount fields

 kernel/bpf/btf.c                             | 30 ++++++------
 tools/testing/selftests/bpf/prog_tests/btf.c | 48 ++++++++++++++++++++
 2 files changed, 64 insertions(+), 14 deletions(-)


base-commit: ecf11bc5f56abb3a2219a8c75e8a5b54467d1781
-- 
2.53.0


^ permalink raw reply	[flat|nested] 11+ messages in thread

* [PATCH bpf-next v2 1/5] bpf: Fix offset warn check for bpf_res_spin_lock
  2026-07-19 15:36 [PATCH bpf-next v2 0/5] Fix unique field logic in BTF Kumar Kartikeya Dwivedi
@ 2026-07-19 15:36 ` Kumar Kartikeya Dwivedi
  2026-07-19 15:48   ` sashiko-bot
  2026-07-19 16:17   ` bot+bpf-ci
  2026-07-19 15:36 ` [PATCH bpf-next v2 2/5] bpf: Preserve unique-field state across nested structs Kumar Kartikeya Dwivedi
                   ` (3 subsequent siblings)
  4 siblings, 2 replies; 11+ messages in thread
From: Kumar Kartikeya Dwivedi @ 2026-07-19 15:36 UTC (permalink / raw)
  To: bpf
  Cc: Alexei Starovoitov, Andrii Nakryiko, Daniel Borkmann,
	Eduard Zingerman, Emil Tsalapatis, kkd, kernel-team

Sashiko pointed out correctly that the case statement for
BPF_RES_SPIN_LOCK incorrectly checks offset for BPF_SPIN_LOCK.
Fix it by checking res_spin_lock_off instead.

Signed-off-by: Kumar Kartikeya Dwivedi <memxor@gmail.com>
---
 kernel/bpf/btf.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/kernel/bpf/btf.c b/kernel/bpf/btf.c
index cbb1e49b9bcb..e7d4e9ba24e2 100644
--- a/kernel/bpf/btf.c
+++ b/kernel/bpf/btf.c
@@ -4168,7 +4168,7 @@ struct btf_record *btf_parse_fields(const struct btf *btf, const struct btf_type
 			rec->spin_lock_off = rec->fields[i].offset;
 			break;
 		case BPF_RES_SPIN_LOCK:
-			WARN_ON_ONCE(rec->spin_lock_off >= 0);
+			WARN_ON_ONCE(rec->res_spin_lock_off >= 0);
 			/* Cache offset for faster lookup at runtime */
 			rec->res_spin_lock_off = rec->fields[i].offset;
 			break;
-- 
2.53.0


^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [PATCH bpf-next v2 2/5] bpf: Preserve unique-field state across nested structs
  2026-07-19 15:36 [PATCH bpf-next v2 0/5] Fix unique field logic in BTF Kumar Kartikeya Dwivedi
  2026-07-19 15:36 ` [PATCH bpf-next v2 1/5] bpf: Fix offset warn check for bpf_res_spin_lock Kumar Kartikeya Dwivedi
@ 2026-07-19 15:36 ` Kumar Kartikeya Dwivedi
  2026-07-19 15:49   ` sashiko-bot
  2026-07-19 15:36 ` [PATCH bpf-next v2 3/5] bpf: Mark bpf_refcount field as unique Kumar Kartikeya Dwivedi
                   ` (2 subsequent siblings)
  4 siblings, 1 reply; 11+ messages in thread
From: Kumar Kartikeya Dwivedi @ 2026-07-19 15:36 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 e7d4e9ba24e2..c577f00e9d88 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] 11+ messages in thread

* [PATCH bpf-next v2 3/5] bpf: Mark bpf_refcount field as unique
  2026-07-19 15:36 [PATCH bpf-next v2 0/5] Fix unique field logic in BTF Kumar Kartikeya Dwivedi
  2026-07-19 15:36 ` [PATCH bpf-next v2 1/5] bpf: Fix offset warn check for bpf_res_spin_lock Kumar Kartikeya Dwivedi
  2026-07-19 15:36 ` [PATCH bpf-next v2 2/5] bpf: Preserve unique-field state across nested structs Kumar Kartikeya Dwivedi
@ 2026-07-19 15:36 ` Kumar Kartikeya Dwivedi
  2026-07-19 15:36 ` [PATCH bpf-next v2 4/5] selftests/bpf: Test duplicate unique fields in nested structs Kumar Kartikeya Dwivedi
  2026-07-19 15:36 ` [PATCH bpf-next v2 5/5] selftests/bpf: Test duplicate bpf_refcount fields Kumar Kartikeya Dwivedi
  4 siblings, 0 replies; 11+ messages in thread
From: Kumar Kartikeya Dwivedi @ 2026-07-19 15:36 UTC (permalink / raw)
  To: bpf
  Cc: Alexei Starovoitov, Andrii Nakryiko, Daniel Borkmann,
	Eduard Zingerman, Emil Tsalapatis, kkd, kernel-team

BPF_REFCOUNT is not marked as a unique field, while it should be. Fix
this oversight.

Fixes: d54730b50bae ("bpf: Introduce opaque bpf_refcount struct and add btf_record plumbing")
Signed-off-by: Kumar Kartikeya Dwivedi <memxor@gmail.com>
---
 kernel/bpf/btf.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/kernel/bpf/btf.c b/kernel/bpf/btf.c
index c577f00e9d88..4eeeaeb69790 100644
--- a/kernel/bpf/btf.c
+++ b/kernel/bpf/btf.c
@@ -3669,7 +3669,7 @@ static int btf_get_field_type(const struct btf *btf, const struct btf_type *var_
 		{ BPF_LIST_NODE, "bpf_list_node", false },
 		{ BPF_RB_ROOT, "bpf_rb_root", false },
 		{ BPF_RB_NODE, "bpf_rb_node", false },
-		{ BPF_REFCOUNT, "bpf_refcount", false },
+		{ BPF_REFCOUNT, "bpf_refcount", true },
 	};
 	int type = 0, i;
 	const char *name = __btf_name_by_offset(btf, var_type->name_off);
-- 
2.53.0


^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [PATCH bpf-next v2 4/5] selftests/bpf: Test duplicate unique fields in nested structs
  2026-07-19 15:36 [PATCH bpf-next v2 0/5] Fix unique field logic in BTF Kumar Kartikeya Dwivedi
                   ` (2 preceding siblings ...)
  2026-07-19 15:36 ` [PATCH bpf-next v2 3/5] bpf: Mark bpf_refcount field as unique Kumar Kartikeya Dwivedi
@ 2026-07-19 15:36 ` Kumar Kartikeya Dwivedi
  2026-07-19 15:36 ` [PATCH bpf-next v2 5/5] selftests/bpf: Test duplicate bpf_refcount fields Kumar Kartikeya Dwivedi
  4 siblings, 0 replies; 11+ messages in thread
From: Kumar Kartikeya Dwivedi @ 2026-07-19 15:36 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 | 27 ++++++++++++++++++++
 1 file changed, 27 insertions(+)

diff --git a/tools/testing/selftests/bpf/prog_tests/btf.c b/tools/testing/selftests/bpf/prog_tests/btf.c
index 66855cbd6b73..2100400d896b 100644
--- a/tools/testing/selftests/bpf/prog_tests/btf.c
+++ b/tools/testing/selftests/bpf/prog_tests/btf.c
@@ -4250,6 +4250,33 @@ 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] 11+ messages in thread

* [PATCH bpf-next v2 5/5] selftests/bpf: Test duplicate bpf_refcount fields
  2026-07-19 15:36 [PATCH bpf-next v2 0/5] Fix unique field logic in BTF Kumar Kartikeya Dwivedi
                   ` (3 preceding siblings ...)
  2026-07-19 15:36 ` [PATCH bpf-next v2 4/5] selftests/bpf: Test duplicate unique fields in nested structs Kumar Kartikeya Dwivedi
@ 2026-07-19 15:36 ` Kumar Kartikeya Dwivedi
  4 siblings, 0 replies; 11+ messages in thread
From: Kumar Kartikeya Dwivedi @ 2026-07-19 15:36 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 two bpf_refcount fields. The duplicate must be
rejected during BTF loading instead of reaching the duplicate-field
invariant in btf_parse_fields().

Signed-off-by: Kumar Kartikeya Dwivedi <memxor@gmail.com>
---
 tools/testing/selftests/bpf/prog_tests/btf.c | 21 ++++++++++++++++++++
 1 file changed, 21 insertions(+)

diff --git a/tools/testing/selftests/bpf/prog_tests/btf.c b/tools/testing/selftests/bpf/prog_tests/btf.c
index 2100400d896b..67b9015cbd98 100644
--- a/tools/testing/selftests/bpf/prog_tests/btf.c
+++ b/tools/testing/selftests/bpf/prog_tests/btf.c
@@ -4277,6 +4277,27 @@ static struct btf_raw_test raw_tests[] = {
 	.btf_load_err = true,
 },
 
+/*
+ * struct value {
+ *     struct bpf_refcount a;
+ *     struct bpf_refcount b;
+ * };
+ */
+{
+	.descr = "struct test duplicate bpf_refcount 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, 2, 8),				/* [3] */
+		BTF_MEMBER_ENC(NAME_TBD, 2, 0),
+		BTF_MEMBER_ENC(NAME_TBD, 2, 32),
+		BTF_END_RAW,
+	},
+	BTF_STR_SEC("\0int\0bpf_refcount\0refs\0value\0a\0b"),
+	.btf_load_err = true,
+},
+
 {
 	.descr = "struct test repeated fields count overflow",
 	.raw_types = {
-- 
2.53.0


^ permalink raw reply related	[flat|nested] 11+ messages in thread

* Re: [PATCH bpf-next v2 1/5] bpf: Fix offset warn check for bpf_res_spin_lock
  2026-07-19 15:36 ` [PATCH bpf-next v2 1/5] bpf: Fix offset warn check for bpf_res_spin_lock Kumar Kartikeya Dwivedi
@ 2026-07-19 15:48   ` sashiko-bot
  2026-07-19 15:50     ` Kumar Kartikeya Dwivedi
  2026-07-19 16:17   ` bot+bpf-ci
  1 sibling, 1 reply; 11+ messages in thread
From: sashiko-bot @ 2026-07-19 15:48 UTC (permalink / raw)
  To: Kumar Kartikeya Dwivedi; +Cc: bpf

Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:

Pre-existing issues:
- [High] Userspace-triggerable kernel warning (WARN_ON_ONCE) due to nested struct bypassing `seen_mask` uniqueness check, potentially leading to kernel panic.
--

--- Patch [1]: [PATCH bpf-next v2 1/5] bpf: Fix offset warn check for bpf_res_spin_lock ---
commit f617fbd9a79f403f8e8be07c38922dcd0eedd840
Author: Kumar Kartikeya Dwivedi <memxor@gmail.com>

bpf: Fix offset warn check for bpf_res_spin_lock

This commit fixes an incorrect offset check for BPF_RES_SPIN_LOCK in
btf_parse_fields(). It now correctly checks res_spin_lock_off instead of
spin_lock_off.

> diff --git a/kernel/bpf/btf.c b/kernel/bpf/btf.c
> index cbb1e49b9bcbf..e7d4e9ba24e26 100644
> --- a/kernel/bpf/btf.c
> +++ b/kernel/bpf/btf.c
> @@ -4168,7 +4168,7 @@ struct btf_record *btf_parse_fields(const struct btf *btf, const struct btf_type
>  			rec->spin_lock_off = rec->fields[i].offset;
>  			break;
>  		case BPF_RES_SPIN_LOCK:
> -			WARN_ON_ONCE(rec->spin_lock_off >= 0);
> +			WARN_ON_ONCE(rec->res_spin_lock_off >= 0);

[Severity: High]
This is a pre-existing issue, but could this WARN_ON_ONCE() be triggered
from userspace and cause a kernel panic on systems with panic_on_warn
enabled?

If a crafted BTF with multiple identical unique fields (like
BPF_RES_SPIN_LOCK) is provided in different nested structures, it appears
btf_find_struct_field() resets seen_mask to 0 for each nested level:

kernel/bpf/btf.c:btf_find_struct_field() {
	u32 i, off, seen_mask = 0;
	...
}

This could allow duplicate unique fields to bypass the seen_mask check and
be returned to btf_parse_fields(). When iterating over these duplicates
here, would it hit this WARN_ON_ONCE() and panic the system? Should we
return an error instead of warning, or pass seen_mask down during the
recursive struct traversal to prevent this?

>  			/* Cache offset for faster lookup at runtime */
>  			rec->res_spin_lock_off = rec->fields[i].offset;
>  			break;

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260719153634.2908692-1-memxor@gmail.com?part=1

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [PATCH bpf-next v2 2/5] bpf: Preserve unique-field state across nested structs
  2026-07-19 15:36 ` [PATCH bpf-next v2 2/5] bpf: Preserve unique-field state across nested structs Kumar Kartikeya Dwivedi
@ 2026-07-19 15:49   ` sashiko-bot
  2026-07-19 15:50     ` Kumar Kartikeya Dwivedi
  0 siblings, 1 reply; 11+ messages in thread
From: sashiko-bot @ 2026-07-19 15:49 UTC (permalink / raw)
  To: Kumar Kartikeya Dwivedi; +Cc: bpf

Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:

Pre-existing issues:
- [High] Multiple BPF_REFCOUNT fields in a BTF struct bypass the seen_mask uniqueness check because is_unique = false, allowing them to trigger a reachable WARN_ON_ONCE() in btf_parse_fields().
--

--- Patch [2]: [PATCH bpf-next v2 2/5] bpf: Preserve unique-field state across nested structs ---
commit f8de1a7879c048283531a81778eac42891723a9d
Author: Kumar Kartikeya Dwivedi <memxor@gmail.com>

bpf: Preserve unique-field state across nested structs

btf_find_struct_field() initializes a fresh seen mask for every recursive
descent. This commit passes a shared seen mask pointer through the entire
field traversal to ensure unique special fields in different levels of the
same aggregate properly see one another.

> diff --git a/kernel/bpf/btf.c b/kernel/bpf/btf.c
> index e7d4e9ba24e26..c577f00e9d885 100644
> --- a/kernel/bpf/btf.c
> +++ b/kernel/bpf/btf.c

[ ... ]

> @@ -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);

[Severity: High]
This is a pre-existing issue, but since this patch improves the uniqueness
tracking via seen_mask, should BPF_REFCOUNT also be treated as a unique field?

In btf_get_field_type(), BPF_REFCOUNT is currently defined with
is_unique = false:

    { BPF_REFCOUNT, "bpf_refcount", false },

Because it bypasses the uniqueness validation, a user could load a BTF struct
containing multiple bpf_refcount fields. If this happens, does it eventually
reach btf_parse_fields() and intentionally trigger the WARN_ON_ONCE there?

    case BPF_REFCOUNT:
        WARN_ON_ONCE(rec->refcount_off >= 0);
        /* Cache offset for faster lookup at runtime */
        rec->refcount_off = rec->fields[i].offset;
        break;

Could a crafted user BTF cause a kernel panic here if panic_on_warn is
enabled?

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260719153634.2908692-1-memxor@gmail.com?part=2

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [PATCH bpf-next v2 2/5] bpf: Preserve unique-field state across nested structs
  2026-07-19 15:49   ` sashiko-bot
@ 2026-07-19 15:50     ` Kumar Kartikeya Dwivedi
  0 siblings, 0 replies; 11+ messages in thread
From: Kumar Kartikeya Dwivedi @ 2026-07-19 15:50 UTC (permalink / raw)
  To: sashiko-reviews, Kumar Kartikeya Dwivedi; +Cc: bpf

On Sun Jul 19, 2026 at 5:49 PM CEST, sashiko-bot wrote:
> Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
>
> Pre-existing issues:
> - [High] Multiple BPF_REFCOUNT fields in a BTF struct bypass the seen_mask uniqueness check because is_unique = false, allowing them to trigger a reachable WARN_ON_ONCE() in btf_parse_fields().
> --
>
> --- Patch [2]: [PATCH bpf-next v2 2/5] bpf: Preserve unique-field state across nested structs ---
> commit f8de1a7879c048283531a81778eac42891723a9d
> Author: Kumar Kartikeya Dwivedi <memxor@gmail.com>
>
> bpf: Preserve unique-field state across nested structs
>
> btf_find_struct_field() initializes a fresh seen mask for every recursive
> descent. This commit passes a shared seen mask pointer through the entire
> field traversal to ensure unique special fields in different levels of the
> same aggregate properly see one another.
>
>> diff --git a/kernel/bpf/btf.c b/kernel/bpf/btf.c
>> index e7d4e9ba24e26..c577f00e9d885 100644
>> --- a/kernel/bpf/btf.c
>> +++ b/kernel/bpf/btf.c
>
> [ ... ]
>
>> @@ -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);
>
> [Severity: High]
> This is a pre-existing issue, but since this patch improves the uniqueness
> tracking via seen_mask, should BPF_REFCOUNT also be treated as a unique field?
>
> In btf_get_field_type(), BPF_REFCOUNT is currently defined with
> is_unique = false:
>
>     { BPF_REFCOUNT, "bpf_refcount", false },
>
> Because it bypasses the uniqueness validation, a user could load a BTF struct
> containing multiple bpf_refcount fields. If this happens, does it eventually
> reach btf_parse_fields() and intentionally trigger the WARN_ON_ONCE there?
>
>     case BPF_REFCOUNT:
>         WARN_ON_ONCE(rec->refcount_off >= 0);
>         /* Cache offset for faster lookup at runtime */
>         rec->refcount_off = rec->fields[i].offset;
>         break;
>
> Could a crafted user BTF cause a kernel panic here if panic_on_warn is
> enabled?

Yes, but exactly what next commit fixes.

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [PATCH bpf-next v2 1/5] bpf: Fix offset warn check for bpf_res_spin_lock
  2026-07-19 15:48   ` sashiko-bot
@ 2026-07-19 15:50     ` Kumar Kartikeya Dwivedi
  0 siblings, 0 replies; 11+ messages in thread
From: Kumar Kartikeya Dwivedi @ 2026-07-19 15:50 UTC (permalink / raw)
  To: sashiko-reviews, Kumar Kartikeya Dwivedi; +Cc: bpf

On Sun Jul 19, 2026 at 5:48 PM CEST, sashiko-bot wrote:
> Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
>
> Pre-existing issues:
> - [High] Userspace-triggerable kernel warning (WARN_ON_ONCE) due to nested struct bypassing `seen_mask` uniqueness check, potentially leading to kernel panic.
> --
>
> --- Patch [1]: [PATCH bpf-next v2 1/5] bpf: Fix offset warn check for bpf_res_spin_lock ---
> commit f617fbd9a79f403f8e8be07c38922dcd0eedd840
> Author: Kumar Kartikeya Dwivedi <memxor@gmail.com>
>
> bpf: Fix offset warn check for bpf_res_spin_lock
>
> This commit fixes an incorrect offset check for BPF_RES_SPIN_LOCK in
> btf_parse_fields(). It now correctly checks res_spin_lock_off instead of
> spin_lock_off.
>
>> diff --git a/kernel/bpf/btf.c b/kernel/bpf/btf.c
>> index cbb1e49b9bcbf..e7d4e9ba24e26 100644
>> --- a/kernel/bpf/btf.c
>> +++ b/kernel/bpf/btf.c
>> @@ -4168,7 +4168,7 @@ struct btf_record *btf_parse_fields(const struct btf *btf, const struct btf_type
>>  			rec->spin_lock_off = rec->fields[i].offset;
>>  			break;
>>  		case BPF_RES_SPIN_LOCK:
>> -			WARN_ON_ONCE(rec->spin_lock_off >= 0);
>> +			WARN_ON_ONCE(rec->res_spin_lock_off >= 0);
>
> [Severity: High]
> This is a pre-existing issue, but could this WARN_ON_ONCE() be triggered
> from userspace and cause a kernel panic on systems with panic_on_warn
> enabled?
>
> If a crafted BTF with multiple identical unique fields (like
> BPF_RES_SPIN_LOCK) is provided in different nested structures, it appears
> btf_find_struct_field() resets seen_mask to 0 for each nested level:
>
> kernel/bpf/btf.c:btf_find_struct_field() {
> 	u32 i, off, seen_mask = 0;
> 	...
> }
>
> This could allow duplicate unique fields to bypass the seen_mask check and
> be returned to btf_parse_fields(). When iterating over these duplicates
> here, would it hit this WARN_ON_ONCE() and panic the system? Should we
> return an error instead of warning, or pass seen_mask down during the
> recursive struct traversal to prevent this?
>
>>  			/* Cache offset for faster lookup at runtime */
>>  			rec->res_spin_lock_off = rec->fields[i].offset;
>>  			break;

Fixed by next commit.

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [PATCH bpf-next v2 1/5] bpf: Fix offset warn check for bpf_res_spin_lock
  2026-07-19 15:36 ` [PATCH bpf-next v2 1/5] bpf: Fix offset warn check for bpf_res_spin_lock Kumar Kartikeya Dwivedi
  2026-07-19 15:48   ` sashiko-bot
@ 2026-07-19 16:17   ` bot+bpf-ci
  1 sibling, 0 replies; 11+ messages in thread
From: bot+bpf-ci @ 2026-07-19 16: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: 834 bytes --]

>     bpf: Fix offset warn check for bpf_res_spin_lock
>
>     Sashiko pointed out correctly that the case statement for
>     BPF_RES_SPIN_LOCK incorrectly checks offset for BPF_SPIN_LOCK.
>     Fix it by checking res_spin_lock_off instead.
>
>     Signed-off-by: Kumar Kartikeya Dwivedi <memxor@gmail.com>

This looks like a bug fix.  The incorrect check
"WARN_ON_ONCE(rec->spin_lock_off >= 0);" in the BPF_RES_SPIN_LOCK case of
btf_parse_fields() was introduced when that case was first added.  Should
this include:

  Fixes: 0de2046137f9 ("bpf: Implement verifier support for rqspinlock")


---
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/29693647189

^ permalink raw reply	[flat|nested] 11+ messages in thread

end of thread, other threads:[~2026-07-19 16:17 UTC | newest]

Thread overview: 11+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-07-19 15:36 [PATCH bpf-next v2 0/5] Fix unique field logic in BTF Kumar Kartikeya Dwivedi
2026-07-19 15:36 ` [PATCH bpf-next v2 1/5] bpf: Fix offset warn check for bpf_res_spin_lock Kumar Kartikeya Dwivedi
2026-07-19 15:48   ` sashiko-bot
2026-07-19 15:50     ` Kumar Kartikeya Dwivedi
2026-07-19 16:17   ` bot+bpf-ci
2026-07-19 15:36 ` [PATCH bpf-next v2 2/5] bpf: Preserve unique-field state across nested structs Kumar Kartikeya Dwivedi
2026-07-19 15:49   ` sashiko-bot
2026-07-19 15:50     ` Kumar Kartikeya Dwivedi
2026-07-19 15:36 ` [PATCH bpf-next v2 3/5] bpf: Mark bpf_refcount field as unique Kumar Kartikeya Dwivedi
2026-07-19 15:36 ` [PATCH bpf-next v2 4/5] selftests/bpf: Test duplicate unique fields in nested structs Kumar Kartikeya Dwivedi
2026-07-19 15:36 ` [PATCH bpf-next v2 5/5] selftests/bpf: Test duplicate bpf_refcount fields Kumar Kartikeya Dwivedi

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox