-
Notifications
You must be signed in to change notification settings - Fork 123
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge branch 'relax-tracing-prog-recursive-attach-rules'
Dmitrii Dolgov says: ==================== Relax tracing prog recursive attach rules Currently, it's not allowed to attach an fentry/fexit prog to another fentry/fexit. At the same time it's not uncommon to see a tracing program with lots of logic in use, and the attachment limitation prevents usage of fentry/fexit for performance analysis (e.g. with "bpftool prog profile" command) in this case. An example could be falcosecurity libs project that uses tp_btf tracing programs for offloading certain part of logic into tail-called programs, but the use-case is still generic enough -- a tracing program could be complicated and heavy enough to warrant its profiling, yet frustratingly it's not possible to do so use best tooling for that. Following the corresponding discussion [1], the reason for that is to avoid tracing progs call cycles without introducing more complex solutions. But currently it seems impossible to load and attach tracing programs in a way that will form such a cycle. Replace "no same type" requirement with verification that no more than one level of attachment nesting is allowed. In this way only one fentry/fexit program could be attached to another fentry/fexit to cover profiling use case, and still no cycle could be formed. The series contains a test for recursive attachment, as well as a fix + test for an issue in re-attachment branch of bpf_tracing_prog_attach. When preparing the test for the main change set, I've stumbled upon the possibility to construct a sequence of events when attach_btf would be NULL while computing a trampoline key. It doesn't look like this issue is triggered by the main change, because the reproduces doesn't actually need to have an fentry attachment chain. [1]: https://lore.kernel.org/bpf/20191108064039.2041889-16-ast@kernel.org/ ==================== Link: https://lore.kernel.org/r/20240103190559.14750-1-9erthalion6@gmail.com Signed-off-by: Alexei Starovoitov <ast@kernel.org>
- Loading branch information
Showing
6 changed files
with
247 additions
and
15 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
151 changes: 151 additions & 0 deletions
151
tools/testing/selftests/bpf/prog_tests/recursive_attach.c
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,151 @@ | ||
// SPDX-License-Identifier: GPL-2.0 | ||
/* Copyright (c) 2023 Red Hat, Inc. */ | ||
#include <test_progs.h> | ||
#include "fentry_recursive.skel.h" | ||
#include "fentry_recursive_target.skel.h" | ||
#include <bpf/btf.h> | ||
#include "bpf/libbpf_internal.h" | ||
|
||
/* Test recursive attachment of tracing progs with more than one nesting level | ||
* is not possible. Create a chain of attachment, verify that the last prog | ||
* will fail. Depending on the arguments, following cases are tested: | ||
* | ||
* - Recursive loading of tracing progs, without attaching (attach = false, | ||
* detach = false). The chain looks like this: | ||
* load target | ||
* load fentry1 -> target | ||
* load fentry2 -> fentry1 (fail) | ||
* | ||
* - Recursive attach of tracing progs (attach = true, detach = false). The | ||
* chain looks like this: | ||
* load target | ||
* load fentry1 -> target | ||
* attach fentry1 -> target | ||
* load fentry2 -> fentry1 (fail) | ||
* | ||
* - Recursive attach and detach of tracing progs (attach = true, detach = | ||
* true). This validates that attach_tracing_prog flag will be set throughout | ||
* the whole lifecycle of an fentry prog, independently from whether it's | ||
* detached. The chain looks like this: | ||
* load target | ||
* load fentry1 -> target | ||
* attach fentry1 -> target | ||
* detach fentry1 | ||
* load fentry2 -> fentry1 (fail) | ||
*/ | ||
static void test_recursive_fentry_chain(bool attach, bool detach) | ||
{ | ||
struct fentry_recursive_target *target_skel = NULL; | ||
struct fentry_recursive *tracing_chain[2] = {}; | ||
struct bpf_program *prog; | ||
int prev_fd, err; | ||
|
||
target_skel = fentry_recursive_target__open_and_load(); | ||
if (!ASSERT_OK_PTR(target_skel, "fentry_recursive_target__open_and_load")) | ||
return; | ||
|
||
/* Create an attachment chain with two fentry progs */ | ||
for (int i = 0; i < 2; i++) { | ||
tracing_chain[i] = fentry_recursive__open(); | ||
if (!ASSERT_OK_PTR(tracing_chain[i], "fentry_recursive__open")) | ||
goto close_prog; | ||
|
||
/* The first prog in the chain is going to be attached to the target | ||
* fentry program, the second one to the previous in the chain. | ||
*/ | ||
prog = tracing_chain[i]->progs.recursive_attach; | ||
if (i == 0) { | ||
prev_fd = bpf_program__fd(target_skel->progs.test1); | ||
err = bpf_program__set_attach_target(prog, prev_fd, "test1"); | ||
} else { | ||
prev_fd = bpf_program__fd(tracing_chain[i-1]->progs.recursive_attach); | ||
err = bpf_program__set_attach_target(prog, prev_fd, "recursive_attach"); | ||
} | ||
|
||
if (!ASSERT_OK(err, "bpf_program__set_attach_target")) | ||
goto close_prog; | ||
|
||
err = fentry_recursive__load(tracing_chain[i]); | ||
/* The first attach should succeed, the second fail */ | ||
if (i == 0) { | ||
if (!ASSERT_OK(err, "fentry_recursive__load")) | ||
goto close_prog; | ||
|
||
if (attach) { | ||
err = fentry_recursive__attach(tracing_chain[i]); | ||
if (!ASSERT_OK(err, "fentry_recursive__attach")) | ||
goto close_prog; | ||
} | ||
|
||
if (detach) { | ||
/* Flag attach_tracing_prog should still be set, preventing | ||
* attachment of the following prog. | ||
*/ | ||
fentry_recursive__detach(tracing_chain[i]); | ||
} | ||
} else { | ||
if (!ASSERT_ERR(err, "fentry_recursive__load")) | ||
goto close_prog; | ||
} | ||
} | ||
|
||
close_prog: | ||
fentry_recursive_target__destroy(target_skel); | ||
for (int i = 0; i < 2; i++) { | ||
fentry_recursive__destroy(tracing_chain[i]); | ||
} | ||
} | ||
|
||
void test_recursive_fentry(void) | ||
{ | ||
if (test__start_subtest("attach")) | ||
test_recursive_fentry_chain(true, false); | ||
if (test__start_subtest("load")) | ||
test_recursive_fentry_chain(false, false); | ||
if (test__start_subtest("detach")) | ||
test_recursive_fentry_chain(true, true); | ||
} | ||
|
||
/* Test that a tracing prog reattachment (when we land in | ||
* "prog->aux->dst_trampoline and tgt_prog is NULL" branch in | ||
* bpf_tracing_prog_attach) does not lead to a crash due to missing attach_btf | ||
*/ | ||
void test_fentry_attach_btf_presence(void) | ||
{ | ||
struct fentry_recursive_target *target_skel = NULL; | ||
struct fentry_recursive *tracing_skel = NULL; | ||
struct bpf_program *prog; | ||
int err, link_fd, tgt_prog_fd; | ||
|
||
target_skel = fentry_recursive_target__open_and_load(); | ||
if (!ASSERT_OK_PTR(target_skel, "fentry_recursive_target__open_and_load")) | ||
goto close_prog; | ||
|
||
tracing_skel = fentry_recursive__open(); | ||
if (!ASSERT_OK_PTR(tracing_skel, "fentry_recursive__open")) | ||
goto close_prog; | ||
|
||
prog = tracing_skel->progs.recursive_attach; | ||
tgt_prog_fd = bpf_program__fd(target_skel->progs.fentry_target); | ||
err = bpf_program__set_attach_target(prog, tgt_prog_fd, "fentry_target"); | ||
if (!ASSERT_OK(err, "bpf_program__set_attach_target")) | ||
goto close_prog; | ||
|
||
err = fentry_recursive__load(tracing_skel); | ||
if (!ASSERT_OK(err, "fentry_recursive__load")) | ||
goto close_prog; | ||
|
||
tgt_prog_fd = bpf_program__fd(tracing_skel->progs.recursive_attach); | ||
link_fd = bpf_link_create(tgt_prog_fd, 0, BPF_TRACE_FENTRY, NULL); | ||
if (!ASSERT_GE(link_fd, 0, "link_fd")) | ||
goto close_prog; | ||
|
||
fentry_recursive__detach(tracing_skel); | ||
|
||
err = fentry_recursive__attach(tracing_skel); | ||
ASSERT_ERR(err, "fentry_recursive__attach"); | ||
|
||
close_prog: | ||
fentry_recursive_target__destroy(target_skel); | ||
fentry_recursive__destroy(tracing_skel); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
// SPDX-License-Identifier: GPL-2.0 | ||
/* Copyright (c) 2023 Red Hat, Inc. */ | ||
#include <linux/bpf.h> | ||
#include <bpf/bpf_helpers.h> | ||
#include <bpf/bpf_tracing.h> | ||
|
||
char _license[] SEC("license") = "GPL"; | ||
|
||
/* Dummy fentry bpf prog for testing fentry attachment chains */ | ||
SEC("fentry/XXX") | ||
int BPF_PROG(recursive_attach, int a) | ||
{ | ||
return 0; | ||
} |
25 changes: 25 additions & 0 deletions
25
tools/testing/selftests/bpf/progs/fentry_recursive_target.c
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
// SPDX-License-Identifier: GPL-2.0 | ||
/* Copyright (c) 2023 Red Hat, Inc. */ | ||
#include <linux/bpf.h> | ||
#include <bpf/bpf_helpers.h> | ||
#include <bpf/bpf_tracing.h> | ||
|
||
char _license[] SEC("license") = "GPL"; | ||
|
||
/* Dummy fentry bpf prog for testing fentry attachment chains. It's going to be | ||
* a start of the chain. | ||
*/ | ||
SEC("fentry/bpf_testmod_fentry_test1") | ||
int BPF_PROG(test1, int a) | ||
{ | ||
return 0; | ||
} | ||
|
||
/* Dummy bpf prog for testing attach_btf presence when attaching an fentry | ||
* program. | ||
*/ | ||
SEC("raw_tp/sys_enter") | ||
int BPF_PROG(fentry_target, struct pt_regs *regs, long id) | ||
{ | ||
return 0; | ||
} |