selftests/bpf: Add field existence CO-RE relocs tests
authorAndrii Nakryiko <andriin@fb.com>
Tue, 15 Oct 2019 18:28:49 +0000 (11:28 -0700)
committerAlexei Starovoitov <ast@kernel.org>
Tue, 15 Oct 2019 23:06:05 +0000 (16:06 -0700)
Add a bunch of tests validating CO-RE is handling field existence
relocation. Relaxed CO-RE relocation mode is activated for these new
tests to prevent libbpf from rejecting BPF object for no-match
relocation, even though test BPF program is not going to use that
relocation, if field is missing.

Signed-off-by: Andrii Nakryiko <andriin@fb.com>
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
Link: https://lore.kernel.org/bpf/20191015182849.3922287-6-andriin@fb.com
tools/testing/selftests/bpf/prog_tests/core_reloc.c
tools/testing/selftests/bpf/progs/btf__core_reloc_existence.c [new file with mode: 0644]
tools/testing/selftests/bpf/progs/btf__core_reloc_existence___err_wrong_arr_kind.c [new file with mode: 0644]
tools/testing/selftests/bpf/progs/btf__core_reloc_existence___err_wrong_arr_value_type.c [new file with mode: 0644]
tools/testing/selftests/bpf/progs/btf__core_reloc_existence___err_wrong_int_kind.c [new file with mode: 0644]
tools/testing/selftests/bpf/progs/btf__core_reloc_existence___err_wrong_int_sz.c [new file with mode: 0644]
tools/testing/selftests/bpf/progs/btf__core_reloc_existence___err_wrong_int_type.c [new file with mode: 0644]
tools/testing/selftests/bpf/progs/btf__core_reloc_existence___err_wrong_struct_type.c [new file with mode: 0644]
tools/testing/selftests/bpf/progs/btf__core_reloc_existence___minimal.c [new file with mode: 0644]
tools/testing/selftests/bpf/progs/core_reloc_types.h
tools/testing/selftests/bpf/progs/test_core_reloc_existence.c [new file with mode: 0644]

index 21a0dff..7e2f5b4 100644 (file)
        .fails = true,                                                  \
 }
 
+#define EXISTENCE_DATA(struct_name) STRUCT_TO_CHAR_PTR(struct_name) {  \
+       .a = 42,                                                        \
+}
+
+#define EXISTENCE_CASE_COMMON(name)                                    \
+       .case_name = #name,                                             \
+       .bpf_obj_file = "test_core_reloc_existence.o",                  \
+       .btf_src_file = "btf__core_reloc_" #name ".o",                  \
+       .relaxed_core_relocs = true                                     \
+
+#define EXISTENCE_ERR_CASE(name) {                                     \
+       EXISTENCE_CASE_COMMON(name),                                    \
+       .fails = true,                                                  \
+}
+
 struct core_reloc_test_case {
        const char *case_name;
        const char *bpf_obj_file;
@@ -183,6 +198,7 @@ struct core_reloc_test_case {
        const char *output;
        int output_len;
        bool fails;
+       bool relaxed_core_relocs;
 };
 
 static struct core_reloc_test_case test_cases[] = {
@@ -283,6 +299,59 @@ static struct core_reloc_test_case test_cases[] = {
                },
                .output_len = sizeof(struct core_reloc_misc_output),
        },
+
+       /* validate field existence checks */
+       {
+               EXISTENCE_CASE_COMMON(existence),
+               .input = STRUCT_TO_CHAR_PTR(core_reloc_existence) {
+                       .a = 1,
+                       .b = 2,
+                       .c = 3,
+                       .arr = { 4 },
+                       .s = { .x = 5 },
+               },
+               .input_len = sizeof(struct core_reloc_existence),
+               .output = STRUCT_TO_CHAR_PTR(core_reloc_existence_output) {
+                       .a_exists = 1,
+                       .b_exists = 1,
+                       .c_exists = 1,
+                       .arr_exists = 1,
+                       .s_exists = 1,
+                       .a_value = 1,
+                       .b_value = 2,
+                       .c_value = 3,
+                       .arr_value = 4,
+                       .s_value = 5,
+               },
+               .output_len = sizeof(struct core_reloc_existence_output),
+       },
+       {
+               EXISTENCE_CASE_COMMON(existence___minimal),
+               .input = STRUCT_TO_CHAR_PTR(core_reloc_existence___minimal) {
+                       .a = 42,
+               },
+               .input_len = sizeof(struct core_reloc_existence),
+               .output = STRUCT_TO_CHAR_PTR(core_reloc_existence_output) {
+                       .a_exists = 1,
+                       .b_exists = 0,
+                       .c_exists = 0,
+                       .arr_exists = 0,
+                       .s_exists = 0,
+                       .a_value = 42,
+                       .b_value = 0xff000002u,
+                       .c_value = 0xff000003u,
+                       .arr_value = 0xff000004u,
+                       .s_value = 0xff000005u,
+               },
+               .output_len = sizeof(struct core_reloc_existence_output),
+       },
+
+       EXISTENCE_ERR_CASE(existence__err_int_sz),
+       EXISTENCE_ERR_CASE(existence__err_int_type),
+       EXISTENCE_ERR_CASE(existence__err_int_kind),
+       EXISTENCE_ERR_CASE(existence__err_arr_kind),
+       EXISTENCE_ERR_CASE(existence__err_arr_value_type),
+       EXISTENCE_ERR_CASE(existence__err_struct_type),
 };
 
 struct data {
@@ -305,11 +374,14 @@ void test_core_reloc(void)
 
        for (i = 0; i < ARRAY_SIZE(test_cases); i++) {
                test_case = &test_cases[i];
-
                if (!test__start_subtest(test_case->case_name))
                        continue;
 
-               obj = bpf_object__open(test_case->bpf_obj_file);
+               LIBBPF_OPTS(bpf_object_open_opts, opts,
+                       .relaxed_core_relocs = test_case->relaxed_core_relocs,
+               );
+
+               obj = bpf_object__open_file(test_case->bpf_obj_file, &opts);
                if (CHECK(IS_ERR_OR_NULL(obj), "obj_open",
                          "failed to open '%s': %ld\n",
                          test_case->bpf_obj_file, PTR_ERR(obj)))
diff --git a/tools/testing/selftests/bpf/progs/btf__core_reloc_existence.c b/tools/testing/selftests/bpf/progs/btf__core_reloc_existence.c
new file mode 100644 (file)
index 0000000..0b62315
--- /dev/null
@@ -0,0 +1,3 @@
+#include "core_reloc_types.h"
+
+void f(struct core_reloc_existence x) {}
diff --git a/tools/testing/selftests/bpf/progs/btf__core_reloc_existence___err_wrong_arr_kind.c b/tools/testing/selftests/bpf/progs/btf__core_reloc_existence___err_wrong_arr_kind.c
new file mode 100644 (file)
index 0000000..dd0ffa5
--- /dev/null
@@ -0,0 +1,3 @@
+#include "core_reloc_types.h"
+
+void f(struct core_reloc_existence___err_wrong_arr_kind x) {}
diff --git a/tools/testing/selftests/bpf/progs/btf__core_reloc_existence___err_wrong_arr_value_type.c b/tools/testing/selftests/bpf/progs/btf__core_reloc_existence___err_wrong_arr_value_type.c
new file mode 100644 (file)
index 0000000..bc83372
--- /dev/null
@@ -0,0 +1,3 @@
+#include "core_reloc_types.h"
+
+void f(struct core_reloc_existence___err_wrong_arr_value_type x) {}
diff --git a/tools/testing/selftests/bpf/progs/btf__core_reloc_existence___err_wrong_int_kind.c b/tools/testing/selftests/bpf/progs/btf__core_reloc_existence___err_wrong_int_kind.c
new file mode 100644 (file)
index 0000000..917bec4
--- /dev/null
@@ -0,0 +1,3 @@
+#include "core_reloc_types.h"
+
+void f(struct core_reloc_existence___err_wrong_int_kind x) {}
diff --git a/tools/testing/selftests/bpf/progs/btf__core_reloc_existence___err_wrong_int_sz.c b/tools/testing/selftests/bpf/progs/btf__core_reloc_existence___err_wrong_int_sz.c
new file mode 100644 (file)
index 0000000..6ec7e6e
--- /dev/null
@@ -0,0 +1,3 @@
+#include "core_reloc_types.h"
+
+void f(struct core_reloc_existence___err_wrong_int_sz x) {}
diff --git a/tools/testing/selftests/bpf/progs/btf__core_reloc_existence___err_wrong_int_type.c b/tools/testing/selftests/bpf/progs/btf__core_reloc_existence___err_wrong_int_type.c
new file mode 100644 (file)
index 0000000..7bbcacf
--- /dev/null
@@ -0,0 +1,3 @@
+#include "core_reloc_types.h"
+
+void f(struct core_reloc_existence___err_wrong_int_type x) {}
diff --git a/tools/testing/selftests/bpf/progs/btf__core_reloc_existence___err_wrong_struct_type.c b/tools/testing/selftests/bpf/progs/btf__core_reloc_existence___err_wrong_struct_type.c
new file mode 100644 (file)
index 0000000..f384dd3
--- /dev/null
@@ -0,0 +1,3 @@
+#include "core_reloc_types.h"
+
+void f(struct core_reloc_existence___err_wrong_struct_type x) {}
diff --git a/tools/testing/selftests/bpf/progs/btf__core_reloc_existence___minimal.c b/tools/testing/selftests/bpf/progs/btf__core_reloc_existence___minimal.c
new file mode 100644 (file)
index 0000000..aec2dec
--- /dev/null
@@ -0,0 +1,3 @@
+#include "core_reloc_types.h"
+
+void f(struct core_reloc_existence___minimal x) {}
index 9a6bdeb..ad763ec 100644 (file)
@@ -674,3 +674,59 @@ struct core_reloc_misc_extensible {
        int c;
        int d;
 };
+
+/*
+ * EXISTENCE
+ */
+struct core_reloc_existence_output {
+       int a_exists;
+       int a_value;
+       int b_exists;
+       int b_value;
+       int c_exists;
+       int c_value;
+       int arr_exists;
+       int arr_value;
+       int s_exists;
+       int s_value;
+};
+
+struct core_reloc_existence {
+       int a;
+       struct {
+               int b;
+       };
+       int c;
+       int arr[1];
+       struct {
+               int x;
+       } s;
+};
+
+struct core_reloc_existence___minimal {
+       int a;
+};
+
+struct core_reloc_existence___err_wrong_int_sz {
+       short a;
+};
+
+struct core_reloc_existence___err_wrong_int_type {
+       int b[1];
+};
+
+struct core_reloc_existence___err_wrong_int_kind {
+       struct{ int x; } c;
+};
+
+struct core_reloc_existence___err_wrong_arr_kind {
+       int arr;
+};
+
+struct core_reloc_existence___err_wrong_arr_value_type {
+       short arr[1];
+};
+
+struct core_reloc_existence___err_wrong_struct_type {
+       int s;
+};
diff --git a/tools/testing/selftests/bpf/progs/test_core_reloc_existence.c b/tools/testing/selftests/bpf/progs/test_core_reloc_existence.c
new file mode 100644 (file)
index 0000000..c3cac95
--- /dev/null
@@ -0,0 +1,79 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright (c) 2019 Facebook
+
+#include <linux/bpf.h>
+#include <stdint.h>
+#include "bpf_helpers.h"
+#include "bpf_core_read.h"
+
+char _license[] SEC("license") = "GPL";
+
+static volatile struct data {
+       char in[256];
+       char out[256];
+} data;
+
+struct core_reloc_existence_output {
+       int a_exists;
+       int a_value;
+       int b_exists;
+       int b_value;
+       int c_exists;
+       int c_value;
+       int arr_exists;
+       int arr_value;
+       int s_exists;
+       int s_value;
+};
+
+struct core_reloc_existence {
+       struct {
+               int x;
+       } s;
+       int arr[1];
+       int a;
+       struct {
+               int b;
+       };
+       int c;
+};
+
+SEC("raw_tracepoint/sys_enter")
+int test_core_existence(void *ctx)
+{
+       struct core_reloc_existence *in = (void *)&data.in;
+       struct core_reloc_existence_output *out = (void *)&data.out;
+
+       out->a_exists = bpf_core_field_exists(in->a);
+       if (bpf_core_field_exists(in->a))
+               out->a_value = BPF_CORE_READ(in, a);
+       else
+               out->a_value = 0xff000001u;
+
+       out->b_exists = bpf_core_field_exists(in->b);
+       if (bpf_core_field_exists(in->b))
+               out->b_value = BPF_CORE_READ(in, b);
+       else
+               out->b_value = 0xff000002u;
+
+       out->c_exists = bpf_core_field_exists(in->c);
+       if (bpf_core_field_exists(in->c))
+               out->c_value = BPF_CORE_READ(in, c);
+       else
+               out->c_value = 0xff000003u;
+
+       out->arr_exists = bpf_core_field_exists(in->arr);
+       if (bpf_core_field_exists(in->arr))
+               out->arr_value = BPF_CORE_READ(in, arr[0]);
+       else
+               out->arr_value = 0xff000004u;
+
+       out->s_exists = bpf_core_field_exists(in->s);
+       if (bpf_core_field_exists(in->s))
+               out->s_value = BPF_CORE_READ(in, s.x);
+       else
+               out->s_value = 0xff000005u;
+
+       return 0;
+}
+