mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2026-08-09 06:14:34 +02:00
The file_reader/on_open_expect_fault fails consistently on my system. It expects a page fault on first dynptr read of some range the exe file of the current process because it has paged out that page range earlier. However a lot can happen to that range (which depending on the actual memory layout could contain text section, data section, sections )related to dynamic linking...) between the moment it was paged out and the moment the bpf program expected to hit a pagefault actually run. A bit of instrumentation with mincore() shows that pages from that range were accessed several times before the program is run. In particular the call of file_reader__load() seems to fault all the range in. Move the call to madvise(MADV_PAGEOUT) to just before attaching the program to minimize the risk of having those page pulled back in from under our feet. Signed-off-by: Jerome Marchand <jmarchan@redhat.com> Acked-by: Mykyta Yatsenko <yatsenko@meta.com> Acked-by: Jiri Olsa <jolsa@kernel.org> Link: https://lore.kernel.org/bpf/20260420134637.2513867-1-jmarchan@redhat.com Signed-off-by: Kumar Kartikeya Dwivedi <memxor@gmail.com>
116 lines
2.6 KiB
C
116 lines
2.6 KiB
C
// SPDX-License-Identifier: GPL-2.0
|
|
/* Copyright (c) 2025 Meta Platforms, Inc. and affiliates. */
|
|
|
|
#include <test_progs.h>
|
|
#include <network_helpers.h>
|
|
#include "file_reader.skel.h"
|
|
#include "file_reader_fail.skel.h"
|
|
#include <dlfcn.h>
|
|
#include <sys/mman.h>
|
|
|
|
const char *user_ptr = "hello world";
|
|
char file_contents[256000];
|
|
void *addr;
|
|
|
|
void *get_executable_base_addr(void)
|
|
{
|
|
Dl_info info;
|
|
|
|
if (!dladdr((void *)&get_executable_base_addr, &info)) {
|
|
fprintf(stderr, "dladdr failed\n");
|
|
return NULL;
|
|
}
|
|
|
|
return info.dli_fbase;
|
|
}
|
|
|
|
static int initialize_file_contents(void)
|
|
{
|
|
int fd, page_sz = sysconf(_SC_PAGESIZE);
|
|
ssize_t n = 0, cur;
|
|
|
|
fd = open("/proc/self/exe", O_RDONLY);
|
|
if (!ASSERT_OK_FD(fd, "Open /proc/self/exe\n"))
|
|
return 1;
|
|
|
|
do {
|
|
cur = read(fd, file_contents + n, sizeof(file_contents) - n);
|
|
if (!ASSERT_GT(cur, 0, "read success"))
|
|
break;
|
|
n += cur;
|
|
} while (n < sizeof(file_contents));
|
|
|
|
close(fd);
|
|
|
|
if (!ASSERT_EQ(n, sizeof(file_contents), "Read /proc/self/exe\n"))
|
|
return 1;
|
|
|
|
addr = get_executable_base_addr();
|
|
if (!ASSERT_NEQ(addr, NULL, "get executable address"))
|
|
return 1;
|
|
|
|
/* page-align base file address */
|
|
addr = (void *)((unsigned long)addr & ~(page_sz - 1));
|
|
|
|
return 0;
|
|
}
|
|
|
|
static void run_test(const char *prog_name)
|
|
{
|
|
struct file_reader *skel;
|
|
struct bpf_program *prog;
|
|
int err, fd;
|
|
|
|
err = initialize_file_contents();
|
|
if (!ASSERT_OK(err, "initialize file contents"))
|
|
return;
|
|
|
|
skel = file_reader__open();
|
|
if (!ASSERT_OK_PTR(skel, "file_reader__open"))
|
|
return;
|
|
|
|
bpf_object__for_each_program(prog, skel->obj) {
|
|
bpf_program__set_autoload(prog, strcmp(bpf_program__name(prog), prog_name) == 0);
|
|
}
|
|
|
|
memcpy(skel->bss->user_buf, file_contents, sizeof(file_contents));
|
|
skel->bss->pid = getpid();
|
|
|
|
err = file_reader__load(skel);
|
|
if (!ASSERT_OK(err, "file_reader__load"))
|
|
goto cleanup;
|
|
|
|
/*
|
|
* Page out range 0..512K, use 0..256K for positive tests and
|
|
* 256K..512K for negative tests expecting page faults
|
|
*/
|
|
if (!ASSERT_OK(madvise(addr, sizeof(file_contents) * 2, MADV_PAGEOUT),
|
|
"madvise pageout"))
|
|
goto cleanup;
|
|
|
|
err = file_reader__attach(skel);
|
|
if (!ASSERT_OK(err, "file_reader__attach"))
|
|
goto cleanup;
|
|
|
|
fd = open("/proc/self/exe", O_RDONLY);
|
|
if (fd >= 0)
|
|
close(fd);
|
|
|
|
ASSERT_EQ(skel->bss->err, 0, "err");
|
|
ASSERT_EQ(skel->bss->run_success, 1, "run_success");
|
|
cleanup:
|
|
file_reader__destroy(skel);
|
|
}
|
|
|
|
void test_file_reader(void)
|
|
{
|
|
if (test__start_subtest("on_open_expect_fault"))
|
|
run_test("on_open_expect_fault");
|
|
|
|
if (test__start_subtest("on_open_validate_file_read"))
|
|
run_test("on_open_validate_file_read");
|
|
|
|
if (test__start_subtest("negative"))
|
|
RUN_TESTS(file_reader_fail);
|
|
}
|