Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at master 543 lines 13 kB view raw
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}