diff options
| -rw-r--r-- | arch/x86/Kconfig | 22 | ||||
| -rw-r--r-- | arch/x86/kernel/kexec-bzimage64.c | 21 | ||||
| -rw-r--r-- | arch/x86/kernel/machine_kexec_64.c | 11 | ||||
| -rw-r--r-- | include/linux/kexec.h | 3 | ||||
| -rw-r--r-- | kernel/kexec.c | 15 |
5 files changed, 72 insertions, 0 deletions
diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig index 9558b9fcafbf..4aafd322e21e 100644 --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig | |||
| @@ -1599,6 +1599,28 @@ config KEXEC | |||
| 1599 | interface is strongly in flux, so no good recommendation can be | 1599 | interface is strongly in flux, so no good recommendation can be |
| 1600 | made. | 1600 | made. |
| 1601 | 1601 | ||
| 1602 | config KEXEC_VERIFY_SIG | ||
| 1603 | bool "Verify kernel signature during kexec_file_load() syscall" | ||
| 1604 | depends on KEXEC | ||
| 1605 | ---help--- | ||
| 1606 | This option makes kernel signature verification mandatory for | ||
| 1607 | kexec_file_load() syscall. If kernel is signature can not be | ||
| 1608 | verified, kexec_file_load() will fail. | ||
| 1609 | |||
| 1610 | This option enforces signature verification at generic level. | ||
| 1611 | One needs to enable signature verification for type of kernel | ||
| 1612 | image being loaded to make sure it works. For example, enable | ||
| 1613 | bzImage signature verification option to be able to load and | ||
| 1614 | verify signatures of bzImage. Otherwise kernel loading will fail. | ||
| 1615 | |||
| 1616 | config KEXEC_BZIMAGE_VERIFY_SIG | ||
| 1617 | bool "Enable bzImage signature verification support" | ||
| 1618 | depends on KEXEC_VERIFY_SIG | ||
| 1619 | depends on SIGNED_PE_FILE_VERIFICATION | ||
| 1620 | select SYSTEM_TRUSTED_KEYRING | ||
| 1621 | ---help--- | ||
| 1622 | Enable bzImage signature verification support. | ||
| 1623 | |||
| 1602 | config CRASH_DUMP | 1624 | config CRASH_DUMP |
| 1603 | bool "kernel crash dumps" | 1625 | bool "kernel crash dumps" |
| 1604 | depends on X86_64 || (X86_32 && HIGHMEM) | 1626 | depends on X86_64 || (X86_32 && HIGHMEM) |
diff --git a/arch/x86/kernel/kexec-bzimage64.c b/arch/x86/kernel/kexec-bzimage64.c index 623e6c58081f..9642b9b33655 100644 --- a/arch/x86/kernel/kexec-bzimage64.c +++ b/arch/x86/kernel/kexec-bzimage64.c | |||
| @@ -19,6 +19,8 @@ | |||
| 19 | #include <linux/kernel.h> | 19 | #include <linux/kernel.h> |
| 20 | #include <linux/mm.h> | 20 | #include <linux/mm.h> |
| 21 | #include <linux/efi.h> | 21 | #include <linux/efi.h> |
| 22 | #include <linux/verify_pefile.h> | ||
| 23 | #include <keys/system_keyring.h> | ||
| 22 | 24 | ||
| 23 | #include <asm/bootparam.h> | 25 | #include <asm/bootparam.h> |
| 24 | #include <asm/setup.h> | 26 | #include <asm/setup.h> |
| @@ -525,8 +527,27 @@ int bzImage64_cleanup(void *loader_data) | |||
| 525 | return 0; | 527 | return 0; |
| 526 | } | 528 | } |
| 527 | 529 | ||
| 530 | #ifdef CONFIG_KEXEC_BZIMAGE_VERIFY_SIG | ||
| 531 | int bzImage64_verify_sig(const char *kernel, unsigned long kernel_len) | ||
| 532 | { | ||
| 533 | bool trusted; | ||
| 534 | int ret; | ||
| 535 | |||
| 536 | ret = verify_pefile_signature(kernel, kernel_len, | ||
| 537 | system_trusted_keyring, &trusted); | ||
| 538 | if (ret < 0) | ||
| 539 | return ret; | ||
| 540 | if (!trusted) | ||
| 541 | return -EKEYREJECTED; | ||
| 542 | return 0; | ||
| 543 | } | ||
| 544 | #endif | ||
| 545 | |||
| 528 | struct kexec_file_ops kexec_bzImage64_ops = { | 546 | struct kexec_file_ops kexec_bzImage64_ops = { |
| 529 | .probe = bzImage64_probe, | 547 | .probe = bzImage64_probe, |
| 530 | .load = bzImage64_load, | 548 | .load = bzImage64_load, |
| 531 | .cleanup = bzImage64_cleanup, | 549 | .cleanup = bzImage64_cleanup, |
| 550 | #ifdef CONFIG_KEXEC_BZIMAGE_VERIFY_SIG | ||
| 551 | .verify_sig = bzImage64_verify_sig, | ||
| 552 | #endif | ||
| 532 | }; | 553 | }; |
diff --git a/arch/x86/kernel/machine_kexec_64.c b/arch/x86/kernel/machine_kexec_64.c index 9330434da777..8b04018e5d1f 100644 --- a/arch/x86/kernel/machine_kexec_64.c +++ b/arch/x86/kernel/machine_kexec_64.c | |||
| @@ -372,6 +372,17 @@ int arch_kimage_file_post_load_cleanup(struct kimage *image) | |||
| 372 | return image->fops->cleanup(image->image_loader_data); | 372 | return image->fops->cleanup(image->image_loader_data); |
| 373 | } | 373 | } |
| 374 | 374 | ||
| 375 | int arch_kexec_kernel_verify_sig(struct kimage *image, void *kernel, | ||
| 376 | unsigned long kernel_len) | ||
| 377 | { | ||
| 378 | if (!image->fops || !image->fops->verify_sig) { | ||
| 379 | pr_debug("kernel loader does not support signature verification."); | ||
| 380 | return -EKEYREJECTED; | ||
| 381 | } | ||
| 382 | |||
| 383 | return image->fops->verify_sig(kernel, kernel_len); | ||
| 384 | } | ||
| 385 | |||
| 375 | /* | 386 | /* |
| 376 | * Apply purgatory relocations. | 387 | * Apply purgatory relocations. |
| 377 | * | 388 | * |
diff --git a/include/linux/kexec.h b/include/linux/kexec.h index 9481703b0e7a..4b2a0e11cc5b 100644 --- a/include/linux/kexec.h +++ b/include/linux/kexec.h | |||
| @@ -191,11 +191,14 @@ typedef void *(kexec_load_t)(struct kimage *image, char *kernel_buf, | |||
| 191 | unsigned long initrd_len, char *cmdline, | 191 | unsigned long initrd_len, char *cmdline, |
| 192 | unsigned long cmdline_len); | 192 | unsigned long cmdline_len); |
| 193 | typedef int (kexec_cleanup_t)(void *loader_data); | 193 | typedef int (kexec_cleanup_t)(void *loader_data); |
| 194 | typedef int (kexec_verify_sig_t)(const char *kernel_buf, | ||
| 195 | unsigned long kernel_len); | ||
| 194 | 196 | ||
| 195 | struct kexec_file_ops { | 197 | struct kexec_file_ops { |
| 196 | kexec_probe_t *probe; | 198 | kexec_probe_t *probe; |
| 197 | kexec_load_t *load; | 199 | kexec_load_t *load; |
| 198 | kexec_cleanup_t *cleanup; | 200 | kexec_cleanup_t *cleanup; |
| 201 | kexec_verify_sig_t *verify_sig; | ||
| 199 | }; | 202 | }; |
| 200 | 203 | ||
| 201 | /* kexec interface functions */ | 204 | /* kexec interface functions */ |
diff --git a/kernel/kexec.c b/kernel/kexec.c index f18c780f9716..0b49a0a58102 100644 --- a/kernel/kexec.c +++ b/kernel/kexec.c | |||
| @@ -416,6 +416,12 @@ void __weak arch_kimage_file_post_load_cleanup(struct kimage *image) | |||
| 416 | { | 416 | { |
| 417 | } | 417 | } |
| 418 | 418 | ||
| 419 | int __weak arch_kexec_kernel_verify_sig(struct kimage *image, void *buf, | ||
| 420 | unsigned long buf_len) | ||
| 421 | { | ||
| 422 | return -EKEYREJECTED; | ||
| 423 | } | ||
| 424 | |||
| 419 | /* Apply relocations of type RELA */ | 425 | /* Apply relocations of type RELA */ |
| 420 | int __weak | 426 | int __weak |
| 421 | arch_kexec_apply_relocations_add(const Elf_Ehdr *ehdr, Elf_Shdr *sechdrs, | 427 | arch_kexec_apply_relocations_add(const Elf_Ehdr *ehdr, Elf_Shdr *sechdrs, |
| @@ -494,6 +500,15 @@ kimage_file_prepare_segments(struct kimage *image, int kernel_fd, int initrd_fd, | |||
| 494 | if (ret) | 500 | if (ret) |
| 495 | goto out; | 501 | goto out; |
| 496 | 502 | ||
| 503 | #ifdef CONFIG_KEXEC_VERIFY_SIG | ||
| 504 | ret = arch_kexec_kernel_verify_sig(image, image->kernel_buf, | ||
| 505 | image->kernel_buf_len); | ||
| 506 | if (ret) { | ||
| 507 | pr_debug("kernel signature verification failed.\n"); | ||
| 508 | goto out; | ||
| 509 | } | ||
| 510 | pr_debug("kernel signature verification successful.\n"); | ||
| 511 | #endif | ||
| 497 | /* It is possible that there no initramfs is being loaded */ | 512 | /* It is possible that there no initramfs is being loaded */ |
| 498 | if (!(flags & KEXEC_FILE_NO_INITRAMFS)) { | 513 | if (!(flags & KEXEC_FILE_NO_INITRAMFS)) { |
| 499 | ret = copy_file_from_fd(initrd_fd, &image->initrd_buf, | 514 | ret = copy_file_from_fd(initrd_fd, &image->initrd_buf, |
