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