xref: /linux/tools/testing/selftests/bpf/prog_tests/verify_pkcs7_sig.c (revision 0fc8f6200d2313278fbf4539bbab74677c685531)
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 <sys/xattr.h>
20 #include <linux/fsverity.h>
21 #include <linux/module_signature.h>
22 #include <test_progs.h>
23 
24 #include "test_verify_pkcs7_sig.skel.h"
25 #include "test_sig_in_xattr.skel.h"
26 
27 #define MAX_DATA_SIZE (1024 * 1024)
28 #define MAX_SIG_SIZE 1024
29 
30 #define VERIFY_USE_SECONDARY_KEYRING (1UL)
31 #define VERIFY_USE_PLATFORM_KEYRING  (2UL)
32 
33 #ifndef SHA256_DIGEST_SIZE
34 #define SHA256_DIGEST_SIZE      32
35 #endif
36 
37 struct data {
38 	__u8 data[MAX_DATA_SIZE];
39 	__u32 data_len;
40 	__u8 sig[MAX_SIG_SIZE];
41 	__u32 sig_len;
42 };
43 
44 static bool kfunc_not_supported;
45 
46 static int libbpf_print_cb(enum libbpf_print_level level, const char *fmt,
47 			   va_list args)
48 {
49 	if (level == LIBBPF_WARN)
50 		vprintf(fmt, args);
51 
52 	if (strcmp(fmt, "libbpf: extern (func ksym) '%s': not found in kernel or module BTFs\n"))
53 		return 0;
54 
55 	if (strcmp(va_arg(args, char *), "bpf_verify_pkcs7_signature"))
56 		return 0;
57 
58 	kfunc_not_supported = true;
59 	return 0;
60 }
61 
62 static int _run_setup_process(const char *setup_dir, const char *cmd)
63 {
64 	int child_pid, child_status;
65 
66 	child_pid = fork();
67 	if (child_pid == 0) {
68 		execlp("./verify_sig_setup.sh", "./verify_sig_setup.sh", cmd,
69 		       setup_dir, NULL);
70 		exit(errno);
71 
72 	} else if (child_pid > 0) {
73 		waitpid(child_pid, &child_status, 0);
74 		return WEXITSTATUS(child_status);
75 	}
76 
77 	return -EINVAL;
78 }
79 
80 static int populate_data_item_str(const char *tmp_dir, struct data *data_item)
81 {
82 	struct stat st;
83 	char data_template[] = "/tmp/dataXXXXXX";
84 	char path[PATH_MAX];
85 	int ret, fd, child_status, child_pid;
86 
87 	data_item->data_len = 4;
88 	memcpy(data_item->data, "test", data_item->data_len);
89 
90 	fd = mkstemp(data_template);
91 	if (fd == -1)
92 		return -errno;
93 
94 	ret = write(fd, data_item->data, data_item->data_len);
95 
96 	close(fd);
97 
98 	if (ret != data_item->data_len) {
99 		ret = -EIO;
100 		goto out;
101 	}
102 
103 	child_pid = fork();
104 
105 	if (child_pid == -1) {
106 		ret = -errno;
107 		goto out;
108 	}
109 
110 	if (child_pid == 0) {
111 		snprintf(path, sizeof(path), "%s/signing_key.pem", tmp_dir);
112 
113 		return execlp("./sign-file", "./sign-file", "-d", "sha256",
114 			      path, path, data_template, NULL);
115 	}
116 
117 	waitpid(child_pid, &child_status, 0);
118 
119 	ret = WEXITSTATUS(child_status);
120 	if (ret)
121 		goto out;
122 
123 	snprintf(path, sizeof(path), "%s.p7s", data_template);
124 
125 	ret = stat(path, &st);
126 	if (ret == -1) {
127 		ret = -errno;
128 		goto out;
129 	}
130 
131 	if (st.st_size > sizeof(data_item->sig)) {
132 		ret = -EINVAL;
133 		goto out_sig;
134 	}
135 
136 	data_item->sig_len = st.st_size;
137 
138 	fd = open(path, O_RDONLY);
139 	if (fd == -1) {
140 		ret = -errno;
141 		goto out_sig;
142 	}
143 
144 	ret = read(fd, data_item->sig, data_item->sig_len);
145 
146 	close(fd);
147 
148 	if (ret != data_item->sig_len) {
149 		ret = -EIO;
150 		goto out_sig;
151 	}
152 
153 	ret = 0;
154 out_sig:
155 	unlink(path);
156 out:
157 	unlink(data_template);
158 	return ret;
159 }
160 
161 static int populate_data_item_mod(struct data *data_item)
162 {
163 	char mod_path[PATH_MAX], *mod_path_ptr;
164 	struct stat st;
165 	void *mod;
166 	FILE *fp;
167 	struct module_signature ms;
168 	int ret, fd, modlen, marker_len, sig_len;
169 
170 	data_item->data_len = 0;
171 
172 	if (stat("/lib/modules", &st) == -1)
173 		return 0;
174 
175 	/* Requires CONFIG_TCP_CONG_BIC=m. */
176 	fp = popen("find /lib/modules/$(uname -r) -name tcp_bic.ko", "r");
177 	if (!fp)
178 		return 0;
179 
180 	mod_path_ptr = fgets(mod_path, sizeof(mod_path), fp);
181 	pclose(fp);
182 
183 	if (!mod_path_ptr)
184 		return 0;
185 
186 	mod_path_ptr = strchr(mod_path, '\n');
187 	if (!mod_path_ptr)
188 		return 0;
189 
190 	*mod_path_ptr = '\0';
191 
192 	if (stat(mod_path, &st) == -1)
193 		return 0;
194 
195 	modlen = st.st_size;
196 	marker_len = sizeof(MODULE_SIGNATURE_MARKER) - 1;
197 
198 	fd = open(mod_path, O_RDONLY);
199 	if (fd == -1)
200 		return -errno;
201 
202 	mod = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
203 
204 	close(fd);
205 
206 	if (mod == MAP_FAILED)
207 		return -errno;
208 
209 	if (strncmp(mod + modlen - marker_len, MODULE_SIGNATURE_MARKER, marker_len)) {
210 		ret = -EINVAL;
211 		goto out;
212 	}
213 
214 	modlen -= marker_len;
215 
216 	memcpy(&ms, mod + (modlen - sizeof(ms)), sizeof(ms));
217 
218 	sig_len = __be32_to_cpu(ms.sig_len);
219 	modlen -= sig_len + sizeof(ms);
220 
221 	if (modlen > sizeof(data_item->data)) {
222 		ret = -E2BIG;
223 		goto out;
224 	}
225 
226 	memcpy(data_item->data, mod, modlen);
227 	data_item->data_len = modlen;
228 
229 	if (sig_len > sizeof(data_item->sig)) {
230 		ret = -E2BIG;
231 		goto out;
232 	}
233 
234 	memcpy(data_item->sig, mod + modlen, sig_len);
235 	data_item->sig_len = sig_len;
236 	ret = 0;
237 out:
238 	munmap(mod, st.st_size);
239 	return ret;
240 }
241 
242 static void test_verify_pkcs7_sig_from_map(void)
243 {
244 	libbpf_print_fn_t old_print_cb;
245 	char tmp_dir_template[] = "/tmp/verify_sigXXXXXX";
246 	char *tmp_dir;
247 	struct test_verify_pkcs7_sig *skel = NULL;
248 	struct bpf_map *map;
249 	struct data data = {};
250 	int ret, zero = 0;
251 
252 	/* Trigger creation of session keyring. */
253 	syscall(__NR_request_key, "keyring", "_uid.0", NULL,
254 		KEY_SPEC_SESSION_KEYRING);
255 
256 	tmp_dir = mkdtemp(tmp_dir_template);
257 	if (!ASSERT_OK_PTR(tmp_dir, "mkdtemp"))
258 		return;
259 
260 	ret = _run_setup_process(tmp_dir, "setup");
261 	if (!ASSERT_OK(ret, "_run_setup_process"))
262 		goto close_prog;
263 
264 	skel = test_verify_pkcs7_sig__open();
265 	if (!ASSERT_OK_PTR(skel, "test_verify_pkcs7_sig__open"))
266 		goto close_prog;
267 
268 	old_print_cb = libbpf_set_print(libbpf_print_cb);
269 	ret = test_verify_pkcs7_sig__load(skel);
270 	libbpf_set_print(old_print_cb);
271 
272 	if (ret < 0 && kfunc_not_supported) {
273 		printf(
274 		  "%s:SKIP:bpf_verify_pkcs7_signature() kfunc not supported\n",
275 		  __func__);
276 		test__skip();
277 		goto close_prog;
278 	}
279 
280 	if (!ASSERT_OK(ret, "test_verify_pkcs7_sig__load"))
281 		goto close_prog;
282 
283 	ret = test_verify_pkcs7_sig__attach(skel);
284 	if (!ASSERT_OK(ret, "test_verify_pkcs7_sig__attach"))
285 		goto close_prog;
286 
287 	map = bpf_object__find_map_by_name(skel->obj, "data_input");
288 	if (!ASSERT_OK_PTR(map, "data_input not found"))
289 		goto close_prog;
290 
291 	skel->bss->monitored_pid = getpid();
292 
293 	/* Test without data and signature. */
294 	skel->bss->user_keyring_serial = KEY_SPEC_SESSION_KEYRING;
295 
296 	ret = bpf_map_update_elem(bpf_map__fd(map), &zero, &data, BPF_ANY);
297 	if (!ASSERT_LT(ret, 0, "bpf_map_update_elem data_input"))
298 		goto close_prog;
299 
300 	/* Test successful signature verification with session keyring. */
301 	ret = populate_data_item_str(tmp_dir, &data);
302 	if (!ASSERT_OK(ret, "populate_data_item_str"))
303 		goto close_prog;
304 
305 	ret = bpf_map_update_elem(bpf_map__fd(map), &zero, &data, BPF_ANY);
306 	if (!ASSERT_OK(ret, "bpf_map_update_elem data_input"))
307 		goto close_prog;
308 
309 	/* Test successful signature verification with testing keyring. */
310 	skel->bss->user_keyring_serial = syscall(__NR_request_key, "keyring",
311 						 "ebpf_testing_keyring", NULL,
312 						 KEY_SPEC_SESSION_KEYRING);
313 
314 	ret = bpf_map_update_elem(bpf_map__fd(map), &zero, &data, BPF_ANY);
315 	if (!ASSERT_OK(ret, "bpf_map_update_elem data_input"))
316 		goto close_prog;
317 
318 	/*
319 	 * Ensure key_task_permission() is called and rejects the keyring
320 	 * (no Search permission).
321 	 */
322 	syscall(__NR_keyctl, KEYCTL_SETPERM, skel->bss->user_keyring_serial,
323 		0x37373737);
324 
325 	ret = bpf_map_update_elem(bpf_map__fd(map), &zero, &data, BPF_ANY);
326 	if (!ASSERT_LT(ret, 0, "bpf_map_update_elem data_input"))
327 		goto close_prog;
328 
329 	syscall(__NR_keyctl, KEYCTL_SETPERM, skel->bss->user_keyring_serial,
330 		0x3f3f3f3f);
331 
332 	/*
333 	 * Ensure key_validate() is called and rejects the keyring (key expired)
334 	 */
335 	syscall(__NR_keyctl, KEYCTL_SET_TIMEOUT,
336 		skel->bss->user_keyring_serial, 1);
337 	sleep(1);
338 
339 	ret = bpf_map_update_elem(bpf_map__fd(map), &zero, &data, BPF_ANY);
340 	if (!ASSERT_LT(ret, 0, "bpf_map_update_elem data_input"))
341 		goto close_prog;
342 
343 	skel->bss->user_keyring_serial = KEY_SPEC_SESSION_KEYRING;
344 
345 	/* Test with corrupted data (signature verification should fail). */
346 	data.data[0] = 'a';
347 	ret = bpf_map_update_elem(bpf_map__fd(map), &zero, &data, BPF_ANY);
348 	if (!ASSERT_LT(ret, 0, "bpf_map_update_elem data_input"))
349 		goto close_prog;
350 
351 	ret = populate_data_item_mod(&data);
352 	if (!ASSERT_OK(ret, "populate_data_item_mod"))
353 		goto close_prog;
354 
355 	/* Test signature verification with system keyrings. */
356 	if (data.data_len) {
357 		skel->bss->user_keyring_serial = 0;
358 		skel->bss->system_keyring_id = 0;
359 
360 		ret = bpf_map_update_elem(bpf_map__fd(map), &zero, &data,
361 					  BPF_ANY);
362 		if (!ASSERT_OK(ret, "bpf_map_update_elem data_input"))
363 			goto close_prog;
364 
365 		skel->bss->system_keyring_id = VERIFY_USE_SECONDARY_KEYRING;
366 
367 		ret = bpf_map_update_elem(bpf_map__fd(map), &zero, &data,
368 					  BPF_ANY);
369 		if (!ASSERT_OK(ret, "bpf_map_update_elem data_input"))
370 			goto close_prog;
371 
372 		skel->bss->system_keyring_id = VERIFY_USE_PLATFORM_KEYRING;
373 
374 		ret = bpf_map_update_elem(bpf_map__fd(map), &zero, &data,
375 					  BPF_ANY);
376 		ASSERT_LT(ret, 0, "bpf_map_update_elem data_input");
377 	}
378 
379 close_prog:
380 	_run_setup_process(tmp_dir, "cleanup");
381 
382 	if (!skel)
383 		return;
384 
385 	skel->bss->monitored_pid = 0;
386 	test_verify_pkcs7_sig__destroy(skel);
387 }
388 
389 static int get_signature_size(const char *sig_path)
390 {
391 	struct stat st;
392 
393 	if (stat(sig_path, &st) == -1)
394 		return -1;
395 
396 	return st.st_size;
397 }
398 
399 static int add_signature_to_xattr(const char *data_path, const char *sig_path)
400 {
401 	char sig[MAX_SIG_SIZE] = {0};
402 	int fd, size, ret;
403 
404 	if (sig_path) {
405 		fd = open(sig_path, O_RDONLY);
406 		if (fd < 0)
407 			return -1;
408 
409 		size = read(fd, sig, MAX_SIG_SIZE);
410 		close(fd);
411 		if (size <= 0)
412 			return -1;
413 	} else {
414 		/* no sig_path, just write 32 bytes of zeros */
415 		size = 32;
416 	}
417 	ret = setxattr(data_path, "user.sig", sig, size, 0);
418 	if (!ASSERT_OK(ret, "setxattr"))
419 		return -1;
420 
421 	return 0;
422 }
423 
424 static int test_open_file(struct test_sig_in_xattr *skel, char *data_path,
425 			  pid_t pid, bool should_success, char *name)
426 {
427 	int ret;
428 
429 	skel->bss->monitored_pid = pid;
430 	ret = open(data_path, O_RDONLY);
431 	close(ret);
432 	skel->bss->monitored_pid = 0;
433 
434 	if (should_success) {
435 		if (!ASSERT_GE(ret, 0, name))
436 			return -1;
437 	} else {
438 		if (!ASSERT_LT(ret, 0, name))
439 			return -1;
440 	}
441 	return 0;
442 }
443 
444 static void test_pkcs7_sig_fsverity(void)
445 {
446 	char data_path[PATH_MAX];
447 	char sig_path[PATH_MAX];
448 	char tmp_dir_template[] = "/tmp/verify_sigXXXXXX";
449 	char *tmp_dir;
450 	struct test_sig_in_xattr *skel = NULL;
451 	pid_t pid;
452 	int ret;
453 
454 	tmp_dir = mkdtemp(tmp_dir_template);
455 	if (!ASSERT_OK_PTR(tmp_dir, "mkdtemp"))
456 		return;
457 
458 	snprintf(data_path, PATH_MAX, "%s/data-file", tmp_dir);
459 	snprintf(sig_path, PATH_MAX, "%s/sig-file", tmp_dir);
460 
461 	ret = _run_setup_process(tmp_dir, "setup");
462 	if (!ASSERT_OK(ret, "_run_setup_process"))
463 		goto out;
464 
465 	ret = _run_setup_process(tmp_dir, "fsverity-create-sign");
466 
467 	if (ret) {
468 		printf("%s: SKIP: fsverity [sign|enable] doesn't work.\n"
469 		       "To run this test, try enable CONFIG_FS_VERITY and enable FSVerity for the filesystem.\n",
470 		       __func__);
471 		test__skip();
472 		goto out;
473 	}
474 
475 	skel = test_sig_in_xattr__open();
476 	if (!ASSERT_OK_PTR(skel, "test_sig_in_xattr__open"))
477 		goto out;
478 	ret = get_signature_size(sig_path);
479 	if (!ASSERT_GT(ret, 0, "get_signature_size"))
480 		goto out;
481 	skel->bss->sig_size = ret;
482 	skel->bss->user_keyring_serial = syscall(__NR_request_key, "keyring",
483 						 "ebpf_testing_keyring", NULL,
484 						 KEY_SPEC_SESSION_KEYRING);
485 	memcpy(skel->bss->digest, "FSVerity", 8);
486 
487 	ret = test_sig_in_xattr__load(skel);
488 	if (!ASSERT_OK(ret, "test_sig_in_xattr__load"))
489 		goto out;
490 
491 	ret = test_sig_in_xattr__attach(skel);
492 	if (!ASSERT_OK(ret, "test_sig_in_xattr__attach"))
493 		goto out;
494 
495 	pid = getpid();
496 
497 	/* Case 1: fsverity is not enabled, open should succeed */
498 	if (test_open_file(skel, data_path, pid, true, "open_1"))
499 		goto out;
500 
501 	/* Case 2: fsverity is enabled, xattr is missing, open should
502 	 * fail
503 	 */
504 	ret = _run_setup_process(tmp_dir, "fsverity-enable");
505 	if (!ASSERT_OK(ret, "fsverity-enable"))
506 		goto out;
507 	if (test_open_file(skel, data_path, pid, false, "open_2"))
508 		goto out;
509 
510 	/* Case 3: fsverity is enabled, xattr has valid signature, open
511 	 * should succeed
512 	 */
513 	ret = add_signature_to_xattr(data_path, sig_path);
514 	if (!ASSERT_OK(ret, "add_signature_to_xattr_1"))
515 		goto out;
516 
517 	if (test_open_file(skel, data_path, pid, true, "open_3"))
518 		goto out;
519 
520 	/* Case 4: fsverity is enabled, xattr has invalid signature, open
521 	 * should fail
522 	 */
523 	ret = add_signature_to_xattr(data_path, NULL);
524 	if (!ASSERT_OK(ret, "add_signature_to_xattr_2"))
525 		goto out;
526 	test_open_file(skel, data_path, pid, false, "open_4");
527 
528 out:
529 	_run_setup_process(tmp_dir, "cleanup");
530 	if (!skel)
531 		return;
532 
533 	skel->bss->monitored_pid = 0;
534 	test_sig_in_xattr__destroy(skel);
535 }
536 
537 void test_verify_pkcs7_sig(void)
538 {
539 	if (test__start_subtest("pkcs7_sig_from_map"))
540 		test_verify_pkcs7_sig_from_map();
541 	if (test__start_subtest("pkcs7_sig_fsverity"))
542 		test_pkcs7_sig_fsverity();
543 }
544