forked from tiwai/sound
-
Notifications
You must be signed in to change notification settings - Fork 16
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
selftest/bpf: Add a test to check trampoline freeing logic.
Add a selftest for commit e21aa34 ("bpf: Fix fexit trampoline.") to make sure that attaching fexit prog to a sleeping kernel function will trigger appropriate trampoline and program destruction. Signed-off-by: Alexei Starovoitov <[email protected]> Signed-off-by: Daniel Borkmann <[email protected]> Link: https://lore.kernel.org/bpf/[email protected]
- Loading branch information
Showing
2 changed files
with
113 additions
and
0 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,82 @@ | ||
// SPDX-License-Identifier: GPL-2.0 | ||
/* Copyright (c) 2021 Facebook */ | ||
#define _GNU_SOURCE | ||
#include <sched.h> | ||
#include <test_progs.h> | ||
#include <time.h> | ||
#include <sys/mman.h> | ||
#include <sys/syscall.h> | ||
#include "fexit_sleep.skel.h" | ||
|
||
static int do_sleep(void *skel) | ||
{ | ||
struct fexit_sleep *fexit_skel = skel; | ||
struct timespec ts1 = { .tv_nsec = 1 }; | ||
struct timespec ts2 = { .tv_sec = 10 }; | ||
|
||
fexit_skel->bss->pid = getpid(); | ||
(void)syscall(__NR_nanosleep, &ts1, NULL); | ||
(void)syscall(__NR_nanosleep, &ts2, NULL); | ||
return 0; | ||
} | ||
|
||
#define STACK_SIZE (1024 * 1024) | ||
static char child_stack[STACK_SIZE]; | ||
|
||
void test_fexit_sleep(void) | ||
{ | ||
struct fexit_sleep *fexit_skel = NULL; | ||
int wstatus, duration = 0; | ||
pid_t cpid; | ||
int err, fexit_cnt; | ||
|
||
fexit_skel = fexit_sleep__open_and_load(); | ||
if (CHECK(!fexit_skel, "fexit_skel_load", "fexit skeleton failed\n")) | ||
goto cleanup; | ||
|
||
err = fexit_sleep__attach(fexit_skel); | ||
if (CHECK(err, "fexit_attach", "fexit attach failed: %d\n", err)) | ||
goto cleanup; | ||
|
||
cpid = clone(do_sleep, child_stack + STACK_SIZE, CLONE_FILES | SIGCHLD, fexit_skel); | ||
if (CHECK(cpid == -1, "clone", strerror(errno))) | ||
goto cleanup; | ||
|
||
/* wait until first sys_nanosleep ends and second sys_nanosleep starts */ | ||
while (READ_ONCE(fexit_skel->bss->fentry_cnt) != 2); | ||
fexit_cnt = READ_ONCE(fexit_skel->bss->fexit_cnt); | ||
if (CHECK(fexit_cnt != 1, "fexit_cnt", "%d", fexit_cnt)) | ||
goto cleanup; | ||
|
||
/* close progs and detach them. That will trigger two nop5->jmp5 rewrites | ||
* in the trampolines to skip nanosleep_fexit prog. | ||
* The nanosleep_fentry prog will get detached first. | ||
* The nanosleep_fexit prog will get detached second. | ||
* Detaching will trigger freeing of both progs JITed images. | ||
* There will be two dying bpf_tramp_image-s, but only the initial | ||
* bpf_tramp_image (with both _fentry and _fexit progs will be stuck | ||
* waiting for percpu_ref_kill to confirm). The other one | ||
* will be freed quickly. | ||
*/ | ||
close(bpf_program__fd(fexit_skel->progs.nanosleep_fentry)); | ||
close(bpf_program__fd(fexit_skel->progs.nanosleep_fexit)); | ||
fexit_sleep__detach(fexit_skel); | ||
|
||
/* kill the thread to unwind sys_nanosleep stack through the trampoline */ | ||
kill(cpid, 9); | ||
|
||
if (CHECK(waitpid(cpid, &wstatus, 0) == -1, "waitpid", strerror(errno))) | ||
goto cleanup; | ||
if (CHECK(WEXITSTATUS(wstatus) != 0, "exitstatus", "failed")) | ||
goto cleanup; | ||
|
||
/* The bypassed nanosleep_fexit prog shouldn't have executed. | ||
* Unlike progs the maps were not freed and directly accessible. | ||
*/ | ||
fexit_cnt = READ_ONCE(fexit_skel->bss->fexit_cnt); | ||
if (CHECK(fexit_cnt != 1, "fexit_cnt", "%d", fexit_cnt)) | ||
goto cleanup; | ||
|
||
cleanup: | ||
fexit_sleep__destroy(fexit_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,31 @@ | ||
// SPDX-License-Identifier: GPL-2.0 | ||
/* Copyright (c) 2021 Facebook */ | ||
#include "vmlinux.h" | ||
#include <bpf/bpf_helpers.h> | ||
#include <bpf/bpf_tracing.h> | ||
|
||
char LICENSE[] SEC("license") = "GPL"; | ||
|
||
int pid = 0; | ||
int fentry_cnt = 0; | ||
int fexit_cnt = 0; | ||
|
||
SEC("fentry/__x64_sys_nanosleep") | ||
int BPF_PROG(nanosleep_fentry, const struct pt_regs *regs) | ||
{ | ||
if ((int)bpf_get_current_pid_tgid() != pid) | ||
return 0; | ||
|
||
fentry_cnt++; | ||
return 0; | ||
} | ||
|
||
SEC("fexit/__x64_sys_nanosleep") | ||
int BPF_PROG(nanosleep_fexit, const struct pt_regs *regs, int ret) | ||
{ | ||
if ((int)bpf_get_current_pid_tgid() != pid) | ||
return 0; | ||
|
||
fexit_cnt++; | ||
return 0; | ||
} |