diff mbox series

[v1,bpf-next,4/4] selftests/bpf: Add tests exercising aggregate type BTF field search

Message ID 20231023220030.2556229-5-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: 9 this patch: 9
netdev/cc_maintainers warning 11 maintainers not CCed: song@kernel.org mykolal@fb.com yonghong.song@linux.dev jolsa@kernel.org kpsingh@kernel.org john.fastabend@gmail.com shuah@kernel.org linux-kselftest@vger.kernel.org sdf@google.com haoluo@google.com martin.lau@linux.dev
netdev/build_clang success Errors and warnings before: 9 this patch: 9
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 No Fixes tag
netdev/build_allmodconfig_warn success Errors and warnings before: 9 this patch: 9
netdev/checkpatch warning CHECK: spaces preferred around that '*' (ctx:WxV) WARNING: Prefer __aligned(8) over __attribute__((aligned(8))) WARNING: added, moved or deleted file(s), does MAINTAINERS need updating?
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-8 success Logs for aarch64-gcc / veristat
bpf/vmtest-bpf-next-VM_Test-0 success Logs for Lint
bpf/vmtest-bpf-next-VM_Test-3 success Logs for aarch64-gcc / build / build for aarch64 with gcc
bpf/vmtest-bpf-next-VM_Test-1 success Logs for ShellCheck
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-5 success Logs for aarch64-gcc / test (test_progs, false, 360) / test_progs on aarch64 with gcc
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-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-24 success Logs for x86_64-llvm-16 / build / build for x86_64 with llvm-16
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-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-16 success Logs for x86_64-gcc / build / build for 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-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-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-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-15 success Logs for set-matrix
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-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-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-23 success Logs for x86_64-gcc / veristat / veristat 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
The newly-added test file attempts to kptr_xchg a prog_test_ref_kfunc
kptr into a kptr field in a variety of nested aggregate types. If the
verifier recognizes that there's a kptr field where we're trying to
kptr_xchg, then the aggregate type digging logic works as expected.

Some of the refactoring changes in this series are tested as well.
Specifically:
  * BTF_FIELDS_MAX is now higher and represents the max size of the
    growable array. Confirm that btf_parse_fields fails for a type which
    contains too many fields.
  * If we've already seen BTF_FIELDS_MAX fields, we should continue
    looking for fields and fail if we find another one, otherwise the
    search should succeed and return BTF_FIELDS_MAX btf_field_infos.
    Confirm that this edge case works as expected.

Signed-off-by: Dave Marchevsky <davemarchevsky@fb.com>
---
 .../selftests/bpf/prog_tests/array_kptr.c     |  12 ++
 .../testing/selftests/bpf/progs/array_kptr.c  | 179 ++++++++++++++++++
 2 files changed, 191 insertions(+)
 create mode 100644 tools/testing/selftests/bpf/prog_tests/array_kptr.c
 create mode 100644 tools/testing/selftests/bpf/progs/array_kptr.c

Comments

kernel test robot Oct. 23, 2023, 11:32 p.m. UTC | #1
Hi Dave,

kernel test robot noticed the following build warnings:

[auto build test WARNING on bpf-next/master]

url:    https://github.com/intel-lab-lkp/linux/commits/Dave-Marchevsky/bpf-Fix-btf_get_field_type-to-fail-for-multiple-bpf_refcount-fields/20231024-060227
base:   https://git.kernel.org/pub/scm/linux/kernel/git/bpf/bpf-next.git master
patch link:    https://lore.kernel.org/r/20231023220030.2556229-5-davemarchevsky%40fb.com
patch subject: [PATCH v1 bpf-next 4/4] selftests/bpf: Add tests exercising aggregate type BTF field search
reproduce: (https://download.01.org/0day-ci/archive/20231024/202310240704.3BxYlwQh-lkp@intel.com/reproduce)

If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202310240704.3BxYlwQh-lkp@intel.com/

# many are suggestions rather than must-fix

ERROR:SPACING: need consistent spacing around '*' (ctx:WxV)
#65: FILE: tools/testing/selftests/bpf/progs/array_kptr.c:12:
+	struct prog_test_ref_kfunc __kptr *ref_ptr;
 	                                  ^
Yonghong Song Oct. 30, 2023, 9:10 p.m. UTC | #2
On 10/23/23 3:00 PM, Dave Marchevsky wrote:
> The newly-added test file attempts to kptr_xchg a prog_test_ref_kfunc
> kptr into a kptr field in a variety of nested aggregate types. If the
> verifier recognizes that there's a kptr field where we're trying to
> kptr_xchg, then the aggregate type digging logic works as expected.
>
> Some of the refactoring changes in this series are tested as well.
> Specifically:
>    * BTF_FIELDS_MAX is now higher and represents the max size of the
>      growable array. Confirm that btf_parse_fields fails for a type which
>      contains too many fields.
>    * If we've already seen BTF_FIELDS_MAX fields, we should continue
>      looking for fields and fail if we find another one, otherwise the
>      search should succeed and return BTF_FIELDS_MAX btf_field_infos.
>      Confirm that this edge case works as expected.
>
> Signed-off-by: Dave Marchevsky <davemarchevsky@fb.com>
> ---
>   .../selftests/bpf/prog_tests/array_kptr.c     |  12 ++
>   .../testing/selftests/bpf/progs/array_kptr.c  | 179 ++++++++++++++++++
>   2 files changed, 191 insertions(+)
>   create mode 100644 tools/testing/selftests/bpf/prog_tests/array_kptr.c
>   create mode 100644 tools/testing/selftests/bpf/progs/array_kptr.c
>
> diff --git a/tools/testing/selftests/bpf/prog_tests/array_kptr.c b/tools/testing/selftests/bpf/prog_tests/array_kptr.c
> new file mode 100644
> index 000000000000..9d088520bdfe
> --- /dev/null
> +++ b/tools/testing/selftests/bpf/prog_tests/array_kptr.c
> @@ -0,0 +1,12 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/* Copyright (c) 2023 Meta Platforms, Inc. and affiliates. */
> +
> +#include <test_progs.h>
> +
> +#include "array_kptr.skel.h"
> +
> +void test_array_kptr(void)
> +{
> +	if (env.has_testmod)
> +		RUN_TESTS(array_kptr);
> +}
> diff --git a/tools/testing/selftests/bpf/progs/array_kptr.c b/tools/testing/selftests/bpf/progs/array_kptr.c
> new file mode 100644
> index 000000000000..f34872e74024
> --- /dev/null
> +++ b/tools/testing/selftests/bpf/progs/array_kptr.c
> @@ -0,0 +1,179 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/* Copyright (c) 2023 Meta Platforms, Inc. and affiliates. */
> +
> +#include <vmlinux.h>
> +#include <bpf/bpf_tracing.h>
> +#include <bpf/bpf_helpers.h>
> +#include "../bpf_testmod/bpf_testmod_kfunc.h"
> +#include "bpf_misc.h"
> +
> +struct val {
> +	int d;
> +	struct prog_test_ref_kfunc __kptr *ref_ptr;
> +};
> +
> +struct val2 {
> +	char c;
> +	struct val v;
> +};
> +
> +struct val_holder {
> +	int e;
> +	struct val2 first[2];
> +	int f;
> +	struct val second[2];
> +};
> +
> +struct array_map {
> +	__uint(type, BPF_MAP_TYPE_ARRAY);
> +	__type(key, int);
> +	__type(value, struct val);
> +	__uint(max_entries, 10);
> +} array_map SEC(".maps");
> +
> +struct array_map2 {
> +	__uint(type, BPF_MAP_TYPE_ARRAY);
> +	__type(key, int);
> +	__type(value, struct val2);
> +	__uint(max_entries, 10);
> +} array_map2 SEC(".maps");
> +
> +__hidden struct val array[25];
> +__hidden struct val double_array[5][5];
> +__hidden struct val_holder double_holder_array[2][2];
> +
> +/* Some tests need their own section to force separate bss arraymap,
> + * otherwise above arrays wouldn't have btf_field_info either
> + */
> +#define private(name) SEC(".bss." #name) __hidden __attribute__((aligned(8)))
> +private(A) struct val array_too_big[300];
> +
> +private(B) struct val exactly_max_fields[256];
> +private(B) int ints[50];
> +
> +SEC("tc")
> +__success __retval(0)
> +int test_arraymap(void *ctx)
> +{
> +	struct prog_test_ref_kfunc *p;
> +	unsigned long dummy = 0;
> +	struct val *v;
> +	int idx = 0;
> +
> +	v = bpf_map_lookup_elem(&array_map, &idx);
> +	if (!v)
> +		return 1;
> +
> +	p = bpf_kfunc_call_test_acquire(&dummy);
> +	if (!p)
> +		return 2;
> +
> +	p = bpf_kptr_xchg(&v->ref_ptr, p);
> +	if (p) {
> +		bpf_kfunc_call_test_release(p);
> +		return 3;
> +	}
> +
> +	return 0;
> +}
> +
> ...
> +
> +SEC("tc")
> +__failure __msg("map '.bss.A' has no valid kptr")

The .bss.A might have valid kptr.
To reflect realiaty, maybe error message can be
'has too many special fields'?

> +int test_array_fail__too_big(void *ctx)
> +{
> +	/* array_too_big's btf_record parsing will fail due to the
> +	 * number of btf_field_infos being > BTF_FIELDS_MAX
> +	 */
> +	return test_array_xchg(&array_too_big[50]);
> +}
> +
> +char _license[] SEC("license") = "GPL";
Andrii Nakryiko Nov. 1, 2023, 9:56 p.m. UTC | #3
On Mon, Oct 23, 2023 at 3:01 PM Dave Marchevsky <davemarchevsky@fb.com> wrote:
>
> The newly-added test file attempts to kptr_xchg a prog_test_ref_kfunc
> kptr into a kptr field in a variety of nested aggregate types. If the
> verifier recognizes that there's a kptr field where we're trying to
> kptr_xchg, then the aggregate type digging logic works as expected.
>
> Some of the refactoring changes in this series are tested as well.
> Specifically:
>   * BTF_FIELDS_MAX is now higher and represents the max size of the
>     growable array. Confirm that btf_parse_fields fails for a type which
>     contains too many fields.
>   * If we've already seen BTF_FIELDS_MAX fields, we should continue
>     looking for fields and fail if we find another one, otherwise the
>     search should succeed and return BTF_FIELDS_MAX btf_field_infos.
>     Confirm that this edge case works as expected.
>
> Signed-off-by: Dave Marchevsky <davemarchevsky@fb.com>
> ---
>  .../selftests/bpf/prog_tests/array_kptr.c     |  12 ++
>  .../testing/selftests/bpf/progs/array_kptr.c  | 179 ++++++++++++++++++
>  2 files changed, 191 insertions(+)
>  create mode 100644 tools/testing/selftests/bpf/prog_tests/array_kptr.c
>  create mode 100644 tools/testing/selftests/bpf/progs/array_kptr.c
>

[...]

> +SEC("tc")
> +__failure __msg("map '.bss.A' has no valid kptr")
> +int test_array_fail__too_big(void *ctx)
> +{
> +       /* array_too_big's btf_record parsing will fail due to the
> +        * number of btf_field_infos being > BTF_FIELDS_MAX
> +        */
> +       return test_array_xchg(&array_too_big[50]);

how often in practice people are going to index such arrays with a
fixed index? I'd imagine it's normally going to be a calculated index
based on something (CPU ID or whatnot). Is that supported? Can we add
a test for that?


> +}
> +
> +char _license[] SEC("license") = "GPL";
> --
> 2.34.1
>
diff mbox series

Patch

diff --git a/tools/testing/selftests/bpf/prog_tests/array_kptr.c b/tools/testing/selftests/bpf/prog_tests/array_kptr.c
new file mode 100644
index 000000000000..9d088520bdfe
--- /dev/null
+++ b/tools/testing/selftests/bpf/prog_tests/array_kptr.c
@@ -0,0 +1,12 @@ 
+// SPDX-License-Identifier: GPL-2.0
+/* Copyright (c) 2023 Meta Platforms, Inc. and affiliates. */
+
+#include <test_progs.h>
+
+#include "array_kptr.skel.h"
+
+void test_array_kptr(void)
+{
+	if (env.has_testmod)
+		RUN_TESTS(array_kptr);
+}
diff --git a/tools/testing/selftests/bpf/progs/array_kptr.c b/tools/testing/selftests/bpf/progs/array_kptr.c
new file mode 100644
index 000000000000..f34872e74024
--- /dev/null
+++ b/tools/testing/selftests/bpf/progs/array_kptr.c
@@ -0,0 +1,179 @@ 
+// SPDX-License-Identifier: GPL-2.0
+/* Copyright (c) 2023 Meta Platforms, Inc. and affiliates. */
+
+#include <vmlinux.h>
+#include <bpf/bpf_tracing.h>
+#include <bpf/bpf_helpers.h>
+#include "../bpf_testmod/bpf_testmod_kfunc.h"
+#include "bpf_misc.h"
+
+struct val {
+	int d;
+	struct prog_test_ref_kfunc __kptr *ref_ptr;
+};
+
+struct val2 {
+	char c;
+	struct val v;
+};
+
+struct val_holder {
+	int e;
+	struct val2 first[2];
+	int f;
+	struct val second[2];
+};
+
+struct array_map {
+	__uint(type, BPF_MAP_TYPE_ARRAY);
+	__type(key, int);
+	__type(value, struct val);
+	__uint(max_entries, 10);
+} array_map SEC(".maps");
+
+struct array_map2 {
+	__uint(type, BPF_MAP_TYPE_ARRAY);
+	__type(key, int);
+	__type(value, struct val2);
+	__uint(max_entries, 10);
+} array_map2 SEC(".maps");
+
+__hidden struct val array[25];
+__hidden struct val double_array[5][5];
+__hidden struct val_holder double_holder_array[2][2];
+
+/* Some tests need their own section to force separate bss arraymap,
+ * otherwise above arrays wouldn't have btf_field_info either
+ */
+#define private(name) SEC(".bss." #name) __hidden __attribute__((aligned(8)))
+private(A) struct val array_too_big[300];
+
+private(B) struct val exactly_max_fields[256];
+private(B) int ints[50];
+
+SEC("tc")
+__success __retval(0)
+int test_arraymap(void *ctx)
+{
+	struct prog_test_ref_kfunc *p;
+	unsigned long dummy = 0;
+	struct val *v;
+	int idx = 0;
+
+	v = bpf_map_lookup_elem(&array_map, &idx);
+	if (!v)
+		return 1;
+
+	p = bpf_kfunc_call_test_acquire(&dummy);
+	if (!p)
+		return 2;
+
+	p = bpf_kptr_xchg(&v->ref_ptr, p);
+	if (p) {
+		bpf_kfunc_call_test_release(p);
+		return 3;
+	}
+
+	return 0;
+}
+
+SEC("tc")
+__success __retval(0)
+int test_arraymap2(void *ctx)
+{
+	struct prog_test_ref_kfunc *p;
+	unsigned long dummy = 0;
+	struct val2 *v;
+	int idx = 0;
+
+	v = bpf_map_lookup_elem(&array_map2, &idx);
+	if (!v)
+		return 1;
+
+	p = bpf_kfunc_call_test_acquire(&dummy);
+	if (!p)
+		return 2;
+
+	p = bpf_kptr_xchg(&v->v.ref_ptr, p);
+	if (p) {
+		bpf_kfunc_call_test_release(p);
+		return 3;
+	}
+
+	return 0;
+}
+
+/* elem must be contained within some mapval so it can be used as
+ * bpf_kptr_xchg's first param
+ */
+static __always_inline int test_array_xchg(struct val *elem)
+{
+	struct prog_test_ref_kfunc *p;
+	unsigned long dummy = 0;
+
+	p = bpf_kfunc_call_test_acquire(&dummy);
+	if (!p)
+		return 1;
+
+	p = bpf_kptr_xchg(&elem->ref_ptr, p);
+	if (p) {
+		bpf_kfunc_call_test_release(p);
+		return 2;
+	}
+
+	return 0;
+}
+
+SEC("tc")
+__success __retval(0)
+int test_array(void *ctx)
+{
+	return test_array_xchg(&array[10]);
+}
+
+SEC("tc")
+__success __retval(0)
+int test_double_array(void *ctx)
+{
+	/* array -> array -> struct -> kptr */
+	return test_array_xchg(&double_array[4][3]);
+}
+
+SEC("tc")
+__success __retval(0)
+int test_double_holder_array_first(void *ctx)
+{
+	/* array -> array -> struct -> array -> struct -> struct -> kptr */
+	return test_array_xchg(&double_holder_array[1][1].first[1].v);
+}
+
+SEC("tc")
+__success __retval(0)
+int test_double_holder_array_second(void *ctx)
+{
+	/* array -> array -> struct -> array -> struct -> kptr */
+	return test_array_xchg(&double_holder_array[1][1].second[1]);
+}
+
+SEC("tc")
+__success __retval(0)
+int test_exactly_max_fields(void *ctx)
+{
+	/* Edge case where verifier finds BTF_FIELDS_MAX fields. It should be
+	 * safe to examine .bss.B's other array, and .bss.B will have a valid
+	 * btf_record if no more fields are found
+	 */
+	return test_array_xchg(&exactly_max_fields[255]);
+}
+
+SEC("tc")
+__failure __msg("map '.bss.A' has no valid kptr")
+int test_array_fail__too_big(void *ctx)
+{
+	/* array_too_big's btf_record parsing will fail due to the
+	 * number of btf_field_infos being > BTF_FIELDS_MAX
+	 */
+	return test_array_xchg(&array_too_big[50]);
+}
+
+char _license[] SEC("license") = "GPL";