1 // SPDX-License-Identifier: GPL-2.0
4 * Copyright (C) 2022 Huawei Technologies Duesseldorf GmbH
18 #include <linux/keyctl.h>
19 #include <sys/xattr.h>
20 #include <linux/fsverity.h>
21 #include <test_progs.h>
23 #include "test_verify_pkcs7_sig.skel.h"
24 #include "test_sig_in_xattr.skel.h"
26 #define MAX_DATA_SIZE (1024 * 1024)
27 #define MAX_SIG_SIZE 1024
29 #define VERIFY_USE_SECONDARY_KEYRING (1UL)
30 #define VERIFY_USE_PLATFORM_KEYRING (2UL)
32 #ifndef SHA256_DIGEST_SIZE
33 #define SHA256_DIGEST_SIZE 32
36 /* In stripped ARM and x86-64 modules, ~ is surprisingly rare. */
37 #define MODULE_SIG_STRING "~Module signature appended~\n"
40 * Module signature information block.
42 * The constituents of the signature section are, in order:
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] */
56 __be32 sig_len; /* Length of signature data */
60 __u8 data[MAX_DATA_SIZE];
62 __u8 sig[MAX_SIG_SIZE];
66 static bool kfunc_not_supported;
68 static int libbpf_print_cb(enum libbpf_print_level level, const char *fmt,
71 if (level == LIBBPF_WARN)
74 if (strcmp(fmt, "libbpf: extern (func ksym) '%s': not found in kernel or module BTFs\n"))
77 if (strcmp(va_arg(args, char *), "bpf_verify_pkcs7_signature"))
80 kfunc_not_supported = true;
84 static int _run_setup_process(const char *setup_dir, const char *cmd)
86 int child_pid, child_status;
90 execlp("./verify_sig_setup.sh", "./verify_sig_setup.sh", cmd,
94 } else if (child_pid > 0) {
95 waitpid(child_pid, &child_status, 0);
96 return WEXITSTATUS(child_status);
102 static int populate_data_item_str(const char *tmp_dir, struct data *data_item)
105 char data_template[] = "/tmp/dataXXXXXX";
107 int ret, fd, child_status, child_pid;
109 data_item->data_len = 4;
110 memcpy(data_item->data, "test", data_item->data_len);
112 fd = mkstemp(data_template);
116 ret = write(fd, data_item->data, data_item->data_len);
120 if (ret != data_item->data_len) {
127 if (child_pid == -1) {
132 if (child_pid == 0) {
133 snprintf(path, sizeof(path), "%s/signing_key.pem", tmp_dir);
135 return execlp("./sign-file", "./sign-file", "-d", "sha256",
136 path, path, data_template, NULL);
139 waitpid(child_pid, &child_status, 0);
141 ret = WEXITSTATUS(child_status);
145 snprintf(path, sizeof(path), "%s.p7s", data_template);
147 ret = stat(path, &st);
153 if (st.st_size > sizeof(data_item->sig)) {
158 data_item->sig_len = st.st_size;
160 fd = open(path, O_RDONLY);
166 ret = read(fd, data_item->sig, data_item->sig_len);
170 if (ret != data_item->sig_len) {
179 unlink(data_template);
183 static int populate_data_item_mod(struct data *data_item)
185 char mod_path[PATH_MAX], *mod_path_ptr;
189 struct module_signature ms;
190 int ret, fd, modlen, marker_len, sig_len;
192 data_item->data_len = 0;
194 if (stat("/lib/modules", &st) == -1)
197 /* Requires CONFIG_TCP_CONG_BIC=m. */
198 fp = popen("find /lib/modules/$(uname -r) -name tcp_bic.ko", "r");
202 mod_path_ptr = fgets(mod_path, sizeof(mod_path), fp);
208 mod_path_ptr = strchr(mod_path, '\n');
212 *mod_path_ptr = '\0';
214 if (stat(mod_path, &st) == -1)
218 marker_len = sizeof(MODULE_SIG_STRING) - 1;
220 fd = open(mod_path, O_RDONLY);
224 mod = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
228 if (mod == MAP_FAILED)
231 if (strncmp(mod + modlen - marker_len, MODULE_SIG_STRING, marker_len)) {
236 modlen -= marker_len;
238 memcpy(&ms, mod + (modlen - sizeof(ms)), sizeof(ms));
240 sig_len = __be32_to_cpu(ms.sig_len);
241 modlen -= sig_len + sizeof(ms);
243 if (modlen > sizeof(data_item->data)) {
248 memcpy(data_item->data, mod, modlen);
249 data_item->data_len = modlen;
251 if (sig_len > sizeof(data_item->sig)) {
256 memcpy(data_item->sig, mod + modlen, sig_len);
257 data_item->sig_len = sig_len;
260 munmap(mod, st.st_size);
264 static void test_verify_pkcs7_sig_from_map(void)
266 libbpf_print_fn_t old_print_cb;
267 char tmp_dir_template[] = "/tmp/verify_sigXXXXXX";
269 struct test_verify_pkcs7_sig *skel = NULL;
274 /* Trigger creation of session keyring. */
275 syscall(__NR_request_key, "keyring", "_uid.0", NULL,
276 KEY_SPEC_SESSION_KEYRING);
278 tmp_dir = mkdtemp(tmp_dir_template);
279 if (!ASSERT_OK_PTR(tmp_dir, "mkdtemp"))
282 ret = _run_setup_process(tmp_dir, "setup");
283 if (!ASSERT_OK(ret, "_run_setup_process"))
286 skel = test_verify_pkcs7_sig__open();
287 if (!ASSERT_OK_PTR(skel, "test_verify_pkcs7_sig__open"))
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);
294 if (ret < 0 && kfunc_not_supported) {
296 "%s:SKIP:bpf_verify_pkcs7_signature() kfunc not supported\n",
302 if (!ASSERT_OK(ret, "test_verify_pkcs7_sig__load"))
305 ret = test_verify_pkcs7_sig__attach(skel);
306 if (!ASSERT_OK(ret, "test_verify_pkcs7_sig__attach"))
309 map = bpf_object__find_map_by_name(skel->obj, "data_input");
310 if (!ASSERT_OK_PTR(map, "data_input not found"))
313 skel->bss->monitored_pid = getpid();
315 /* Test without data and signature. */
316 skel->bss->user_keyring_serial = KEY_SPEC_SESSION_KEYRING;
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"))
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"))
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"))
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);
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"))
341 * Ensure key_task_permission() is called and rejects the keyring
342 * (no Search permission).
344 syscall(__NR_keyctl, KEYCTL_SETPERM, skel->bss->user_keyring_serial,
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"))
351 syscall(__NR_keyctl, KEYCTL_SETPERM, skel->bss->user_keyring_serial,
355 * Ensure key_validate() is called and rejects the keyring (key expired)
357 syscall(__NR_keyctl, KEYCTL_SET_TIMEOUT,
358 skel->bss->user_keyring_serial, 1);
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"))
365 skel->bss->user_keyring_serial = KEY_SPEC_SESSION_KEYRING;
367 /* Test with corrupted data (signature verification should fail). */
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"))
373 ret = populate_data_item_mod(&data);
374 if (!ASSERT_OK(ret, "populate_data_item_mod"))
377 /* Test signature verification with system keyrings. */
379 skel->bss->user_keyring_serial = 0;
380 skel->bss->system_keyring_id = 0;
382 ret = bpf_map_update_elem(bpf_map__fd(map), &zero, &data,
384 if (!ASSERT_OK(ret, "bpf_map_update_elem data_input"))
387 skel->bss->system_keyring_id = VERIFY_USE_SECONDARY_KEYRING;
389 ret = bpf_map_update_elem(bpf_map__fd(map), &zero, &data,
391 if (!ASSERT_OK(ret, "bpf_map_update_elem data_input"))
394 skel->bss->system_keyring_id = VERIFY_USE_PLATFORM_KEYRING;
396 ret = bpf_map_update_elem(bpf_map__fd(map), &zero, &data,
398 ASSERT_LT(ret, 0, "bpf_map_update_elem data_input");
402 _run_setup_process(tmp_dir, "cleanup");
407 skel->bss->monitored_pid = 0;
408 test_verify_pkcs7_sig__destroy(skel);
411 static int get_signature_size(const char *sig_path)
415 if (stat(sig_path, &st) == -1)
421 static int add_signature_to_xattr(const char *data_path, const char *sig_path)
423 char sig[MAX_SIG_SIZE] = {0};
427 fd = open(sig_path, O_RDONLY);
431 size = read(fd, sig, MAX_SIG_SIZE);
436 /* no sig_path, just write 32 bytes of zeros */
439 ret = setxattr(data_path, "user.sig", sig, size, 0);
440 if (!ASSERT_OK(ret, "setxattr"))
446 static int test_open_file(struct test_sig_in_xattr *skel, char *data_path,
447 pid_t pid, bool should_success, char *name)
451 skel->bss->monitored_pid = pid;
452 ret = open(data_path, O_RDONLY);
454 skel->bss->monitored_pid = 0;
456 if (should_success) {
457 if (!ASSERT_GE(ret, 0, name))
460 if (!ASSERT_LT(ret, 0, name))
466 static void test_pkcs7_sig_fsverity(void)
468 char data_path[PATH_MAX];
469 char sig_path[PATH_MAX];
470 char tmp_dir_template[] = "/tmp/verify_sigXXXXXX";
472 struct test_sig_in_xattr *skel = NULL;
476 tmp_dir = mkdtemp(tmp_dir_template);
477 if (!ASSERT_OK_PTR(tmp_dir, "mkdtemp"))
480 snprintf(data_path, PATH_MAX, "%s/data-file", tmp_dir);
481 snprintf(sig_path, PATH_MAX, "%s/sig-file", tmp_dir);
483 ret = _run_setup_process(tmp_dir, "setup");
484 if (!ASSERT_OK(ret, "_run_setup_process"))
487 ret = _run_setup_process(tmp_dir, "fsverity-create-sign");
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",
497 skel = test_sig_in_xattr__open();
498 if (!ASSERT_OK_PTR(skel, "test_sig_in_xattr__open"))
500 ret = get_signature_size(sig_path);
501 if (!ASSERT_GT(ret, 0, "get_signature_size"))
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);
509 ret = test_sig_in_xattr__load(skel);
510 if (!ASSERT_OK(ret, "test_sig_in_xattr__load"))
513 ret = test_sig_in_xattr__attach(skel);
514 if (!ASSERT_OK(ret, "test_sig_in_xattr__attach"))
519 /* Case 1: fsverity is not enabled, open should succeed */
520 if (test_open_file(skel, data_path, pid, true, "open_1"))
523 /* Case 2: fsverity is enabled, xattr is missing, open should
526 ret = _run_setup_process(tmp_dir, "fsverity-enable");
527 if (!ASSERT_OK(ret, "fsverity-enable"))
529 if (test_open_file(skel, data_path, pid, false, "open_2"))
532 /* Case 3: fsverity is enabled, xattr has valid signature, open
535 ret = add_signature_to_xattr(data_path, sig_path);
536 if (!ASSERT_OK(ret, "add_signature_to_xattr_1"))
539 if (test_open_file(skel, data_path, pid, true, "open_3"))
542 /* Case 4: fsverity is enabled, xattr has invalid signature, open
545 ret = add_signature_to_xattr(data_path, NULL);
546 if (!ASSERT_OK(ret, "add_signature_to_xattr_2"))
548 test_open_file(skel, data_path, pid, false, "open_4");
551 _run_setup_process(tmp_dir, "cleanup");
555 skel->bss->monitored_pid = 0;
556 test_sig_in_xattr__destroy(skel);
559 void test_verify_pkcs7_sig(void)
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();