selftests/bpf: add CO-RE relocs nesting tests

Add a bunch of test validating correct handling of nested
structs/unions.

Signed-off-by: Andrii Nakryiko <andriin@fb.com>
Acked-by: Song Liu <songliubraving@fb.com>
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
This commit is contained in:
Andrii Nakryiko 2019-08-07 14:39:55 -07:00 committed by Alexei Starovoitov
parent 002d3afce6
commit ec6438a988
16 changed files with 421 additions and 0 deletions

View File

@ -28,6 +28,29 @@
.fails = true, \
}
#define NESTING_DATA(struct_name) STRUCT_TO_CHAR_PTR(struct_name) { \
.a = { .a = { .a = 42 } }, \
.b = { .b = { .b = 0xc001 } }, \
}
#define NESTING_CASE_COMMON(name) \
.case_name = #name, \
.bpf_obj_file = "test_core_reloc_nesting.o", \
.btf_src_file = "btf__core_reloc_" #name ".o"
#define NESTING_CASE(name) { \
NESTING_CASE_COMMON(name), \
.input = NESTING_DATA(core_reloc_##name), \
.input_len = sizeof(struct core_reloc_##name), \
.output = NESTING_DATA(core_reloc_nesting), \
.output_len = sizeof(struct core_reloc_nesting) \
}
#define NESTING_ERR_CASE(name) { \
NESTING_CASE_COMMON(name), \
.fails = true, \
}
struct core_reloc_test_case {
const char *case_name;
const char *bpf_obj_file;
@ -57,6 +80,22 @@ static struct core_reloc_test_case test_cases[] = {
FLAVORS_CASE(flavors),
FLAVORS_ERR_CASE(flavors__err_wrong_name),
/* various struct/enum nesting and resolution scenarios */
NESTING_CASE(nesting),
NESTING_CASE(nesting___anon_embed),
NESTING_CASE(nesting___struct_union_mixup),
NESTING_CASE(nesting___extra_nesting),
NESTING_CASE(nesting___dup_compat_types),
NESTING_ERR_CASE(nesting___err_missing_field),
NESTING_ERR_CASE(nesting___err_array_field),
NESTING_ERR_CASE(nesting___err_missing_container),
NESTING_ERR_CASE(nesting___err_nonstruct_container),
NESTING_ERR_CASE(nesting___err_array_container),
NESTING_ERR_CASE(nesting___err_dup_incompat_types),
NESTING_ERR_CASE(nesting___err_partial_match_dups),
NESTING_ERR_CASE(nesting___err_too_deep),
};
struct data {

View File

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

View File

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

View File

@ -0,0 +1,5 @@
#include "core_reloc_types.h"
void f1(struct core_reloc_nesting___dup_compat_types x) {}
void f2(struct core_reloc_nesting___dup_compat_types__2 x) {}
void f3(struct core_reloc_nesting___dup_compat_types__3 x) {}

View File

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

View File

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

View File

@ -0,0 +1,4 @@
#include "core_reloc_types.h"
void f1(struct core_reloc_nesting___err_dup_incompat_types__1 x) {}
void f2(struct core_reloc_nesting___err_dup_incompat_types__2 x) {}

View File

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

View File

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

View File

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

View File

@ -0,0 +1,4 @@
#include "core_reloc_types.h"
void f1(struct core_reloc_nesting___err_partial_match_dups__a x) {}
void f2(struct core_reloc_nesting___err_partial_match_dups__b x) {}

View File

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

View File

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

View File

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

View File

@ -13,3 +13,296 @@ struct core_reloc_flavors__err_wrong_name {
int b;
int c;
};
/*
* NESTING
*/
/* original set up, used to record relocations in BPF program */
struct core_reloc_nesting_substruct {
int a;
};
union core_reloc_nesting_subunion {
int b;
};
struct core_reloc_nesting {
union {
struct core_reloc_nesting_substruct a;
} a;
struct {
union core_reloc_nesting_subunion b;
} b;
};
/* inlined anonymous struct/union instead of named structs in original */
struct core_reloc_nesting___anon_embed {
int __just_for_padding;
union {
struct {
int a;
} a;
} a;
struct {
union {
int b;
} b;
} b;
};
/* different mix of nested structs/unions than in original */
struct core_reloc_nesting___struct_union_mixup {
int __a;
struct {
int __a;
union {
char __a;
int a;
} a;
} a;
int __b;
union {
int __b;
union {
char __b;
int b;
} b;
} b;
};
/* extra anon structs/unions, but still valid a.a.a and b.b.b accessors */
struct core_reloc_nesting___extra_nesting {
int __padding;
struct {
struct {
struct {
struct {
union {
int a;
} a;
};
};
} a;
int __some_more;
struct {
union {
union {
union {
struct {
int b;
};
} b;
};
} b;
};
};
};
/* three flavors of same struct with different structure but same layout for
* a.a.a and b.b.b, thus successfully resolved and relocatable */
struct core_reloc_nesting___dup_compat_types {
char __just_for_padding;
/* 3 more bytes of padding */
struct {
struct {
int a; /* offset 4 */
} a;
} a;
long long __more_padding;
struct {
struct {
int b; /* offset 16 */
} b;
} b;
};
struct core_reloc_nesting___dup_compat_types__2 {
int __aligned_padding;
struct {
int __trickier_noop[0];
struct {
char __some_more_noops[0];
int a; /* offset 4 */
} a;
} a;
int __more_padding;
struct {
struct {
struct {
int __critical_padding;
int b; /* offset 16 */
} b;
int __does_not_matter;
};
} b;
int __more_irrelevant_stuff;
};
struct core_reloc_nesting___dup_compat_types__3 {
char __correct_padding[4];
struct {
struct {
int a; /* offset 4 */
} a;
} a;
/* 8 byte padding due to next struct's alignment */
struct {
struct {
int b;
} b;
} b __attribute__((aligned(16)));
};
/* b.b.b field is missing */
struct core_reloc_nesting___err_missing_field {
struct {
struct {
int a;
} a;
} a;
struct {
struct {
int x;
} b;
} b;
};
/* b.b.b field is an array of integers instead of plain int */
struct core_reloc_nesting___err_array_field {
struct {
struct {
int a;
} a;
} a;
struct {
struct {
int b[1];
} b;
} b;
};
/* middle b container is missing */
struct core_reloc_nesting___err_missing_container {
struct {
struct {
int a;
} a;
} a;
struct {
int x;
} b;
};
/* middle b container is referenced through pointer instead of being embedded */
struct core_reloc_nesting___err_nonstruct_container {
struct {
struct {
int a;
} a;
} a;
struct {
struct {
int b;
} *b;
} b;
};
/* middle b container is an array of structs instead of plain struct */
struct core_reloc_nesting___err_array_container {
struct {
struct {
int a;
} a;
} a;
struct {
struct {
int b;
} b[1];
} b;
};
/* two flavors of same struct with incompatible layout for b.b.b */
struct core_reloc_nesting___err_dup_incompat_types__1 {
struct {
struct {
int a; /* offset 0 */
} a;
} a;
struct {
struct {
int b; /* offset 4 */
} b;
} b;
};
struct core_reloc_nesting___err_dup_incompat_types__2 {
struct {
struct {
int a; /* offset 0 */
} a;
} a;
int __extra_padding;
struct {
struct {
int b; /* offset 8 (!) */
} b;
} b;
};
/* two flavors of same struct having one of a.a.a and b.b.b, but not both */
struct core_reloc_nesting___err_partial_match_dups__a {
struct {
struct {
int a;
} a;
} a;
};
struct core_reloc_nesting___err_partial_match_dups__b {
struct {
struct {
int b;
} b;
} b;
};
struct core_reloc_nesting___err_too_deep {
struct {
struct {
int a;
} a;
} a;
/* 65 levels of nestedness for b.b.b */
struct {
struct {
struct { struct { struct { struct { struct {
struct { struct { struct { struct { struct {
struct { struct { struct { struct { struct {
struct { struct { struct { struct { struct {
struct { struct { struct { struct { struct {
struct { struct { struct { struct { struct {
struct { struct { struct { struct { struct {
struct { struct { struct { struct { struct {
struct { struct { struct { struct { struct {
struct { struct { struct { struct { struct {
struct { struct { struct { struct { struct {
struct { struct { struct { struct { struct {
/* this one is one too much */
struct {
int b;
};
}; }; }; }; };
}; }; }; }; };
}; }; }; }; };
}; }; }; }; };
}; }; }; }; };
}; }; }; }; };
}; }; }; }; };
}; }; }; }; };
}; }; }; }; };
}; }; }; }; };
}; }; }; }; };
}; }; }; }; };
} b;
} b;
};

View File

@ -0,0 +1,46 @@
// SPDX-License-Identifier: GPL-2.0
// Copyright (c) 2019 Facebook
#include <linux/bpf.h>
#include <stdint.h>
#include "bpf_helpers.h"
char _license[] SEC("license") = "GPL";
static volatile struct data {
char in[256];
char out[256];
} data;
struct core_reloc_nesting_substruct {
int a;
};
union core_reloc_nesting_subunion {
int b;
};
/* int a.a.a and b.b.b accesses */
struct core_reloc_nesting {
union {
struct core_reloc_nesting_substruct a;
} a;
struct {
union core_reloc_nesting_subunion b;
} b;
};
SEC("raw_tracepoint/sys_enter")
int test_core_nesting(void *ctx)
{
struct core_reloc_nesting *in = (void *)&data.in;
struct core_reloc_nesting *out = (void *)&data.out;
if (BPF_CORE_READ(&out->a.a.a, &in->a.a.a))
return 1;
if (BPF_CORE_READ(&out->b.b.b, &in->b.b.b))
return 1;
return 0;
}