xref: /linux/tools/testing/selftests/bpf/prog_tests/bpf_mod_race.c (revision d5288c519bbd0df9dff9f8dce2a8ce24e2ca9c8a)
1 // SPDX-License-Identifier: GPL-2.0
2 #include <unistd.h>
3 #include <pthread.h>
4 #include <sys/mman.h>
5 #include <stdatomic.h>
6 #include <test_progs.h>
7 #include <sys/syscall.h>
8 #include <linux/module.h>
9 #include <linux/userfaultfd.h>
10 
11 #include "ksym_race.skel.h"
12 #include "bpf_mod_race.skel.h"
13 #include "kfunc_call_race.skel.h"
14 #include "testing_helpers.h"
15 
16 /* This test crafts a race between btf_try_get_module and do_init_module, and
17  * checks whether btf_try_get_module handles the invocation for a well-formed
18  * but uninitialized module correctly. Unless the module has completed its
19  * initcalls, the verifier should fail the program load and return ENXIO.
20  *
21  * userfaultfd is used to trigger a fault in an fmod_ret program, and make it
22  * sleep, then the BPF program is loaded and the return value from verifier is
23  * inspected. After this, the userfaultfd is closed so that the module loading
24  * thread makes forward progress, and fmod_ret injects an error so that the
25  * module load fails and it is freed.
26  *
27  * If the verifier succeeded in loading the supplied program, it will end up
28  * taking reference to freed module, and trigger a crash when the program fd
29  * is closed later. This is true for both kfuncs and ksyms. In both cases,
30  * the crash is triggered inside bpf_prog_free_deferred, when module reference
31  * is finally released.
32  */
33 
34 struct test_config {
35 	const char *str_open;
36 	void *(*bpf_open_and_load)();
37 	void (*bpf_destroy)(void *);
38 };
39 
40 enum bpf_test_state {
41 	_TS_INVALID,
42 	TS_MODULE_LOAD,
43 	TS_MODULE_LOAD_FAIL,
44 };
45 
46 static _Atomic enum bpf_test_state state = _TS_INVALID;
47 
48 static void *load_module_thread(void *p)
49 {
50 
51 	if (!ASSERT_NEQ(load_bpf_testmod(false), 0, "load_module_thread must fail"))
52 		atomic_store(&state, TS_MODULE_LOAD);
53 	else
54 		atomic_store(&state, TS_MODULE_LOAD_FAIL);
55 	return p;
56 }
57 
58 static void test_bpf_mod_race_config(const struct test_config *config)
59 {
60 	void *fault_addr, *skel_fail;
61 	struct bpf_mod_race *skel;
62 	struct uffd_msg uffd_msg;
63 	pthread_t load_mod_thrd;
64 	_Atomic int *blockingp;
65 	int uffd, ret;
66 
67 	fault_addr = mmap(0, 4096, PROT_READ, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
68 	if (!ASSERT_NEQ(fault_addr, MAP_FAILED, "mmap for uffd registration"))
69 		return;
70 
71 	if (!ASSERT_OK(unload_bpf_testmod(false), "unload bpf_testmod"))
72 		goto end_mmap;
73 
74 	skel = bpf_mod_race__open();
75 	if (!ASSERT_OK_PTR(skel, "bpf_mod_kfunc_race__open"))
76 		goto end_module;
77 
78 	skel->rodata->bpf_mod_race_config.tgid = getpid();
79 	skel->rodata->bpf_mod_race_config.inject_error = -4242;
80 	skel->rodata->bpf_mod_race_config.fault_addr = fault_addr;
81 	if (!ASSERT_OK(bpf_mod_race__load(skel), "bpf_mod___load"))
82 		goto end_destroy;
83 	blockingp = (_Atomic int *)&skel->bss->bpf_blocking;
84 
85 	if (!ASSERT_OK(bpf_mod_race__attach(skel), "bpf_mod_kfunc_race__attach"))
86 		goto end_destroy;
87 
88 	uffd = uffd_block_page(fault_addr);
89 	if (!ASSERT_GE(uffd, 0, "userfaultfd open + register address"))
90 		goto end_destroy;
91 
92 	if (!ASSERT_OK(pthread_create(&load_mod_thrd, NULL, load_module_thread, NULL),
93 		       "load module thread"))
94 		goto end_uffd;
95 
96 	/* Now, we either fail loading module, or block in bpf prog, spin to find out */
97 	while (!atomic_load(&state) && !atomic_load(blockingp))
98 		;
99 	if (!ASSERT_EQ(state, _TS_INVALID, "module load should block"))
100 		goto end_join;
101 	if (!ASSERT_EQ(*blockingp, 1, "module load blocked")) {
102 		pthread_kill(load_mod_thrd, SIGKILL);
103 		goto end_uffd;
104 	}
105 
106 	/* We might have set bpf_blocking to 1, but may have not blocked in
107 	 * bpf_copy_from_user. Read userfaultfd descriptor to verify that.
108 	 */
109 	if (!ASSERT_EQ(read(uffd, &uffd_msg, sizeof(uffd_msg)), sizeof(uffd_msg),
110 		       "read uffd block event"))
111 		goto end_join;
112 	if (!ASSERT_EQ(uffd_msg.event, UFFD_EVENT_PAGEFAULT, "read uffd event is pagefault"))
113 		goto end_join;
114 
115 	/* We know that load_mod_thrd is blocked in the fmod_ret program, the
116 	 * module state is still MODULE_STATE_COMING because mod->init hasn't
117 	 * returned. This is the time we try to load a program calling kfunc and
118 	 * check if we get ENXIO from verifier.
119 	 */
120 	skel_fail = config->bpf_open_and_load();
121 	ret = errno;
122 	if (!ASSERT_EQ(skel_fail, NULL, config->str_open)) {
123 		/* Close uffd to unblock load_mod_thrd */
124 		close(uffd);
125 		uffd = -1;
126 		while (atomic_load(blockingp) != 2)
127 			;
128 		ASSERT_OK(kern_sync_rcu(), "kern_sync_rcu");
129 		config->bpf_destroy(skel_fail);
130 		goto end_join;
131 
132 	}
133 	ASSERT_EQ(ret, ENXIO, "verifier returns ENXIO");
134 	ASSERT_EQ(skel->data->res_try_get_module, false, "btf_try_get_module == false");
135 
136 	close(uffd);
137 	uffd = -1;
138 end_join:
139 	pthread_join(load_mod_thrd, NULL);
140 	if (uffd < 0)
141 		ASSERT_EQ(atomic_load(&state), TS_MODULE_LOAD_FAIL, "load_mod_thrd success");
142 end_uffd:
143 	if (uffd >= 0)
144 		close(uffd);
145 end_destroy:
146 	bpf_mod_race__destroy(skel);
147 	ASSERT_OK(kern_sync_rcu(), "kern_sync_rcu");
148 end_module:
149 	unload_bpf_testmod(false);
150 	ASSERT_OK(load_bpf_testmod(false), "restore bpf_testmod");
151 end_mmap:
152 	munmap(fault_addr, 4096);
153 	atomic_store(&state, _TS_INVALID);
154 }
155 
156 static const struct test_config ksym_config = {
157 	.str_open = "ksym_race__open_and_load",
158 	.bpf_open_and_load = (void *)ksym_race__open_and_load,
159 	.bpf_destroy = (void *)ksym_race__destroy,
160 };
161 
162 static const struct test_config kfunc_config = {
163 	.str_open = "kfunc_call_race__open_and_load",
164 	.bpf_open_and_load = (void *)kfunc_call_race__open_and_load,
165 	.bpf_destroy = (void *)kfunc_call_race__destroy,
166 };
167 
168 void serial_test_bpf_mod_race(void)
169 {
170 	if (test__start_subtest("ksym (used_btfs UAF)"))
171 		test_bpf_mod_race_config(&ksym_config);
172 	if (test__start_subtest("kfunc (kfunc_btf_tab UAF)"))
173 		test_bpf_mod_race_config(&kfunc_config);
174 }
175