diff mbox series

[v1,bpf-next,1/4] bpf: Fix btf_get_field_type to fail for multiple bpf_refcount fields

Message ID 20231023220030.2556229-2-davemarchevsky@fb.com (mailing list archive)
State Changes Requested
Delegated to: BPF
Headers show
Series Descend into struct, array types when searching for fields | expand

Checks

Context Check Description
netdev/series_format success Posting correctly formatted
netdev/tree_selection success Clearly marked for bpf-next, async
netdev/fixes_present success Fixes tag not required for -next series
netdev/header_inline success No static functions without inline keyword in header files
netdev/build_32bit success Errors and warnings before: 1366 this patch: 1366
netdev/cc_maintainers warning 8 maintainers not CCed: song@kernel.org yonghong.song@linux.dev jolsa@kernel.org kpsingh@kernel.org john.fastabend@gmail.com sdf@google.com haoluo@google.com martin.lau@linux.dev
netdev/build_clang success Errors and warnings before: 1386 this patch: 1386
netdev/verify_signedoff success Signed-off-by tag matches author and committer
netdev/deprecated_api success None detected
netdev/check_selftest success No net selftest shell script
netdev/verify_fixes success Fixes tag looks correct
netdev/build_allmodconfig_warn success Errors and warnings before: 1391 this patch: 1391
netdev/checkpatch fail CHECK: Macro argument 'field_type' may be better as '(field_type)' to avoid precedence issues ERROR: Macros starting with if should be enclosed by a do - while loop to avoid possible if/else logic defects WARNING: Macros with flow control statements should be avoided
netdev/kdoc success Errors and warnings before: 0 this patch: 0
netdev/source_inline success Was 0 now: 0
bpf/vmtest-bpf-next-PR success PR summary
bpf/vmtest-bpf-next-VM_Test-32 success Logs for x86_64-llvm-16 / test (test_verifier, false, 360) / test_verifier on x86_64 with llvm-16
bpf/vmtest-bpf-next-VM_Test-33 success Logs for x86_64-llvm-16 / veristat
bpf/vmtest-bpf-next-VM_Test-30 success Logs for x86_64-llvm-16 / test (test_progs_no_alu32_parallel, true, 30) / test_progs_no_alu32_parallel on x86_64 with llvm-16
bpf/vmtest-bpf-next-VM_Test-31 success Logs for x86_64-llvm-16 / test (test_progs_parallel, true, 30) / test_progs_parallel on x86_64 with llvm-16
bpf/vmtest-bpf-next-VM_Test-2 success Logs for Validate matrix.py
bpf/vmtest-bpf-next-VM_Test-0 success Logs for Lint
bpf/vmtest-bpf-next-VM_Test-1 success Logs for ShellCheck
bpf/vmtest-bpf-next-VM_Test-3 success Logs for aarch64-gcc / build / build for aarch64 with gcc
bpf/vmtest-bpf-next-VM_Test-8 success Logs for aarch64-gcc / veristat
bpf/vmtest-bpf-next-VM_Test-4 success Logs for aarch64-gcc / test (test_maps, false, 360) / test_maps on aarch64 with gcc
bpf/vmtest-bpf-next-VM_Test-5 success Logs for aarch64-gcc / test (test_progs, false, 360) / test_progs on aarch64 with gcc
bpf/vmtest-bpf-next-VM_Test-7 success Logs for aarch64-gcc / test (test_verifier, false, 360) / test_verifier on aarch64 with gcc
bpf/vmtest-bpf-next-VM_Test-6 success Logs for aarch64-gcc / test (test_progs_no_alu32, false, 360) / test_progs_no_alu32 on aarch64 with gcc
bpf/vmtest-bpf-next-VM_Test-25 success Logs for x86_64-llvm-16 / test (test_maps, false, 360) / test_maps on x86_64 with llvm-16
bpf/vmtest-bpf-next-VM_Test-24 success Logs for x86_64-llvm-16 / build / build for x86_64 with llvm-16
bpf/vmtest-bpf-next-VM_Test-15 success Logs for set-matrix
bpf/vmtest-bpf-next-VM_Test-9 success Logs for s390x-gcc / build / build for s390x with gcc
bpf/vmtest-bpf-next-VM_Test-14 success Logs for s390x-gcc / veristat
bpf/vmtest-bpf-next-VM_Test-26 success Logs for x86_64-llvm-16 / test (test_progs, false, 360) / test_progs on x86_64 with llvm-16
bpf/vmtest-bpf-next-VM_Test-18 success Logs for x86_64-gcc / test (test_progs, false, 360) / test_progs on x86_64 with gcc
bpf/vmtest-bpf-next-VM_Test-21 success Logs for x86_64-gcc / test (test_progs_parallel, true, 30) / test_progs_parallel on x86_64 with gcc
bpf/vmtest-bpf-next-VM_Test-23 success Logs for x86_64-gcc / veristat / veristat on x86_64 with gcc
bpf/vmtest-bpf-next-VM_Test-20 success Logs for x86_64-gcc / test (test_progs_no_alu32_parallel, true, 30) / test_progs_no_alu32_parallel on x86_64 with gcc
bpf/vmtest-bpf-next-VM_Test-17 success Logs for x86_64-gcc / test (test_maps, false, 360) / test_maps on x86_64 with gcc
bpf/vmtest-bpf-next-VM_Test-16 success Logs for x86_64-gcc / build / build for x86_64 with gcc
bpf/vmtest-bpf-next-VM_Test-22 success Logs for x86_64-gcc / test (test_verifier, false, 360) / test_verifier on x86_64 with gcc
bpf/vmtest-bpf-next-VM_Test-19 success Logs for x86_64-gcc / test (test_progs_no_alu32, false, 360) / test_progs_no_alu32 on x86_64 with gcc
bpf/vmtest-bpf-next-VM_Test-27 success Logs for x86_64-llvm-16 / test (test_progs_no_alu32, false, 360) / test_progs_no_alu32 on x86_64 with llvm-16
bpf/vmtest-bpf-next-VM_Test-28 success Logs for x86_64-llvm-16 / test (test_verifier, false, 360) / test_verifier on x86_64 with llvm-16
bpf/vmtest-bpf-next-VM_Test-29 success Logs for x86_64-llvm-16 / veristat
bpf/vmtest-bpf-next-VM_Test-12 success Logs for s390x-gcc / test (test_progs_no_alu32, false, 360) / test_progs_no_alu32 on s390x with gcc
bpf/vmtest-bpf-next-VM_Test-13 success Logs for s390x-gcc / test (test_verifier, false, 360) / test_verifier on s390x with gcc
bpf/vmtest-bpf-next-VM_Test-11 success Logs for s390x-gcc / test (test_progs, false, 360) / test_progs on s390x with gcc
bpf/vmtest-bpf-next-VM_Test-10 success Logs for s390x-gcc / test (test_maps, false, 360) / test_maps on s390x with gcc

Commit Message

Dave Marchevsky Oct. 23, 2023, 10 p.m. UTC
If a struct has a bpf_refcount field, the refcount controls lifetime of
the entire struct. Currently there's no usecase or support for multiple
bpf_refcount fields in a struct.

bpf_spin_lock and bpf_timer fields don't support multiples either, but
with better error behavior. Parsing BTF w/ a struct containing multiple
{bpf_spin_lock, bpf_timer} fields fails in btf_get_field_type, while
multiple bpf_refcount fields doesn't fail BTF parsing at all, instead
triggering a WARN_ON_ONCE in btf_parse_fields, with the verifier using
the last bpf_refcount field to actually do refcounting.

This patch changes bpf_refcount handling in btf_get_field_type to use
same error logic as bpf_spin_lock and bpf_timer. Since it's being used
3x and is boilerplatey, the logic is shoved into
field_mask_test_name_check_seen helper macro.

Signed-off-by: Dave Marchevsky <davemarchevsky@fb.com>
Fixes: d54730b50bae ("bpf: Introduce opaque bpf_refcount struct and add btf_record plumbing")
---
 kernel/bpf/btf.c | 37 ++++++++++++++++---------------------
 1 file changed, 16 insertions(+), 21 deletions(-)

Comments

Yonghong Song Oct. 30, 2023, 5:56 p.m. UTC | #1
On 10/23/23 3:00 PM, Dave Marchevsky wrote:
> If a struct has a bpf_refcount field, the refcount controls lifetime of
> the entire struct. Currently there's no usecase or support for multiple
> bpf_refcount fields in a struct.
>
> bpf_spin_lock and bpf_timer fields don't support multiples either, but
> with better error behavior. Parsing BTF w/ a struct containing multiple
> {bpf_spin_lock, bpf_timer} fields fails in btf_get_field_type, while
> multiple bpf_refcount fields doesn't fail BTF parsing at all, instead
> triggering a WARN_ON_ONCE in btf_parse_fields, with the verifier using
> the last bpf_refcount field to actually do refcounting.
>
> This patch changes bpf_refcount handling in btf_get_field_type to use
> same error logic as bpf_spin_lock and bpf_timer. Since it's being used
> 3x and is boilerplatey, the logic is shoved into
> field_mask_test_name_check_seen helper macro.
>
> Signed-off-by: Dave Marchevsky <davemarchevsky@fb.com>
> Fixes: d54730b50bae ("bpf: Introduce opaque bpf_refcount struct and add btf_record plumbing")

Acked-by: Yonghong Song <yonghong.song@linux.dev>
Andrii Nakryiko Nov. 1, 2023, 9:56 p.m. UTC | #2
On Mon, Oct 23, 2023 at 3:00 PM Dave Marchevsky <davemarchevsky@fb.com> wrote:
>
> If a struct has a bpf_refcount field, the refcount controls lifetime of
> the entire struct. Currently there's no usecase or support for multiple
> bpf_refcount fields in a struct.
>
> bpf_spin_lock and bpf_timer fields don't support multiples either, but
> with better error behavior. Parsing BTF w/ a struct containing multiple
> {bpf_spin_lock, bpf_timer} fields fails in btf_get_field_type, while
> multiple bpf_refcount fields doesn't fail BTF parsing at all, instead
> triggering a WARN_ON_ONCE in btf_parse_fields, with the verifier using
> the last bpf_refcount field to actually do refcounting.
>
> This patch changes bpf_refcount handling in btf_get_field_type to use
> same error logic as bpf_spin_lock and bpf_timer. Since it's being used
> 3x and is boilerplatey, the logic is shoved into
> field_mask_test_name_check_seen helper macro.
>
> Signed-off-by: Dave Marchevsky <davemarchevsky@fb.com>
> Fixes: d54730b50bae ("bpf: Introduce opaque bpf_refcount struct and add btf_record plumbing")
> ---
>  kernel/bpf/btf.c | 37 ++++++++++++++++---------------------
>  1 file changed, 16 insertions(+), 21 deletions(-)
>

LGTM

Acked-by: Andrii Nakryiko <andrii@kernel.org>

> diff --git a/kernel/bpf/btf.c b/kernel/bpf/btf.c
> index 15d71d2986d3..975ef8e73393 100644
> --- a/kernel/bpf/btf.c
> +++ b/kernel/bpf/btf.c
> @@ -3374,8 +3374,17 @@ btf_find_graph_root(const struct btf *btf, const struct btf_type *pt,
>         return BTF_FIELD_FOUND;
>  }
>

[...]
diff mbox series

Patch

diff --git a/kernel/bpf/btf.c b/kernel/bpf/btf.c
index 15d71d2986d3..975ef8e73393 100644
--- a/kernel/bpf/btf.c
+++ b/kernel/bpf/btf.c
@@ -3374,8 +3374,17 @@  btf_find_graph_root(const struct btf *btf, const struct btf_type *pt,
 	return BTF_FIELD_FOUND;
 }
 
-#define field_mask_test_name(field_type, field_type_str) \
-	if (field_mask & field_type && !strcmp(name, field_type_str)) { \
+#define field_mask_test_name(field_type, field_type_str)		\
+	if (field_mask & field_type && !strcmp(name, field_type_str)) {	\
+		type = field_type;					\
+		goto end;						\
+	}
+
+#define field_mask_test_name_check_seen(field_type, field_type_str)	\
+	if (field_mask & field_type && !strcmp(name, field_type_str)) {	\
+		if (*seen_mask & field_type)				\
+			return -E2BIG;					\
+		*seen_mask |= field_type;				\
 		type = field_type;					\
 		goto end;						\
 	}
@@ -3385,29 +3394,14 @@  static int btf_get_field_type(const char *name, u32 field_mask, u32 *seen_mask,
 {
 	int type = 0;
 
-	if (field_mask & BPF_SPIN_LOCK) {
-		if (!strcmp(name, "bpf_spin_lock")) {
-			if (*seen_mask & BPF_SPIN_LOCK)
-				return -E2BIG;
-			*seen_mask |= BPF_SPIN_LOCK;
-			type = BPF_SPIN_LOCK;
-			goto end;
-		}
-	}
-	if (field_mask & BPF_TIMER) {
-		if (!strcmp(name, "bpf_timer")) {
-			if (*seen_mask & BPF_TIMER)
-				return -E2BIG;
-			*seen_mask |= BPF_TIMER;
-			type = BPF_TIMER;
-			goto end;
-		}
-	}
+	field_mask_test_name_check_seen(BPF_SPIN_LOCK, "bpf_spin_lock");
+	field_mask_test_name_check_seen(BPF_TIMER,     "bpf_timer");
+	field_mask_test_name_check_seen(BPF_REFCOUNT,  "bpf_refcount");
+
 	field_mask_test_name(BPF_LIST_HEAD, "bpf_list_head");
 	field_mask_test_name(BPF_LIST_NODE, "bpf_list_node");
 	field_mask_test_name(BPF_RB_ROOT,   "bpf_rb_root");
 	field_mask_test_name(BPF_RB_NODE,   "bpf_rb_node");
-	field_mask_test_name(BPF_REFCOUNT,  "bpf_refcount");
 
 	/* Only return BPF_KPTR when all other types with matchable names fail */
 	if (field_mask & BPF_KPTR) {
@@ -3421,6 +3415,7 @@  static int btf_get_field_type(const char *name, u32 field_mask, u32 *seen_mask,
 	return type;
 }
 
+#undef field_mask_test_name_check_seen
 #undef field_mask_test_name
 
 static int btf_find_struct_field(const struct btf *btf,