Skip to content

Commit ba0cbe2

Browse files
ThinkerYzu1anakryiko
authored andcommitted
selftests/bpf: Make sure libbpf doesn't enforce the signature of a func pointer.
The verifier in the kernel ensures that the struct_ops operators behave correctly by checking that they access parameters and context appropriately. The verifier will approve a program as long as it correctly accesses the context/parameters, regardless of its function signature. In contrast, libbpf should not verify the signature of function pointers and functions to enable flexibility in loading various implementations of an operator even if the signature of the function pointer does not match those in the implementations or the kernel. With this flexibility, user space applications can adapt to different kernel versions by loading a specific implementation of an operator based on feature detection. This is a follow-up of the commit c911fc6 ("libbpf: Skip zeroed or null fields if not found in the kernel type.") Signed-off-by: Kui-Feng Lee <[email protected]> Signed-off-by: Andrii Nakryiko <[email protected]> Link: https://lore.kernel.org/bpf/[email protected]
1 parent 2709547 commit ba0cbe2

File tree

2 files changed

+37
-0
lines changed

2 files changed

+37
-0
lines changed

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

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -138,11 +138,35 @@ static void test_struct_ops_not_zeroed(void)
138138
struct_ops_module__destroy(skel);
139139
}
140140

141+
/* The signature of an implementation might not match the signature of the
142+
* function pointer prototype defined in the BPF program. This mismatch
143+
* should be allowed as long as the behavior of the operator program
144+
* adheres to the signature in the kernel. Libbpf should not enforce the
145+
* signature; rather, let the kernel verifier handle the enforcement.
146+
*/
147+
static void test_struct_ops_incompatible(void)
148+
{
149+
struct struct_ops_module *skel;
150+
struct bpf_link *link;
151+
152+
skel = struct_ops_module__open_and_load();
153+
if (!ASSERT_OK_PTR(skel, "open_and_load"))
154+
return;
155+
156+
link = bpf_map__attach_struct_ops(skel->maps.testmod_incompatible);
157+
if (ASSERT_OK_PTR(link, "attach_struct_ops"))
158+
bpf_link__destroy(link);
159+
160+
struct_ops_module__destroy(skel);
161+
}
162+
141163
void serial_test_struct_ops_module(void)
142164
{
143165
if (test__start_subtest("test_struct_ops_load"))
144166
test_struct_ops_load();
145167
if (test__start_subtest("test_struct_ops_not_zeroed"))
146168
test_struct_ops_not_zeroed();
169+
if (test__start_subtest("test_struct_ops_incompatible"))
170+
test_struct_ops_incompatible();
147171
}
148172

tools/testing/selftests/bpf/progs/struct_ops_module.c

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,3 +68,16 @@ struct bpf_testmod_ops___zeroed testmod_zeroed = {
6868
.test_1 = (void *)test_1,
6969
.test_2 = (void *)test_2_v2,
7070
};
71+
72+
struct bpf_testmod_ops___incompatible {
73+
int (*test_1)(void);
74+
void (*test_2)(int *a);
75+
int data;
76+
};
77+
78+
SEC(".struct_ops.link")
79+
struct bpf_testmod_ops___incompatible testmod_incompatible = {
80+
.test_1 = (void *)test_1,
81+
.test_2 = (void *)test_2,
82+
.data = 3,
83+
};

0 commit comments

Comments
 (0)