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
Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.