lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-Id: <20220128223312.1253169-10-mauricio@kinvolk.io>
Date:   Fri, 28 Jan 2022 17:33:12 -0500
From:   Mauricio Vásquez <mauricio@...volk.io>
To:     netdev@...r.kernel.org, bpf@...r.kernel.org
Cc:     Alexei Starovoitov <ast@...nel.org>,
        Daniel Borkmann <daniel@...earbox.net>,
        Andrii Nakryiko <andrii@...nel.org>,
        Quentin Monnet <quentin@...valent.com>,
        Rafael David Tinoco <rafaeldtinoco@...il.com>,
        Lorenzo Fontana <lorenzo.fontana@...stic.co>,
        Leonardo Di Donato <leonardo.didonato@...stic.co>
Subject: [PATCH bpf-next v5 9/9] selftest/bpf: Implement tests for bpftool gen min_core_btf

This commit implements some integration tests for "BTFGen". The goal
of such tests is to verify that the generated BTF file contains the
expected types.

Signed-off-by: Mauricio Vásquez <mauricio@...volk.io>
Signed-off-by: Rafael David Tinoco <rafael.tinoco@...asec.com>
Signed-off-by: Lorenzo Fontana <lorenzo.fontana@...stic.co>
Signed-off-by: Leonardo Di Donato <leonardo.didonato@...stic.co>
---
 tools/testing/selftests/bpf/.gitignore        |   1 +
 tools/testing/selftests/bpf/Makefile          |   4 +-
 .../selftests/bpf/progs/btfgen_btf_source.c   |  12 +
 .../bpf/progs/btfgen_primitives_array.c       |  39 +++
 .../bpf/progs/btfgen_primitives_struct.c      |  40 +++
 .../bpf/progs/btfgen_primitives_struct2.c     |  44 ++++
 .../bpf/progs/btfgen_primitives_union.c       |  32 +++
 tools/testing/selftests/bpf/test_bpftool.c    | 228 ++++++++++++++++++
 8 files changed, 399 insertions(+), 1 deletion(-)
 create mode 100644 tools/testing/selftests/bpf/progs/btfgen_btf_source.c
 create mode 100644 tools/testing/selftests/bpf/progs/btfgen_primitives_array.c
 create mode 100644 tools/testing/selftests/bpf/progs/btfgen_primitives_struct.c
 create mode 100644 tools/testing/selftests/bpf/progs/btfgen_primitives_struct2.c
 create mode 100644 tools/testing/selftests/bpf/progs/btfgen_primitives_union.c
 create mode 100644 tools/testing/selftests/bpf/test_bpftool.c

diff --git a/tools/testing/selftests/bpf/.gitignore b/tools/testing/selftests/bpf/.gitignore
index 1dad8d617da8..308cd5b9cfc4 100644
--- a/tools/testing/selftests/bpf/.gitignore
+++ b/tools/testing/selftests/bpf/.gitignore
@@ -41,3 +41,4 @@ test_cpp
 *.tmp
 xdpxceiver
 xdp_redirect_multi
+test_bpftool
diff --git a/tools/testing/selftests/bpf/Makefile b/tools/testing/selftests/bpf/Makefile
index 945f92d71db3..afc9bff6545d 100644
--- a/tools/testing/selftests/bpf/Makefile
+++ b/tools/testing/selftests/bpf/Makefile
@@ -38,7 +38,8 @@ TEST_GEN_PROGS = test_verifier test_tag test_maps test_lru_map test_lpm_map test
 	test_sock test_sockmap get_cgroup_id_user \
 	test_cgroup_storage \
 	test_tcpnotify_user test_sysctl \
-	test_progs-no_alu32
+	test_progs-no_alu32 \
+	test_bpftool
 
 # Also test bpf-gcc, if present
 ifneq ($(BPF_GCC),)
@@ -212,6 +213,7 @@ $(OUTPUT)/xdping: $(TESTING_HELPERS)
 $(OUTPUT)/flow_dissector_load: $(TESTING_HELPERS)
 $(OUTPUT)/test_maps: $(TESTING_HELPERS)
 $(OUTPUT)/test_verifier: $(TESTING_HELPERS)
+$(OUTPUT)/test_bpftool:
 
 BPFTOOL ?= $(DEFAULT_BPFTOOL)
 $(DEFAULT_BPFTOOL): $(wildcard $(BPFTOOLDIR)/*.[ch] $(BPFTOOLDIR)/Makefile)    \
diff --git a/tools/testing/selftests/bpf/progs/btfgen_btf_source.c b/tools/testing/selftests/bpf/progs/btfgen_btf_source.c
new file mode 100644
index 000000000000..772d5d1e2788
--- /dev/null
+++ b/tools/testing/selftests/bpf/progs/btfgen_btf_source.c
@@ -0,0 +1,12 @@
+// SPDX-License-Identifier: GPL-2.0
+
+#include "core_reloc_types.h"
+
+// structure made of primitive types
+void f0(struct core_reloc_primitives x) {}
+
+// union made of primite types
+void f1(union a_union x) {}
+
+// arrays
+void f2(struct core_reloc_arrays x) {}
diff --git a/tools/testing/selftests/bpf/progs/btfgen_primitives_array.c b/tools/testing/selftests/bpf/progs/btfgen_primitives_array.c
new file mode 100644
index 000000000000..aa514d1bcd96
--- /dev/null
+++ b/tools/testing/selftests/bpf/progs/btfgen_primitives_array.c
@@ -0,0 +1,39 @@
+// SPDX-License-Identifier: GPL-2.0
+
+#include <linux/bpf.h>
+#include <stdint.h>
+#include <bpf/bpf_helpers.h>
+#include <bpf/bpf_core_read.h>
+
+char _license[] SEC("license") = "GPL";
+
+struct {
+	char in[256];
+	char out[256];
+} data = {};
+
+struct core_reloc_arrays_substruct {
+	int c;
+	int d;
+};
+
+struct core_reloc_arrays {
+	int a[5];
+	char b[2][3][4];
+	struct core_reloc_arrays_substruct c[3];
+	struct core_reloc_arrays_substruct d[1][2];
+	struct core_reloc_arrays_substruct f[][2];
+};
+#define CORE_READ(dst, src) bpf_core_read(dst, sizeof(*(dst)), src)
+
+SEC("raw_tracepoint/sys_enter")
+int test_btfgen_primitives(void *ctx)
+{
+	struct core_reloc_arrays *in = (void *)&data.in;
+	struct core_reloc_arrays *out = (void *)&data.out;
+
+	if (CORE_READ(&out->a[0], &in->a[0]))
+		return 1;
+
+	return 0;
+}
diff --git a/tools/testing/selftests/bpf/progs/btfgen_primitives_struct.c b/tools/testing/selftests/bpf/progs/btfgen_primitives_struct.c
new file mode 100644
index 000000000000..b761d020fa4d
--- /dev/null
+++ b/tools/testing/selftests/bpf/progs/btfgen_primitives_struct.c
@@ -0,0 +1,40 @@
+// SPDX-License-Identifier: GPL-2.0
+
+#include <linux/bpf.h>
+#include <stdint.h>
+#include <bpf/bpf_helpers.h>
+#include <bpf/bpf_core_read.h>
+
+char _license[] SEC("license") = "GPL";
+
+struct {
+	char in[256];
+	char out[256];
+} data = {};
+
+enum core_reloc_primitives_enum {
+	A = 0,
+	B = 1,
+};
+
+struct core_reloc_primitives {
+	char a;
+	int b;
+	enum core_reloc_primitives_enum c;
+	void *d;
+	int (*f)(const char *);
+};
+
+#define CORE_READ(dst, src) bpf_core_read(dst, sizeof(*(dst)), src)
+
+SEC("raw_tracepoint/sys_enter")
+int test_btfgen_primitives(void *ctx)
+{
+	struct core_reloc_primitives *in = (void *)&data.in;
+	struct core_reloc_primitives *out = (void *)&data.out;
+
+	if (CORE_READ(&out->a, &in->a))
+		return 1;
+
+	return 0;
+}
diff --git a/tools/testing/selftests/bpf/progs/btfgen_primitives_struct2.c b/tools/testing/selftests/bpf/progs/btfgen_primitives_struct2.c
new file mode 100644
index 000000000000..fe67c9a24a7f
--- /dev/null
+++ b/tools/testing/selftests/bpf/progs/btfgen_primitives_struct2.c
@@ -0,0 +1,44 @@
+// SPDX-License-Identifier: GPL-2.0
+
+/* This is almost the same as btfgen_primitives_struct.c but in this one
+ * a different field is accessed
+ */
+
+#include <linux/bpf.h>
+#include <stdint.h>
+#include <bpf/bpf_helpers.h>
+#include <bpf/bpf_core_read.h>
+
+char _license[] SEC("license") = "GPL";
+
+struct {
+	char in[256];
+	char out[256];
+} data = {};
+
+enum core_reloc_primitives_enum {
+	A = 0,
+	B = 1,
+};
+
+struct core_reloc_primitives {
+	char a;
+	int b;
+	enum core_reloc_primitives_enum c;
+	void *d;
+	int (*f)(const char *);
+};
+
+#define CORE_READ(dst, src) bpf_core_read(dst, sizeof(*(dst)), src)
+
+SEC("raw_tracepoint/sys_enter")
+int test_btfgen_primitives(void *ctx)
+{
+	struct core_reloc_primitives *in = (void *)&data.in;
+	struct core_reloc_primitives *out = (void *)&data.out;
+
+	if (CORE_READ(&out->b, &in->b))
+		return 1;
+
+	return 0;
+}
diff --git a/tools/testing/selftests/bpf/progs/btfgen_primitives_union.c b/tools/testing/selftests/bpf/progs/btfgen_primitives_union.c
new file mode 100644
index 000000000000..d4690c9e963c
--- /dev/null
+++ b/tools/testing/selftests/bpf/progs/btfgen_primitives_union.c
@@ -0,0 +1,32 @@
+// SPDX-License-Identifier: GPL-2.0
+
+#include <linux/bpf.h>
+#include <stdint.h>
+#include <bpf/bpf_helpers.h>
+#include <bpf/bpf_core_read.h>
+
+char _license[] SEC("license") = "GPL";
+
+struct {
+	char in[256];
+	char out[256];
+} data = {};
+
+union a_union {
+	int y;
+	int z;
+};
+
+#define CORE_READ(dst, src) bpf_core_read(dst, sizeof(*(dst)), src)
+
+SEC("raw_tracepoint/sys_enter")
+int test_btfgen_primitives(void *ctx)
+{
+	union a_union *in = (void *)&data.in;
+	union a_union *out = (void *)&data.out;
+
+	if (CORE_READ(&out->y, &in->y))
+		return 1;
+
+	return 0;
+}
diff --git a/tools/testing/selftests/bpf/test_bpftool.c b/tools/testing/selftests/bpf/test_bpftool.c
new file mode 100644
index 000000000000..ca7facc582d5
--- /dev/null
+++ b/tools/testing/selftests/bpf/test_bpftool.c
@@ -0,0 +1,228 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
+#include <stdio.h>
+#include <string.h>
+#include <assert.h>
+#include <stdlib.h>
+#include <linux/limits.h>
+
+#include <bpf/libbpf.h>
+#include <bpf/btf.h>
+
+#include "bpf_util.h"
+
+static int run_btfgen(const char *src_btf, const char *dst_btf, const char *objspaths[])
+{
+	char command[4096];
+	int ret, i, n;
+
+	n = snprintf(command, sizeof(command),
+		     "./tools/build/bpftool/bpftool gen min_core_btf %s %s", src_btf, dst_btf);
+	assert(n >= 0 && n < sizeof(command));
+
+	for (i = 0; objspaths[i] != NULL; i++) {
+		assert(sizeof(command) - strlen(command) > strlen(objspaths[i]) + 1);
+		strcat(command, " ");
+		strcat(command, objspaths[i]);
+	}
+
+	printf("Executing bpftool: %s\n", command);
+	printf("---\n");
+	ret = system(command);
+	printf("---\n");
+	return ret;
+}
+
+struct btfgen_test {
+	const char *descr;
+	const char *src_btf;
+	const char *bpfobj[16];
+	void (*run_test)(struct btf *btf);
+};
+
+static void check_btfgen_primitive_struct(struct btf *btf)
+{
+	struct btf_member *members;
+	const struct btf_type *t;
+	int id;
+
+	assert(btf__type_cnt(btf) == 3);
+
+	id = btf__find_by_name_kind(btf, "core_reloc_primitives", BTF_KIND_STRUCT);
+	assert(id > 0);
+
+	t = btf__type_by_id(btf, id);
+	assert(btf_vlen(t) == 1);
+
+	members = btf_members(t);
+
+	id = btf__find_by_name_kind(btf, "char", BTF_KIND_INT);
+	assert(id > 0);
+
+	/* the type of the struct member must be the char */
+	assert(members[0].type == id);
+}
+
+static void check_btfgen_primitive_union(struct btf *btf)
+{
+	struct btf_member *members;
+	const struct btf_type *t;
+	int id;
+
+	/* void, a_union and int*/
+	assert(btf__type_cnt(btf) == 3);
+
+	id = btf__find_by_name_kind(btf, "a_union", BTF_KIND_UNION);
+	assert(id > 0);
+
+	t = btf__type_by_id(btf, id);
+	assert(btf_vlen(t) == 1);
+
+	members = btf_members(t);
+
+	id = btf__find_by_name_kind(btf, "int", BTF_KIND_INT);
+	assert(id > 0);
+
+	/* the type of the union member must be the integer */
+	assert(members[0].type == id);
+}
+
+static void check_btfgen_primitive_array(struct btf *btf)
+{
+	int array_id, array_type_id, array_index_type_id;
+	struct btf_array *array;
+
+	/* void, struct, array, int (array index type) and int (array type) */
+	assert(btf__type_cnt(btf) == 5);
+
+	array_id = btf__find_by_name_kind(btf, "", BTF_KIND_ARRAY);
+	assert(array_id > 0);
+
+	array = btf_array(btf__type_by_id(btf, array_id));
+
+	array_type_id = btf__find_by_name_kind(btf, "int", BTF_KIND_INT);
+	assert(array_type_id > 0);
+
+	array_index_type_id = btf__find_by_name_kind(btf, "__ARRAY_SIZE_TYPE__", BTF_KIND_INT);
+	assert(array_index_type_id > 0);
+
+	/* check that array types are the correct ones */
+	assert(array->type == array_type_id);
+	assert(array->index_type == array_index_type_id);
+}
+
+/* If there are relocations in two different BPF objects involving
+ * different members of the same struct, then the generated BTF should
+ * contain a single instance of such struct with both fields.
+ */
+static void check_btfgen_primitive_structs_different_objects(struct btf *btf)
+{
+	struct btf_member *members;
+	const struct btf_type *t;
+	int struct_id, char_id, int_id;
+
+	/* void, struct, int and char */
+	assert(btf__type_cnt(btf) == 4);
+
+	struct_id = btf__find_by_name_kind(btf, "core_reloc_primitives", BTF_KIND_STRUCT);
+	assert(struct_id > 0);
+
+	t = btf__type_by_id(btf, struct_id);
+	assert(btf_vlen(t) == 2);
+
+	members = btf_members(t);
+
+	char_id = btf__find_by_name_kind(btf, "char", BTF_KIND_INT);
+	assert(char_id > 0);
+
+	int_id = btf__find_by_name_kind(btf, "int", BTF_KIND_INT);
+	assert(int_id > 0);
+
+	for (int i = 0; i < btf_vlen(t); i++) {
+		const char *name = btf__str_by_offset(btf, members[i].name_off);
+
+		if (!strcmp("a", name))
+			assert(members[i].type == char_id);
+		else if (!strcmp("b", name))
+			assert(members[i].type == int_id);
+	}
+}
+
+static struct btfgen_test btfgen_tests[] = {
+	{
+		"primitive struct",
+		"btfgen_btf_source.o",
+		{
+			"btfgen_primitives_struct.o",
+		},
+		check_btfgen_primitive_struct,
+	},
+	{
+		"primitive union",
+		"btfgen_btf_source.o",
+		{
+			"btfgen_primitives_union.o",
+		},
+		check_btfgen_primitive_union,
+	},
+	{
+		"primitive array",
+		"btfgen_btf_source.o",
+		{
+			"btfgen_primitives_array.o",
+		},
+		check_btfgen_primitive_array,
+	},
+	{
+		"primitive structs in different objects",
+		"btfgen_btf_source.o",
+		{
+			"btfgen_primitives_struct.o",
+			"btfgen_primitives_struct2.o",
+		},
+		check_btfgen_primitive_structs_different_objects,
+	},
+};
+
+void test_gen_min_core_btf(void)
+{
+	char target_path[PATH_MAX];
+	struct btfgen_test *test;
+	struct btf *dst_btf;
+	int ret;
+
+	for (int i = 0; i < ARRAY_SIZE(btfgen_tests); i++) {
+		char dir_path[] = "/tmp/btfgen-XXXXXX";
+
+		test = &btfgen_tests[i];
+
+		printf("Running %s\n", test->descr);
+
+		mkdtemp(dir_path);
+
+		snprintf(target_path, sizeof(target_path), "%s/foo.btf", dir_path);
+
+		ret = run_btfgen(test->src_btf, target_path, test->bpfobj);
+		assert(ret == 0);
+
+		dst_btf = btf__parse(target_path, NULL);
+		assert(dst_btf != NULL);
+
+		test->run_test(dst_btf);
+
+		printf("Test %s: PASS\n", test->descr);
+	}
+
+	printf("%s: PASS\n", __func__);
+}
+
+int main(void)
+{
+	libbpf_set_strict_mode(LIBBPF_STRICT_ALL);
+
+	test_gen_min_core_btf();
+
+	printf("test_bpftool: OK\n");
+
+	return 0;
+}
-- 
2.25.1

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ