xref: /linux/tools/testing/selftests/bpf/prog_tests/file_reader.c (revision 24f171c7e145f43b9f187578e89b0982ce87e54c)
1784cdf93SMykyta Yatsenko // SPDX-License-Identifier: GPL-2.0
2784cdf93SMykyta Yatsenko /* Copyright (c) 2025 Meta Platforms, Inc. and affiliates. */
3784cdf93SMykyta Yatsenko 
4784cdf93SMykyta Yatsenko #include <test_progs.h>
5784cdf93SMykyta Yatsenko #include <network_helpers.h>
6784cdf93SMykyta Yatsenko #include "file_reader.skel.h"
7784cdf93SMykyta Yatsenko #include "file_reader_fail.skel.h"
8784cdf93SMykyta Yatsenko #include <dlfcn.h>
9784cdf93SMykyta Yatsenko #include <sys/mman.h>
10784cdf93SMykyta Yatsenko 
11784cdf93SMykyta Yatsenko const char *user_ptr = "hello world";
12784cdf93SMykyta Yatsenko char file_contents[256000];
13784cdf93SMykyta Yatsenko 
14784cdf93SMykyta Yatsenko void *get_executable_base_addr(void)
15784cdf93SMykyta Yatsenko {
16784cdf93SMykyta Yatsenko 	Dl_info info;
17784cdf93SMykyta Yatsenko 
18784cdf93SMykyta Yatsenko 	if (!dladdr((void *)&get_executable_base_addr, &info)) {
19784cdf93SMykyta Yatsenko 		fprintf(stderr, "dladdr failed\n");
20784cdf93SMykyta Yatsenko 		return NULL;
21784cdf93SMykyta Yatsenko 	}
22784cdf93SMykyta Yatsenko 
23784cdf93SMykyta Yatsenko 	return info.dli_fbase;
24784cdf93SMykyta Yatsenko }
25784cdf93SMykyta Yatsenko 
26784cdf93SMykyta Yatsenko static int initialize_file_contents(void)
27784cdf93SMykyta Yatsenko {
28784cdf93SMykyta Yatsenko 	int fd, page_sz = sysconf(_SC_PAGESIZE);
29784cdf93SMykyta Yatsenko 	ssize_t n = 0, cur, off;
30784cdf93SMykyta Yatsenko 	void *addr;
31784cdf93SMykyta Yatsenko 
32784cdf93SMykyta Yatsenko 	fd = open("/proc/self/exe", O_RDONLY);
33784cdf93SMykyta Yatsenko 	if (!ASSERT_OK_FD(fd, "Open /proc/self/exe\n"))
34784cdf93SMykyta Yatsenko 		return 1;
35784cdf93SMykyta Yatsenko 
36784cdf93SMykyta Yatsenko 	do {
37784cdf93SMykyta Yatsenko 		cur = read(fd, file_contents + n, sizeof(file_contents) - n);
38784cdf93SMykyta Yatsenko 		if (!ASSERT_GT(cur, 0, "read success"))
39784cdf93SMykyta Yatsenko 			break;
40784cdf93SMykyta Yatsenko 		n += cur;
41784cdf93SMykyta Yatsenko 	} while (n < sizeof(file_contents));
42784cdf93SMykyta Yatsenko 
43784cdf93SMykyta Yatsenko 	close(fd);
44784cdf93SMykyta Yatsenko 
45784cdf93SMykyta Yatsenko 	if (!ASSERT_EQ(n, sizeof(file_contents), "Read /proc/self/exe\n"))
46784cdf93SMykyta Yatsenko 		return 1;
47784cdf93SMykyta Yatsenko 
48784cdf93SMykyta Yatsenko 	addr = get_executable_base_addr();
49784cdf93SMykyta Yatsenko 	if (!ASSERT_NEQ(addr, NULL, "get executable address"))
50784cdf93SMykyta Yatsenko 		return 1;
51784cdf93SMykyta Yatsenko 
52784cdf93SMykyta Yatsenko 	/* page-align base file address */
53784cdf93SMykyta Yatsenko 	addr = (void *)((unsigned long)addr & ~(page_sz - 1));
54784cdf93SMykyta Yatsenko 
55*5913e936SMykyta Yatsenko 	/*
56*5913e936SMykyta Yatsenko 	 * Page out range 0..512K, use 0..256K for positive tests and
57*5913e936SMykyta Yatsenko 	 * 256K..512K for negative tests expecting page faults
58*5913e936SMykyta Yatsenko 	 */
59*5913e936SMykyta Yatsenko 	for (off = 0; off < sizeof(file_contents) * 2; off += page_sz) {
60784cdf93SMykyta Yatsenko 		if (!ASSERT_OK(madvise(addr + off, page_sz, MADV_PAGEOUT),
61784cdf93SMykyta Yatsenko 			       "madvise pageout"))
62784cdf93SMykyta Yatsenko 			return errno;
63784cdf93SMykyta Yatsenko 	}
64784cdf93SMykyta Yatsenko 
65784cdf93SMykyta Yatsenko 	return 0;
66784cdf93SMykyta Yatsenko }
67784cdf93SMykyta Yatsenko 
68784cdf93SMykyta Yatsenko static void run_test(const char *prog_name)
69784cdf93SMykyta Yatsenko {
70784cdf93SMykyta Yatsenko 	struct file_reader *skel;
71784cdf93SMykyta Yatsenko 	struct bpf_program *prog;
72784cdf93SMykyta Yatsenko 	int err, fd;
73784cdf93SMykyta Yatsenko 
74784cdf93SMykyta Yatsenko 	err = initialize_file_contents();
75784cdf93SMykyta Yatsenko 	if (!ASSERT_OK(err, "initialize file contents"))
76784cdf93SMykyta Yatsenko 		return;
77784cdf93SMykyta Yatsenko 
78784cdf93SMykyta Yatsenko 	skel = file_reader__open();
79784cdf93SMykyta Yatsenko 	if (!ASSERT_OK_PTR(skel, "file_reader__open"))
80784cdf93SMykyta Yatsenko 		return;
81784cdf93SMykyta Yatsenko 
82784cdf93SMykyta Yatsenko 	bpf_object__for_each_program(prog, skel->obj) {
83784cdf93SMykyta Yatsenko 		bpf_program__set_autoload(prog, strcmp(bpf_program__name(prog), prog_name) == 0);
84784cdf93SMykyta Yatsenko 	}
85784cdf93SMykyta Yatsenko 
86784cdf93SMykyta Yatsenko 	memcpy(skel->bss->user_buf, file_contents, sizeof(file_contents));
87784cdf93SMykyta Yatsenko 	skel->bss->pid = getpid();
88784cdf93SMykyta Yatsenko 
89784cdf93SMykyta Yatsenko 	err = file_reader__load(skel);
90784cdf93SMykyta Yatsenko 	if (!ASSERT_OK(err, "file_reader__load"))
91784cdf93SMykyta Yatsenko 		goto cleanup;
92784cdf93SMykyta Yatsenko 
93784cdf93SMykyta Yatsenko 	err = file_reader__attach(skel);
94784cdf93SMykyta Yatsenko 	if (!ASSERT_OK(err, "file_reader__attach"))
95784cdf93SMykyta Yatsenko 		goto cleanup;
96784cdf93SMykyta Yatsenko 
97784cdf93SMykyta Yatsenko 	fd = open("/proc/self/exe", O_RDONLY);
98784cdf93SMykyta Yatsenko 	if (fd >= 0)
99784cdf93SMykyta Yatsenko 		close(fd);
100784cdf93SMykyta Yatsenko 
101784cdf93SMykyta Yatsenko 	ASSERT_EQ(skel->bss->err, 0, "err");
102784cdf93SMykyta Yatsenko 	ASSERT_EQ(skel->bss->run_success, 1, "run_success");
103784cdf93SMykyta Yatsenko cleanup:
104784cdf93SMykyta Yatsenko 	file_reader__destroy(skel);
105784cdf93SMykyta Yatsenko }
106784cdf93SMykyta Yatsenko 
107784cdf93SMykyta Yatsenko void test_file_reader(void)
108784cdf93SMykyta Yatsenko {
109784cdf93SMykyta Yatsenko 	if (test__start_subtest("on_open_expect_fault"))
110784cdf93SMykyta Yatsenko 		run_test("on_open_expect_fault");
111784cdf93SMykyta Yatsenko 
112784cdf93SMykyta Yatsenko 	if (test__start_subtest("on_open_validate_file_read"))
113784cdf93SMykyta Yatsenko 		run_test("on_open_validate_file_read");
114784cdf93SMykyta Yatsenko 
115784cdf93SMykyta Yatsenko 	if (test__start_subtest("negative"))
116784cdf93SMykyta Yatsenko 		RUN_TESTS(file_reader_fail);
117784cdf93SMykyta Yatsenko }
118