1 // SPDX-License-Identifier: GPL-2.0
2 
3 /*
4  * Copyright (C) 2022 Huawei Technologies Duesseldorf GmbH
5  *
6  * Author: Roberto Sassu <roberto.sassu@huawei.com>
7  */
8 
9 #include <stdio.h>
10 #include <errno.h>
11 #include <stdlib.h>
12 #include <unistd.h>
13 #include <endian.h>
14 #include <limits.h>
15 #include <sys/stat.h>
16 #include <sys/wait.h>
17 #include <sys/mman.h>
18 #include <linux/keyctl.h>
19 #include <test_progs.h>
20 
21 #include "test_verify_pkcs7_sig.skel.h"
22 
23 #define MAX_DATA_SIZE (1024 * 1024)
24 #define MAX_SIG_SIZE 1024
25 
26 #define VERIFY_USE_SECONDARY_KEYRING (1UL)
27 #define VERIFY_USE_PLATFORM_KEYRING  (2UL)
28 
29 /* In stripped ARM and x86-64 modules, ~ is surprisingly rare. */
30 #define MODULE_SIG_STRING "~Module signature appended~\n"
31 
32 /*
33  * Module signature information block.
34  *
35  * The constituents of the signature section are, in order:
36  *
37  *	- Signer's name
38  *	- Key identifier
39  *	- Signature data
40  *	- Information block
41  */
42 struct module_signature {
43 	__u8	algo;		/* Public-key crypto algorithm [0] */
44 	__u8	hash;		/* Digest algorithm [0] */
45 	__u8	id_type;	/* Key identifier type [PKEY_ID_PKCS7] */
46 	__u8	signer_len;	/* Length of signer's name [0] */
47 	__u8	key_id_len;	/* Length of key identifier [0] */
48 	__u8	__pad[3];
49 	__be32	sig_len;	/* Length of signature data */
50 };
51 
52 struct data {
53 	__u8 data[MAX_DATA_SIZE];
54 	__u32 data_len;
55 	__u8 sig[MAX_SIG_SIZE];
56 	__u32 sig_len;
57 };
58 
59 static bool kfunc_not_supported;
60 
libbpf_print_cb(enum libbpf_print_level level,const char * fmt,va_list args)61 static int libbpf_print_cb(enum libbpf_print_level level, const char *fmt,
62 			   va_list args)
63 {
64 	if (level == LIBBPF_WARN)
65 		vprintf(fmt, args);
66 
67 	if (strcmp(fmt, "libbpf: extern (func ksym) '%s': not found in kernel or module BTFs\n"))
68 		return 0;
69 
70 	if (strcmp(va_arg(args, char *), "bpf_verify_pkcs7_signature"))
71 		return 0;
72 
73 	kfunc_not_supported = true;
74 	return 0;
75 }
76 
_run_setup_process(const char * setup_dir,const char * cmd)77 static int _run_setup_process(const char *setup_dir, const char *cmd)
78 {
79 	int child_pid, child_status;
80 
81 	child_pid = fork();
82 	if (child_pid == 0) {
83 		execlp("./verify_sig_setup.sh", "./verify_sig_setup.sh", cmd,
84 		       setup_dir, NULL);
85 		exit(errno);
86 
87 	} else if (child_pid > 0) {
88 		waitpid(child_pid, &child_status, 0);
89 		return WEXITSTATUS(child_status);
90 	}
91 
92 	return -EINVAL;
93 }
94 
populate_data_item_str(const char * tmp_dir,struct data * data_item)95 static int populate_data_item_str(const char *tmp_dir, struct data *data_item)
96 {
97 	struct stat st;
98 	char data_template[] = "/tmp/dataXXXXXX";
99 	char path[PATH_MAX];
100 	int ret, fd, child_status, child_pid;
101 
102 	data_item->data_len = 4;
103 	memcpy(data_item->data, "test", data_item->data_len);
104 
105 	fd = mkstemp(data_template);
106 	if (fd == -1)
107 		return -errno;
108 
109 	ret = write(fd, data_item->data, data_item->data_len);
110 
111 	close(fd);
112 
113 	if (ret != data_item->data_len) {
114 		ret = -EIO;
115 		goto out;
116 	}
117 
118 	child_pid = fork();
119 
120 	if (child_pid == -1) {
121 		ret = -errno;
122 		goto out;
123 	}
124 
125 	if (child_pid == 0) {
126 		snprintf(path, sizeof(path), "%s/signing_key.pem", tmp_dir);
127 
128 		return execlp("./sign-file", "./sign-file", "-d", "sha256",
129 			      path, path, data_template, NULL);
130 	}
131 
132 	waitpid(child_pid, &child_status, 0);
133 
134 	ret = WEXITSTATUS(child_status);
135 	if (ret)
136 		goto out;
137 
138 	snprintf(path, sizeof(path), "%s.p7s", data_template);
139 
140 	ret = stat(path, &st);
141 	if (ret == -1) {
142 		ret = -errno;
143 		goto out;
144 	}
145 
146 	if (st.st_size > sizeof(data_item->sig)) {
147 		ret = -EINVAL;
148 		goto out_sig;
149 	}
150 
151 	data_item->sig_len = st.st_size;
152 
153 	fd = open(path, O_RDONLY);
154 	if (fd == -1) {
155 		ret = -errno;
156 		goto out_sig;
157 	}
158 
159 	ret = read(fd, data_item->sig, data_item->sig_len);
160 
161 	close(fd);
162 
163 	if (ret != data_item->sig_len) {
164 		ret = -EIO;
165 		goto out_sig;
166 	}
167 
168 	ret = 0;
169 out_sig:
170 	unlink(path);
171 out:
172 	unlink(data_template);
173 	return ret;
174 }
175 
populate_data_item_mod(struct data * data_item)176 static int populate_data_item_mod(struct data *data_item)
177 {
178 	char mod_path[PATH_MAX], *mod_path_ptr;
179 	struct stat st;
180 	void *mod;
181 	FILE *fp;
182 	struct module_signature ms;
183 	int ret, fd, modlen, marker_len, sig_len;
184 
185 	data_item->data_len = 0;
186 
187 	if (stat("/lib/modules", &st) == -1)
188 		return 0;
189 
190 	/* Requires CONFIG_TCP_CONG_BIC=m. */
191 	fp = popen("find /lib/modules/$(uname -r) -name tcp_bic.ko", "r");
192 	if (!fp)
193 		return 0;
194 
195 	mod_path_ptr = fgets(mod_path, sizeof(mod_path), fp);
196 	pclose(fp);
197 
198 	if (!mod_path_ptr)
199 		return 0;
200 
201 	mod_path_ptr = strchr(mod_path, '\n');
202 	if (!mod_path_ptr)
203 		return 0;
204 
205 	*mod_path_ptr = '\0';
206 
207 	if (stat(mod_path, &st) == -1)
208 		return 0;
209 
210 	modlen = st.st_size;
211 	marker_len = sizeof(MODULE_SIG_STRING) - 1;
212 
213 	fd = open(mod_path, O_RDONLY);
214 	if (fd == -1)
215 		return -errno;
216 
217 	mod = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
218 
219 	close(fd);
220 
221 	if (mod == MAP_FAILED)
222 		return -errno;
223 
224 	if (strncmp(mod + modlen - marker_len, MODULE_SIG_STRING, marker_len)) {
225 		ret = -EINVAL;
226 		goto out;
227 	}
228 
229 	modlen -= marker_len;
230 
231 	memcpy(&ms, mod + (modlen - sizeof(ms)), sizeof(ms));
232 
233 	sig_len = __be32_to_cpu(ms.sig_len);
234 	modlen -= sig_len + sizeof(ms);
235 
236 	if (modlen > sizeof(data_item->data)) {
237 		ret = -E2BIG;
238 		goto out;
239 	}
240 
241 	memcpy(data_item->data, mod, modlen);
242 	data_item->data_len = modlen;
243 
244 	if (sig_len > sizeof(data_item->sig)) {
245 		ret = -E2BIG;
246 		goto out;
247 	}
248 
249 	memcpy(data_item->sig, mod + modlen, sig_len);
250 	data_item->sig_len = sig_len;
251 	ret = 0;
252 out:
253 	munmap(mod, st.st_size);
254 	return ret;
255 }
256 
test_verify_pkcs7_sig(void)257 void test_verify_pkcs7_sig(void)
258 {
259 	libbpf_print_fn_t old_print_cb;
260 	char tmp_dir_template[] = "/tmp/verify_sigXXXXXX";
261 	char *tmp_dir;
262 	struct test_verify_pkcs7_sig *skel = NULL;
263 	struct bpf_map *map;
264 	struct data data;
265 	int ret, zero = 0;
266 
267 	/* Trigger creation of session keyring. */
268 	syscall(__NR_request_key, "keyring", "_uid.0", NULL,
269 		KEY_SPEC_SESSION_KEYRING);
270 
271 	tmp_dir = mkdtemp(tmp_dir_template);
272 	if (!ASSERT_OK_PTR(tmp_dir, "mkdtemp"))
273 		return;
274 
275 	ret = _run_setup_process(tmp_dir, "setup");
276 	if (!ASSERT_OK(ret, "_run_setup_process"))
277 		goto close_prog;
278 
279 	skel = test_verify_pkcs7_sig__open();
280 	if (!ASSERT_OK_PTR(skel, "test_verify_pkcs7_sig__open"))
281 		goto close_prog;
282 
283 	old_print_cb = libbpf_set_print(libbpf_print_cb);
284 	ret = test_verify_pkcs7_sig__load(skel);
285 	libbpf_set_print(old_print_cb);
286 
287 	if (ret < 0 && kfunc_not_supported) {
288 		printf(
289 		  "%s:SKIP:bpf_verify_pkcs7_signature() kfunc not supported\n",
290 		  __func__);
291 		test__skip();
292 		goto close_prog;
293 	}
294 
295 	if (!ASSERT_OK(ret, "test_verify_pkcs7_sig__load"))
296 		goto close_prog;
297 
298 	ret = test_verify_pkcs7_sig__attach(skel);
299 	if (!ASSERT_OK(ret, "test_verify_pkcs7_sig__attach"))
300 		goto close_prog;
301 
302 	map = bpf_object__find_map_by_name(skel->obj, "data_input");
303 	if (!ASSERT_OK_PTR(map, "data_input not found"))
304 		goto close_prog;
305 
306 	skel->bss->monitored_pid = getpid();
307 
308 	/* Test without data and signature. */
309 	skel->bss->user_keyring_serial = KEY_SPEC_SESSION_KEYRING;
310 
311 	ret = bpf_map_update_elem(bpf_map__fd(map), &zero, &data, BPF_ANY);
312 	if (!ASSERT_LT(ret, 0, "bpf_map_update_elem data_input"))
313 		goto close_prog;
314 
315 	/* Test successful signature verification with session keyring. */
316 	ret = populate_data_item_str(tmp_dir, &data);
317 	if (!ASSERT_OK(ret, "populate_data_item_str"))
318 		goto close_prog;
319 
320 	ret = bpf_map_update_elem(bpf_map__fd(map), &zero, &data, BPF_ANY);
321 	if (!ASSERT_OK(ret, "bpf_map_update_elem data_input"))
322 		goto close_prog;
323 
324 	/* Test successful signature verification with testing keyring. */
325 	skel->bss->user_keyring_serial = syscall(__NR_request_key, "keyring",
326 						 "ebpf_testing_keyring", NULL,
327 						 KEY_SPEC_SESSION_KEYRING);
328 
329 	ret = bpf_map_update_elem(bpf_map__fd(map), &zero, &data, BPF_ANY);
330 	if (!ASSERT_OK(ret, "bpf_map_update_elem data_input"))
331 		goto close_prog;
332 
333 	/*
334 	 * Ensure key_task_permission() is called and rejects the keyring
335 	 * (no Search permission).
336 	 */
337 	syscall(__NR_keyctl, KEYCTL_SETPERM, skel->bss->user_keyring_serial,
338 		0x37373737);
339 
340 	ret = bpf_map_update_elem(bpf_map__fd(map), &zero, &data, BPF_ANY);
341 	if (!ASSERT_LT(ret, 0, "bpf_map_update_elem data_input"))
342 		goto close_prog;
343 
344 	syscall(__NR_keyctl, KEYCTL_SETPERM, skel->bss->user_keyring_serial,
345 		0x3f3f3f3f);
346 
347 	/*
348 	 * Ensure key_validate() is called and rejects the keyring (key expired)
349 	 */
350 	syscall(__NR_keyctl, KEYCTL_SET_TIMEOUT,
351 		skel->bss->user_keyring_serial, 1);
352 	sleep(1);
353 
354 	ret = bpf_map_update_elem(bpf_map__fd(map), &zero, &data, BPF_ANY);
355 	if (!ASSERT_LT(ret, 0, "bpf_map_update_elem data_input"))
356 		goto close_prog;
357 
358 	skel->bss->user_keyring_serial = KEY_SPEC_SESSION_KEYRING;
359 
360 	/* Test with corrupted data (signature verification should fail). */
361 	data.data[0] = 'a';
362 	ret = bpf_map_update_elem(bpf_map__fd(map), &zero, &data, BPF_ANY);
363 	if (!ASSERT_LT(ret, 0, "bpf_map_update_elem data_input"))
364 		goto close_prog;
365 
366 	ret = populate_data_item_mod(&data);
367 	if (!ASSERT_OK(ret, "populate_data_item_mod"))
368 		goto close_prog;
369 
370 	/* Test signature verification with system keyrings. */
371 	if (data.data_len) {
372 		skel->bss->user_keyring_serial = 0;
373 		skel->bss->system_keyring_id = 0;
374 
375 		ret = bpf_map_update_elem(bpf_map__fd(map), &zero, &data,
376 					  BPF_ANY);
377 		if (!ASSERT_OK(ret, "bpf_map_update_elem data_input"))
378 			goto close_prog;
379 
380 		skel->bss->system_keyring_id = VERIFY_USE_SECONDARY_KEYRING;
381 
382 		ret = bpf_map_update_elem(bpf_map__fd(map), &zero, &data,
383 					  BPF_ANY);
384 		if (!ASSERT_OK(ret, "bpf_map_update_elem data_input"))
385 			goto close_prog;
386 
387 		skel->bss->system_keyring_id = VERIFY_USE_PLATFORM_KEYRING;
388 
389 		ret = bpf_map_update_elem(bpf_map__fd(map), &zero, &data,
390 					  BPF_ANY);
391 		ASSERT_LT(ret, 0, "bpf_map_update_elem data_input");
392 	}
393 
394 close_prog:
395 	_run_setup_process(tmp_dir, "cleanup");
396 
397 	if (!skel)
398 		return;
399 
400 	skel->bss->monitored_pid = 0;
401 	test_verify_pkcs7_sig__destroy(skel);
402 }
403