Linux kernel mirror (for testing)
git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel
os
linux
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
37struct data {
38 __u8 data[MAX_DATA_SIZE];
39 __u32 data_len;
40 __u8 sig[MAX_SIG_SIZE];
41 __u32 sig_len;
42};
43
44static bool kfunc_not_supported;
45
46static 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
62static 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
80static 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;
154out_sig:
155 unlink(path);
156out:
157 unlink(data_template);
158 return ret;
159}
160
161static 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;
237out:
238 munmap(mod, st.st_size);
239 return ret;
240}
241
242static 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
379close_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
389static 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
399static 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
424static 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
444static 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
528out:
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
537void 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}