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 
15 /* This test crafts a race between btf_try_get_module and do_init_module, and
16  * checks whether btf_try_get_module handles the invocation for a well-formed
17  * but uninitialized module correctly. Unless the module has completed its
18  * initcalls, the verifier should fail the program load and return ENXIO.
19  *
20  * userfaultfd is used to trigger a fault in an fmod_ret program, and make it
21  * sleep, then the BPF program is loaded and the return value from verifier is
22  * inspected. After this, the userfaultfd is closed so that the module loading
23  * thread makes forward progress, and fmod_ret injects an error so that the
24  * module load fails and it is freed.
25  *
26  * If the verifier succeeded in loading the supplied program, it will end up
27  * taking reference to freed module, and trigger a crash when the program fd
28  * is closed later. This is true for both kfuncs and ksyms. In both cases,
29  * the crash is triggered inside bpf_prog_free_deferred, when module reference
30  * is finally released.
31  */
32 
33 struct test_config {
34 	const char *str_open;
35 	void *(*bpf_open_and_load)();
36 	void (*bpf_destroy)(void *);
37 };
38 
39 enum bpf_test_state {
40 	_TS_INVALID,
41 	TS_MODULE_LOAD,
42 	TS_MODULE_LOAD_FAIL,
43 };
44 
45 static _Atomic enum bpf_test_state state = _TS_INVALID;
46 
sys_finit_module(int fd,const char * param_values,int flags)47 static int sys_finit_module(int fd, const char *param_values, int flags)
48 {
49 	return syscall(__NR_finit_module, fd, param_values, flags);
50 }
51 
sys_delete_module(const char * name,unsigned int flags)52 static int sys_delete_module(const char *name, unsigned int flags)
53 {
54 	return syscall(__NR_delete_module, name, flags);
55 }
56 
load_module(const char * mod)57 static int load_module(const char *mod)
58 {
59 	int ret, fd;
60 
61 	fd = open("bpf_testmod.ko", O_RDONLY);
62 	if (fd < 0)
63 		return fd;
64 
65 	ret = sys_finit_module(fd, "", 0);
66 	close(fd);
67 	if (ret < 0)
68 		return ret;
69 	return 0;
70 }
71 
load_module_thread(void * p)72 static void *load_module_thread(void *p)
73 {
74 
75 	if (!ASSERT_NEQ(load_module("bpf_testmod.ko"), 0, "load_module_thread must fail"))
76 		atomic_store(&state, TS_MODULE_LOAD);
77 	else
78 		atomic_store(&state, TS_MODULE_LOAD_FAIL);
79 	return p;
80 }
81 
sys_userfaultfd(int flags)82 static int sys_userfaultfd(int flags)
83 {
84 	return syscall(__NR_userfaultfd, flags);
85 }
86 
test_setup_uffd(void * fault_addr)87 static int test_setup_uffd(void *fault_addr)
88 {
89 	struct uffdio_register uffd_register = {};
90 	struct uffdio_api uffd_api = {};
91 	int uffd;
92 
93 	uffd = sys_userfaultfd(O_CLOEXEC);
94 	if (uffd < 0)
95 		return -errno;
96 
97 	uffd_api.api = UFFD_API;
98 	uffd_api.features = 0;
99 	if (ioctl(uffd, UFFDIO_API, &uffd_api)) {
100 		close(uffd);
101 		return -1;
102 	}
103 
104 	uffd_register.range.start = (unsigned long)fault_addr;
105 	uffd_register.range.len = 4096;
106 	uffd_register.mode = UFFDIO_REGISTER_MODE_MISSING;
107 	if (ioctl(uffd, UFFDIO_REGISTER, &uffd_register)) {
108 		close(uffd);
109 		return -1;
110 	}
111 	return uffd;
112 }
113 
test_bpf_mod_race_config(const struct test_config * config)114 static void test_bpf_mod_race_config(const struct test_config *config)
115 {
116 	void *fault_addr, *skel_fail;
117 	struct bpf_mod_race *skel;
118 	struct uffd_msg uffd_msg;
119 	pthread_t load_mod_thrd;
120 	_Atomic int *blockingp;
121 	int uffd, ret;
122 
123 	fault_addr = mmap(0, 4096, PROT_READ, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
124 	if (!ASSERT_NEQ(fault_addr, MAP_FAILED, "mmap for uffd registration"))
125 		return;
126 
127 	if (!ASSERT_OK(sys_delete_module("bpf_testmod", 0), "unload bpf_testmod"))
128 		goto end_mmap;
129 
130 	skel = bpf_mod_race__open();
131 	if (!ASSERT_OK_PTR(skel, "bpf_mod_kfunc_race__open"))
132 		goto end_module;
133 
134 	skel->rodata->bpf_mod_race_config.tgid = getpid();
135 	skel->rodata->bpf_mod_race_config.inject_error = -4242;
136 	skel->rodata->bpf_mod_race_config.fault_addr = fault_addr;
137 	if (!ASSERT_OK(bpf_mod_race__load(skel), "bpf_mod___load"))
138 		goto end_destroy;
139 	blockingp = (_Atomic int *)&skel->bss->bpf_blocking;
140 
141 	if (!ASSERT_OK(bpf_mod_race__attach(skel), "bpf_mod_kfunc_race__attach"))
142 		goto end_destroy;
143 
144 	uffd = test_setup_uffd(fault_addr);
145 	if (!ASSERT_GE(uffd, 0, "userfaultfd open + register address"))
146 		goto end_destroy;
147 
148 	if (!ASSERT_OK(pthread_create(&load_mod_thrd, NULL, load_module_thread, NULL),
149 		       "load module thread"))
150 		goto end_uffd;
151 
152 	/* Now, we either fail loading module, or block in bpf prog, spin to find out */
153 	while (!atomic_load(&state) && !atomic_load(blockingp))
154 		;
155 	if (!ASSERT_EQ(state, _TS_INVALID, "module load should block"))
156 		goto end_join;
157 	if (!ASSERT_EQ(*blockingp, 1, "module load blocked")) {
158 		pthread_kill(load_mod_thrd, SIGKILL);
159 		goto end_uffd;
160 	}
161 
162 	/* We might have set bpf_blocking to 1, but may have not blocked in
163 	 * bpf_copy_from_user. Read userfaultfd descriptor to verify that.
164 	 */
165 	if (!ASSERT_EQ(read(uffd, &uffd_msg, sizeof(uffd_msg)), sizeof(uffd_msg),
166 		       "read uffd block event"))
167 		goto end_join;
168 	if (!ASSERT_EQ(uffd_msg.event, UFFD_EVENT_PAGEFAULT, "read uffd event is pagefault"))
169 		goto end_join;
170 
171 	/* We know that load_mod_thrd is blocked in the fmod_ret program, the
172 	 * module state is still MODULE_STATE_COMING because mod->init hasn't
173 	 * returned. This is the time we try to load a program calling kfunc and
174 	 * check if we get ENXIO from verifier.
175 	 */
176 	skel_fail = config->bpf_open_and_load();
177 	ret = errno;
178 	if (!ASSERT_EQ(skel_fail, NULL, config->str_open)) {
179 		/* Close uffd to unblock load_mod_thrd */
180 		close(uffd);
181 		uffd = -1;
182 		while (atomic_load(blockingp) != 2)
183 			;
184 		ASSERT_OK(kern_sync_rcu(), "kern_sync_rcu");
185 		config->bpf_destroy(skel_fail);
186 		goto end_join;
187 
188 	}
189 	ASSERT_EQ(ret, ENXIO, "verifier returns ENXIO");
190 	ASSERT_EQ(skel->data->res_try_get_module, false, "btf_try_get_module == false");
191 
192 	close(uffd);
193 	uffd = -1;
194 end_join:
195 	pthread_join(load_mod_thrd, NULL);
196 	if (uffd < 0)
197 		ASSERT_EQ(atomic_load(&state), TS_MODULE_LOAD_FAIL, "load_mod_thrd success");
198 end_uffd:
199 	if (uffd >= 0)
200 		close(uffd);
201 end_destroy:
202 	bpf_mod_race__destroy(skel);
203 	ASSERT_OK(kern_sync_rcu(), "kern_sync_rcu");
204 end_module:
205 	sys_delete_module("bpf_testmod", 0);
206 	ASSERT_OK(load_module("bpf_testmod.ko"), "restore bpf_testmod");
207 end_mmap:
208 	munmap(fault_addr, 4096);
209 	atomic_store(&state, _TS_INVALID);
210 }
211 
212 static const struct test_config ksym_config = {
213 	.str_open = "ksym_race__open_and_load",
214 	.bpf_open_and_load = (void *)ksym_race__open_and_load,
215 	.bpf_destroy = (void *)ksym_race__destroy,
216 };
217 
218 static const struct test_config kfunc_config = {
219 	.str_open = "kfunc_call_race__open_and_load",
220 	.bpf_open_and_load = (void *)kfunc_call_race__open_and_load,
221 	.bpf_destroy = (void *)kfunc_call_race__destroy,
222 };
223 
serial_test_bpf_mod_race(void)224 void serial_test_bpf_mod_race(void)
225 {
226 	if (test__start_subtest("ksym (used_btfs UAF)"))
227 		test_bpf_mod_race_config(&ksym_config);
228 	if (test__start_subtest("kfunc (kfunc_btf_tab UAF)"))
229 		test_bpf_mod_race_config(&kfunc_config);
230 }
231