selftests/bpf: Add field existence CO-RE relocs tests

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
This commit is contained in:
Andrii Nakryiko 2019-10-15 11:28:49 -07:00 committed by Alexei Starovoitov
parent 01340e3191
commit c7566a6969
11 changed files with 233 additions and 2 deletions

View File

@ -174,6 +174,21 @@
.fails = true, \ .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 { struct core_reloc_test_case {
const char *case_name; const char *case_name;
const char *bpf_obj_file; const char *bpf_obj_file;
@ -183,6 +198,7 @@ struct core_reloc_test_case {
const char *output; const char *output;
int output_len; int output_len;
bool fails; bool fails;
bool relaxed_core_relocs;
}; };
static struct core_reloc_test_case test_cases[] = { 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), .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 { struct data {
@ -305,11 +374,14 @@ void test_core_reloc(void)
for (i = 0; i < ARRAY_SIZE(test_cases); i++) { for (i = 0; i < ARRAY_SIZE(test_cases); i++) {
test_case = &test_cases[i]; test_case = &test_cases[i];
if (!test__start_subtest(test_case->case_name)) if (!test__start_subtest(test_case->case_name))
continue; 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", if (CHECK(IS_ERR_OR_NULL(obj), "obj_open",
"failed to open '%s': %ld\n", "failed to open '%s': %ld\n",
test_case->bpf_obj_file, PTR_ERR(obj))) test_case->bpf_obj_file, PTR_ERR(obj)))

View File

@ -0,0 +1,3 @@
#include "core_reloc_types.h"
void f(struct core_reloc_existence x) {}

View File

@ -0,0 +1,3 @@
#include "core_reloc_types.h"
void f(struct core_reloc_existence___err_wrong_arr_kind x) {}

View File

@ -0,0 +1,3 @@
#include "core_reloc_types.h"
void f(struct core_reloc_existence___err_wrong_arr_value_type x) {}

View File

@ -0,0 +1,3 @@
#include "core_reloc_types.h"
void f(struct core_reloc_existence___err_wrong_int_kind x) {}

View File

@ -0,0 +1,3 @@
#include "core_reloc_types.h"
void f(struct core_reloc_existence___err_wrong_int_sz x) {}

View File

@ -0,0 +1,3 @@
#include "core_reloc_types.h"
void f(struct core_reloc_existence___err_wrong_int_type x) {}

View File

@ -0,0 +1,3 @@
#include "core_reloc_types.h"
void f(struct core_reloc_existence___err_wrong_struct_type x) {}

View File

@ -0,0 +1,3 @@
#include "core_reloc_types.h"
void f(struct core_reloc_existence___minimal x) {}

View File

@ -674,3 +674,59 @@ struct core_reloc_misc_extensible {
int c; int c;
int d; 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;
};

View File

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