Skip to content

Commit

Permalink
selftests/bpf: Add test for recursive attachment of tracing progs
Browse files Browse the repository at this point in the history
Verify the fact that only one fentry prog could be attached to another
fentry, building up an attachment chain of limited size. Use existing
bpf_testmod as a start of the chain.

Acked-by: Jiri Olsa <olsajiri@gmail.com>
Acked-by: Song Liu <song@kernel.org>
Signed-off-by: Dmitrii Dolgov <9erthalion6@gmail.com>
Link: https://lore.kernel.org/r/20240103190559.14750-3-9erthalion6@gmail.com
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
  • Loading branch information
Dmitrii Dolgov authored and Alexei Starovoitov committed Jan 5, 2024
1 parent 19bfcdf commit 5c5371e
Show file tree
Hide file tree
Showing 3 changed files with 137 additions and 0 deletions.
107 changes: 107 additions & 0 deletions tools/testing/selftests/bpf/prog_tests/recursive_attach.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
// 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);
}
14 changes: 14 additions & 0 deletions tools/testing/selftests/bpf/progs/fentry_recursive.c
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;
}
16 changes: 16 additions & 0 deletions tools/testing/selftests/bpf/progs/fentry_recursive_target.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
// 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;
}

0 comments on commit 5c5371e

Please sign in to comment.