Skip to content

Commit 651d49f

Browse files
eddyz87anakryiko
authored andcommitted
selftests/bpf: Verify struct_ops autoload/autocreate sync
Check that autocreate flags of struct_ops map cause autoload of struct_ops corresponding programs: - when struct_ops program is referenced only from a map for which autocreate is set to false, that program should not be loaded; - when struct_ops program with autoload == false is set to be used from a map with autocreate == true using shadow var, that program should be loaded; - when struct_ops program is not referenced from any map object load should fail. Signed-off-by: Eduard Zingerman <[email protected]> Signed-off-by: Andrii Nakryiko <[email protected]> Link: https://lore.kernel.org/bpf/[email protected]
1 parent fe9d049 commit 651d49f

File tree

4 files changed

+125
-4
lines changed

4 files changed

+125
-4
lines changed

tools/testing/selftests/bpf/prog_tests/bad_struct_ops.c

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
#include <test_progs.h>
44
#include "bad_struct_ops.skel.h"
5+
#include "bad_struct_ops2.skel.h"
56

67
static void invalid_prog_reuse(void)
78
{
@@ -28,8 +29,39 @@ static void invalid_prog_reuse(void)
2829
bad_struct_ops__destroy(skel);
2930
}
3031

32+
static void unused_program(void)
33+
{
34+
struct bad_struct_ops2 *skel;
35+
char *log = NULL;
36+
int err;
37+
38+
skel = bad_struct_ops2__open();
39+
if (!ASSERT_OK_PTR(skel, "bad_struct_ops2__open"))
40+
return;
41+
42+
/* struct_ops programs not referenced from any maps are open
43+
* with autoload set to true.
44+
*/
45+
ASSERT_TRUE(bpf_program__autoload(skel->progs.foo), "foo autoload == true");
46+
47+
if (start_libbpf_log_capture())
48+
goto cleanup;
49+
50+
err = bad_struct_ops2__load(skel);
51+
ASSERT_ERR(err, "bad_struct_ops2__load should fail");
52+
log = stop_libbpf_log_capture();
53+
ASSERT_HAS_SUBSTR(log, "prog 'foo': failed to load",
54+
"message about 'foo' failing to load");
55+
56+
cleanup:
57+
free(log);
58+
bad_struct_ops2__destroy(skel);
59+
}
60+
3161
void test_bad_struct_ops(void)
3262
{
3363
if (test__start_subtest("invalid_prog_reuse"))
3464
invalid_prog_reuse();
65+
if (test__start_subtest("unused_program"))
66+
unused_program();
3567
}

tools/testing/selftests/bpf/prog_tests/struct_ops_autocreate.c

Lines changed: 47 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
#include <test_progs.h>
44
#include "struct_ops_autocreate.skel.h"
5+
#include "struct_ops_autocreate2.skel.h"
56

67
static void cant_load_full_object(void)
78
{
@@ -43,18 +44,20 @@ static void can_load_partial_object(void)
4344
if (!ASSERT_OK_PTR(skel, "struct_ops_autocreate__open_opts"))
4445
return;
4546

46-
err = bpf_program__set_autoload(skel->progs.test_2, false);
47-
if (!ASSERT_OK(err, "bpf_program__set_autoload"))
48-
goto cleanup;
49-
5047
err = bpf_map__set_autocreate(skel->maps.testmod_2, false);
5148
if (!ASSERT_OK(err, "bpf_map__set_autocreate"))
5249
goto cleanup;
5350

51+
ASSERT_TRUE(bpf_program__autoload(skel->progs.test_1), "test_1 default autoload");
52+
ASSERT_TRUE(bpf_program__autoload(skel->progs.test_2), "test_2 default autoload");
53+
5454
err = struct_ops_autocreate__load(skel);
5555
if (ASSERT_OK(err, "struct_ops_autocreate__load"))
5656
goto cleanup;
5757

58+
ASSERT_TRUE(bpf_program__autoload(skel->progs.test_1), "test_1 actual autoload");
59+
ASSERT_FALSE(bpf_program__autoload(skel->progs.test_2), "test_2 actual autoload");
60+
5861
link = bpf_map__attach_struct_ops(skel->maps.testmod_1);
5962
if (!ASSERT_OK_PTR(link, "bpf_map__attach_struct_ops"))
6063
goto cleanup;
@@ -67,10 +70,50 @@ static void can_load_partial_object(void)
6770
struct_ops_autocreate__destroy(skel);
6871
}
6972

73+
/* Swap test_mod1->test_1 program from 'bar' to 'foo' using shadow vars.
74+
* test_mod1 load should enable autoload for 'foo'.
75+
*/
76+
static void autoload_and_shadow_vars(void)
77+
{
78+
struct struct_ops_autocreate2 *skel = NULL;
79+
struct bpf_link *link = NULL;
80+
int err;
81+
82+
skel = struct_ops_autocreate2__open();
83+
if (!ASSERT_OK_PTR(skel, "struct_ops_autocreate__open_opts"))
84+
return;
85+
86+
ASSERT_FALSE(bpf_program__autoload(skel->progs.foo), "foo default autoload");
87+
ASSERT_FALSE(bpf_program__autoload(skel->progs.bar), "bar default autoload");
88+
89+
/* loading map testmod_1 would switch foo's autoload to true */
90+
skel->struct_ops.testmod_1->test_1 = skel->progs.foo;
91+
92+
err = struct_ops_autocreate2__load(skel);
93+
if (ASSERT_OK(err, "struct_ops_autocreate__load"))
94+
goto cleanup;
95+
96+
ASSERT_TRUE(bpf_program__autoload(skel->progs.foo), "foo actual autoload");
97+
ASSERT_FALSE(bpf_program__autoload(skel->progs.bar), "bar actual autoload");
98+
99+
link = bpf_map__attach_struct_ops(skel->maps.testmod_1);
100+
if (!ASSERT_OK_PTR(link, "bpf_map__attach_struct_ops"))
101+
goto cleanup;
102+
103+
/* test_1() would be called from bpf_dummy_reg2() in bpf_testmod.c */
104+
err = ASSERT_EQ(skel->bss->test_1_result, 42, "test_1_result");
105+
106+
cleanup:
107+
bpf_link__destroy(link);
108+
struct_ops_autocreate2__destroy(skel);
109+
}
110+
70111
void test_struct_ops_autocreate(void)
71112
{
72113
if (test__start_subtest("cant_load_full_object"))
73114
cant_load_full_object();
74115
if (test__start_subtest("can_load_partial_object"))
75116
can_load_partial_object();
117+
if (test__start_subtest("autoload_and_shadow_vars"))
118+
autoload_and_shadow_vars();
76119
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
// SPDX-License-Identifier: GPL-2.0
2+
3+
#include <linux/bpf.h>
4+
#include <bpf/bpf_helpers.h>
5+
6+
char _license[] SEC("license") = "GPL";
7+
8+
/* This is an unused struct_ops program, it lacks corresponding
9+
* struct_ops map, which provides attachment information.
10+
* W/o additional configuration attempt to load such
11+
* BPF object file would fail.
12+
*/
13+
SEC("struct_ops/foo")
14+
void foo(void) {}
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
// SPDX-License-Identifier: GPL-2.0
2+
3+
#include <linux/bpf.h>
4+
#include <bpf/bpf_helpers.h>
5+
#include <bpf/bpf_tracing.h>
6+
7+
char _license[] SEC("license") = "GPL";
8+
9+
int test_1_result = 0;
10+
11+
SEC("?struct_ops/test_1")
12+
int BPF_PROG(foo)
13+
{
14+
test_1_result = 42;
15+
return 0;
16+
}
17+
18+
SEC("?struct_ops/test_1")
19+
int BPF_PROG(bar)
20+
{
21+
test_1_result = 24;
22+
return 0;
23+
}
24+
25+
struct bpf_testmod_ops {
26+
int (*test_1)(void);
27+
};
28+
29+
SEC(".struct_ops.link")
30+
struct bpf_testmod_ops testmod_1 = {
31+
.test_1 = (void *)bar
32+
};

0 commit comments

Comments
 (0)