~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/tools/testing/selftests/bpf/prog_tests/verify_pkcs7_sig.c

Version: ~ [ linux-6.11.5 ] ~ [ linux-6.10.14 ] ~ [ linux-6.9.12 ] ~ [ linux-6.8.12 ] ~ [ linux-6.7.12 ] ~ [ linux-6.6.58 ] ~ [ linux-6.5.13 ] ~ [ linux-6.4.16 ] ~ [ linux-6.3.13 ] ~ [ linux-6.2.16 ] ~ [ linux-6.1.114 ] ~ [ linux-6.0.19 ] ~ [ linux-5.19.17 ] ~ [ linux-5.18.19 ] ~ [ linux-5.17.15 ] ~ [ linux-5.16.20 ] ~ [ linux-5.15.169 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.228 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.284 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.322 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.336 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.337 ] ~ [ linux-4.4.302 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.9 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  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 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

sflogo.php