linux-stable/tools/testing/selftests/bpf/prog_tests/find_vma.c
Song Liu f108662b27 selftests/bpf: Add tests for bpf_find_vma
Add tests for bpf_find_vma in perf_event program and kprobe program. The
perf_event program is triggered from NMI context, so the second call of
bpf_find_vma() will return -EBUSY (irq_work busy). The kprobe program,
on the other hand, does not have this constraint.

Also add tests for illegal writes to task or vma from the callback
function. The verifier should reject both cases.

Signed-off-by: Song Liu <songliubraving@fb.com>
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
Acked-by: Yonghong Song <yhs@fb.com>
Link: https://lore.kernel.org/bpf/20211105232330.1936330-3-songliubraving@fb.com
2021-11-07 11:54:51 -08:00

117 lines
2.8 KiB
C

// SPDX-License-Identifier: GPL-2.0
/* Copyright (c) 2021 Facebook */
#include <test_progs.h>
#include <sys/types.h>
#include <unistd.h>
#include "find_vma.skel.h"
#include "find_vma_fail1.skel.h"
#include "find_vma_fail2.skel.h"
static void test_and_reset_skel(struct find_vma *skel, int expected_find_zero_ret)
{
ASSERT_EQ(skel->bss->found_vm_exec, 1, "found_vm_exec");
ASSERT_EQ(skel->data->find_addr_ret, 0, "find_addr_ret");
ASSERT_EQ(skel->data->find_zero_ret, expected_find_zero_ret, "find_zero_ret");
ASSERT_OK_PTR(strstr(skel->bss->d_iname, "test_progs"), "find_test_progs");
skel->bss->found_vm_exec = 0;
skel->data->find_addr_ret = -1;
skel->data->find_zero_ret = -1;
skel->bss->d_iname[0] = 0;
}
static int open_pe(void)
{
struct perf_event_attr attr = {0};
int pfd;
/* create perf event */
attr.size = sizeof(attr);
attr.type = PERF_TYPE_HARDWARE;
attr.config = PERF_COUNT_HW_CPU_CYCLES;
attr.freq = 1;
attr.sample_freq = 4000;
pfd = syscall(__NR_perf_event_open, &attr, 0, -1, -1, PERF_FLAG_FD_CLOEXEC);
return pfd >= 0 ? pfd : -errno;
}
static void test_find_vma_pe(struct find_vma *skel)
{
struct bpf_link *link = NULL;
volatile int j = 0;
int pfd, i;
pfd = open_pe();
if (pfd < 0) {
if (pfd == -ENOENT || pfd == -EOPNOTSUPP) {
printf("%s:SKIP:no PERF_COUNT_HW_CPU_CYCLES\n", __func__);
test__skip();
goto cleanup;
}
if (!ASSERT_GE(pfd, 0, "perf_event_open"))
goto cleanup;
}
link = bpf_program__attach_perf_event(skel->progs.handle_pe, pfd);
if (!ASSERT_OK_PTR(link, "attach_perf_event"))
goto cleanup;
for (i = 0; i < 1000000; ++i)
++j;
test_and_reset_skel(skel, -EBUSY /* in nmi, irq_work is busy */);
cleanup:
bpf_link__destroy(link);
close(pfd);
}
static void test_find_vma_kprobe(struct find_vma *skel)
{
int err;
err = find_vma__attach(skel);
if (!ASSERT_OK(err, "get_branch_snapshot__attach"))
return;
getpgid(skel->bss->target_pid);
test_and_reset_skel(skel, -ENOENT /* could not find vma for ptr 0 */);
}
static void test_illegal_write_vma(void)
{
struct find_vma_fail1 *skel;
skel = find_vma_fail1__open_and_load();
if (!ASSERT_ERR_PTR(skel, "find_vma_fail1__open_and_load"))
find_vma_fail1__destroy(skel);
}
static void test_illegal_write_task(void)
{
struct find_vma_fail2 *skel;
skel = find_vma_fail2__open_and_load();
if (!ASSERT_ERR_PTR(skel, "find_vma_fail2__open_and_load"))
find_vma_fail2__destroy(skel);
}
void serial_test_find_vma(void)
{
struct find_vma *skel;
skel = find_vma__open_and_load();
if (!ASSERT_OK_PTR(skel, "find_vma__open_and_load"))
return;
skel->bss->target_pid = getpid();
skel->bss->addr = (__u64)(uintptr_t)test_find_vma_pe;
test_find_vma_pe(skel);
usleep(100000); /* allow the irq_work to finish */
test_find_vma_kprobe(skel);
find_vma__destroy(skel);
test_illegal_write_vma();
test_illegal_write_task();
}