kexec_file: split KEXEC_VERIFY_SIG into KEXEC_SIG and KEXEC_SIG_FORCE
This is a preparatory patch for kexec_file_load() lockdown. A locked down kernel needs to prevent unsigned kernel images from being loaded with kexec_file_load(). Currently, the only way to force the signature verification is compiling with KEXEC_VERIFY_SIG. This prevents loading usigned images even when the kernel is not locked down at runtime. This patch splits KEXEC_VERIFY_SIG into KEXEC_SIG and KEXEC_SIG_FORCE. Analogous to the MODULE_SIG and MODULE_SIG_FORCE for modules, KEXEC_SIG turns on the signature verification but allows unsigned images to be loaded. KEXEC_SIG_FORCE disallows images without a valid signature. Signed-off-by: Jiri Bohac <jbohac@suse.cz> Signed-off-by: David Howells <dhowells@redhat.com> Signed-off-by: Matthew Garrett <mjg59@google.com> cc: kexec@lists.infradead.org Signed-off-by: James Morris <jmorris@namei.org>
This commit is contained in:
parent
fef5dad987
commit
99d5cadfde
|
@ -961,7 +961,7 @@ config KEXEC_FILE
|
||||||
for kernel and initramfs as opposed to list of segments as
|
for kernel and initramfs as opposed to list of segments as
|
||||||
accepted by previous system call.
|
accepted by previous system call.
|
||||||
|
|
||||||
config KEXEC_VERIFY_SIG
|
config KEXEC_SIG
|
||||||
bool "Verify kernel signature during kexec_file_load() syscall"
|
bool "Verify kernel signature during kexec_file_load() syscall"
|
||||||
depends on KEXEC_FILE
|
depends on KEXEC_FILE
|
||||||
help
|
help
|
||||||
|
@ -976,13 +976,13 @@ config KEXEC_VERIFY_SIG
|
||||||
config KEXEC_IMAGE_VERIFY_SIG
|
config KEXEC_IMAGE_VERIFY_SIG
|
||||||
bool "Enable Image signature verification support"
|
bool "Enable Image signature verification support"
|
||||||
default y
|
default y
|
||||||
depends on KEXEC_VERIFY_SIG
|
depends on KEXEC_SIG
|
||||||
depends on EFI && SIGNED_PE_FILE_VERIFICATION
|
depends on EFI && SIGNED_PE_FILE_VERIFICATION
|
||||||
help
|
help
|
||||||
Enable Image signature verification support.
|
Enable Image signature verification support.
|
||||||
|
|
||||||
comment "Support for PE file signature verification disabled"
|
comment "Support for PE file signature verification disabled"
|
||||||
depends on KEXEC_VERIFY_SIG
|
depends on KEXEC_SIG
|
||||||
depends on !EFI || !SIGNED_PE_FILE_VERIFICATION
|
depends on !EFI || !SIGNED_PE_FILE_VERIFICATION
|
||||||
|
|
||||||
config CRASH_DUMP
|
config CRASH_DUMP
|
||||||
|
|
|
@ -555,7 +555,7 @@ config ARCH_HAS_KEXEC_PURGATORY
|
||||||
def_bool y
|
def_bool y
|
||||||
depends on KEXEC_FILE
|
depends on KEXEC_FILE
|
||||||
|
|
||||||
config KEXEC_VERIFY_SIG
|
config KEXEC_SIG
|
||||||
bool "Verify kernel signature during kexec_file_load() syscall"
|
bool "Verify kernel signature during kexec_file_load() syscall"
|
||||||
depends on KEXEC_FILE && SYSTEM_DATA_VERIFICATION
|
depends on KEXEC_FILE && SYSTEM_DATA_VERIFICATION
|
||||||
help
|
help
|
||||||
|
|
|
@ -64,7 +64,7 @@ CONFIG_NUMA=y
|
||||||
CONFIG_PREEMPT=y
|
CONFIG_PREEMPT=y
|
||||||
CONFIG_HZ_100=y
|
CONFIG_HZ_100=y
|
||||||
CONFIG_KEXEC_FILE=y
|
CONFIG_KEXEC_FILE=y
|
||||||
CONFIG_KEXEC_VERIFY_SIG=y
|
CONFIG_KEXEC_SIG=y
|
||||||
CONFIG_EXPOLINE=y
|
CONFIG_EXPOLINE=y
|
||||||
CONFIG_EXPOLINE_AUTO=y
|
CONFIG_EXPOLINE_AUTO=y
|
||||||
CONFIG_MEMORY_HOTPLUG=y
|
CONFIG_MEMORY_HOTPLUG=y
|
||||||
|
|
|
@ -39,7 +39,7 @@ CONFIG_NR_CPUS=256
|
||||||
CONFIG_NUMA=y
|
CONFIG_NUMA=y
|
||||||
CONFIG_HZ_100=y
|
CONFIG_HZ_100=y
|
||||||
CONFIG_KEXEC_FILE=y
|
CONFIG_KEXEC_FILE=y
|
||||||
CONFIG_KEXEC_VERIFY_SIG=y
|
CONFIG_KEXEC_SIG=y
|
||||||
CONFIG_CRASH_DUMP=y
|
CONFIG_CRASH_DUMP=y
|
||||||
CONFIG_HIBERNATION=y
|
CONFIG_HIBERNATION=y
|
||||||
CONFIG_PM_DEBUG=y
|
CONFIG_PM_DEBUG=y
|
||||||
|
|
|
@ -65,7 +65,7 @@ CONFIG_NR_CPUS=512
|
||||||
CONFIG_NUMA=y
|
CONFIG_NUMA=y
|
||||||
CONFIG_HZ_100=y
|
CONFIG_HZ_100=y
|
||||||
CONFIG_KEXEC_FILE=y
|
CONFIG_KEXEC_FILE=y
|
||||||
CONFIG_KEXEC_VERIFY_SIG=y
|
CONFIG_KEXEC_SIG=y
|
||||||
CONFIG_EXPOLINE=y
|
CONFIG_EXPOLINE=y
|
||||||
CONFIG_EXPOLINE_AUTO=y
|
CONFIG_EXPOLINE_AUTO=y
|
||||||
CONFIG_MEMORY_HOTPLUG=y
|
CONFIG_MEMORY_HOTPLUG=y
|
||||||
|
|
|
@ -130,7 +130,7 @@ static int s390_elf_probe(const char *buf, unsigned long len)
|
||||||
const struct kexec_file_ops s390_kexec_elf_ops = {
|
const struct kexec_file_ops s390_kexec_elf_ops = {
|
||||||
.probe = s390_elf_probe,
|
.probe = s390_elf_probe,
|
||||||
.load = s390_elf_load,
|
.load = s390_elf_load,
|
||||||
#ifdef CONFIG_KEXEC_VERIFY_SIG
|
#ifdef CONFIG_KEXEC__SIG
|
||||||
.verify_sig = s390_verify_sig,
|
.verify_sig = s390_verify_sig,
|
||||||
#endif /* CONFIG_KEXEC_VERIFY_SIG */
|
#endif /* CONFIG_KEXEC_SIG */
|
||||||
};
|
};
|
||||||
|
|
|
@ -59,7 +59,7 @@ static int s390_image_probe(const char *buf, unsigned long len)
|
||||||
const struct kexec_file_ops s390_kexec_image_ops = {
|
const struct kexec_file_ops s390_kexec_image_ops = {
|
||||||
.probe = s390_image_probe,
|
.probe = s390_image_probe,
|
||||||
.load = s390_image_load,
|
.load = s390_image_load,
|
||||||
#ifdef CONFIG_KEXEC_VERIFY_SIG
|
#ifdef CONFIG_KEXEC_SIG
|
||||||
.verify_sig = s390_verify_sig,
|
.verify_sig = s390_verify_sig,
|
||||||
#endif /* CONFIG_KEXEC_VERIFY_SIG */
|
#endif /* CONFIG_KEXEC_SIG */
|
||||||
};
|
};
|
||||||
|
|
|
@ -22,7 +22,7 @@ const struct kexec_file_ops * const kexec_file_loaders[] = {
|
||||||
NULL,
|
NULL,
|
||||||
};
|
};
|
||||||
|
|
||||||
#ifdef CONFIG_KEXEC_VERIFY_SIG
|
#ifdef CONFIG_KEXEC_SIG
|
||||||
/*
|
/*
|
||||||
* Module signature information block.
|
* Module signature information block.
|
||||||
*
|
*
|
||||||
|
@ -90,7 +90,7 @@ int s390_verify_sig(const char *kernel, unsigned long kernel_len)
|
||||||
VERIFYING_MODULE_SIGNATURE,
|
VERIFYING_MODULE_SIGNATURE,
|
||||||
NULL, NULL);
|
NULL, NULL);
|
||||||
}
|
}
|
||||||
#endif /* CONFIG_KEXEC_VERIFY_SIG */
|
#endif /* CONFIG_KEXEC_SIG */
|
||||||
|
|
||||||
static int kexec_file_update_purgatory(struct kimage *image,
|
static int kexec_file_update_purgatory(struct kimage *image,
|
||||||
struct s390_load_data *data)
|
struct s390_load_data *data)
|
||||||
|
|
|
@ -2006,20 +2006,30 @@ config KEXEC_FILE
|
||||||
config ARCH_HAS_KEXEC_PURGATORY
|
config ARCH_HAS_KEXEC_PURGATORY
|
||||||
def_bool KEXEC_FILE
|
def_bool KEXEC_FILE
|
||||||
|
|
||||||
config KEXEC_VERIFY_SIG
|
config KEXEC_SIG
|
||||||
bool "Verify kernel signature during kexec_file_load() syscall"
|
bool "Verify kernel signature during kexec_file_load() syscall"
|
||||||
depends on KEXEC_FILE
|
depends on KEXEC_FILE
|
||||||
|
---help---
|
||||||
|
|
||||||
|
This option makes the kexec_file_load() syscall check for a valid
|
||||||
|
signature of the kernel image. The image can still be loaded without
|
||||||
|
a valid signature unless you also enable KEXEC_SIG_FORCE, though if
|
||||||
|
there's a signature that we can check, then it must be valid.
|
||||||
|
|
||||||
|
In addition to this option, you need to enable signature
|
||||||
|
verification for the corresponding kernel image type being
|
||||||
|
loaded in order for this to work.
|
||||||
|
|
||||||
|
config KEXEC_SIG_FORCE
|
||||||
|
bool "Require a valid signature in kexec_file_load() syscall"
|
||||||
|
depends on KEXEC_SIG
|
||||||
---help---
|
---help---
|
||||||
This option makes kernel signature verification mandatory for
|
This option makes kernel signature verification mandatory for
|
||||||
the kexec_file_load() syscall.
|
the kexec_file_load() syscall.
|
||||||
|
|
||||||
In addition to that option, you need to enable signature
|
|
||||||
verification for the corresponding kernel image type being
|
|
||||||
loaded in order for this to work.
|
|
||||||
|
|
||||||
config KEXEC_BZIMAGE_VERIFY_SIG
|
config KEXEC_BZIMAGE_VERIFY_SIG
|
||||||
bool "Enable bzImage signature verification support"
|
bool "Enable bzImage signature verification support"
|
||||||
depends on KEXEC_VERIFY_SIG
|
depends on KEXEC_SIG
|
||||||
depends on SIGNED_PE_FILE_VERIFICATION
|
depends on SIGNED_PE_FILE_VERIFICATION
|
||||||
select SYSTEM_TRUSTED_KEYRING
|
select SYSTEM_TRUSTED_KEYRING
|
||||||
---help---
|
---help---
|
||||||
|
|
|
@ -66,9 +66,9 @@ bool arch_ima_get_secureboot(void)
|
||||||
|
|
||||||
/* secureboot arch rules */
|
/* secureboot arch rules */
|
||||||
static const char * const sb_arch_rules[] = {
|
static const char * const sb_arch_rules[] = {
|
||||||
#if !IS_ENABLED(CONFIG_KEXEC_VERIFY_SIG)
|
#if !IS_ENABLED(CONFIG_KEXEC_SIG)
|
||||||
"appraise func=KEXEC_KERNEL_CHECK appraise_type=imasig",
|
"appraise func=KEXEC_KERNEL_CHECK appraise_type=imasig",
|
||||||
#endif /* CONFIG_KEXEC_VERIFY_SIG */
|
#endif /* CONFIG_KEXEC_SIG */
|
||||||
"measure func=KEXEC_KERNEL_CHECK",
|
"measure func=KEXEC_KERNEL_CHECK",
|
||||||
#if !IS_ENABLED(CONFIG_MODULE_SIG)
|
#if !IS_ENABLED(CONFIG_MODULE_SIG)
|
||||||
"appraise func=MODULE_CHECK appraise_type=imasig",
|
"appraise func=MODULE_CHECK appraise_type=imasig",
|
||||||
|
|
|
@ -96,7 +96,7 @@ static int pefile_parse_binary(const void *pebuf, unsigned int pelen,
|
||||||
|
|
||||||
if (!ddir->certs.virtual_address || !ddir->certs.size) {
|
if (!ddir->certs.virtual_address || !ddir->certs.size) {
|
||||||
pr_debug("Unsigned PE binary\n");
|
pr_debug("Unsigned PE binary\n");
|
||||||
return -EKEYREJECTED;
|
return -ENODATA;
|
||||||
}
|
}
|
||||||
|
|
||||||
chkaddr(ctx->header_size, ddir->certs.virtual_address,
|
chkaddr(ctx->header_size, ddir->certs.virtual_address,
|
||||||
|
@ -403,6 +403,8 @@ error_no_desc:
|
||||||
* (*) 0 if at least one signature chain intersects with the keys in the trust
|
* (*) 0 if at least one signature chain intersects with the keys in the trust
|
||||||
* keyring, or:
|
* keyring, or:
|
||||||
*
|
*
|
||||||
|
* (*) -ENODATA if there is no signature present.
|
||||||
|
*
|
||||||
* (*) -ENOPKG if a suitable crypto module couldn't be found for a check on a
|
* (*) -ENOPKG if a suitable crypto module couldn't be found for a check on a
|
||||||
* chain.
|
* chain.
|
||||||
*
|
*
|
||||||
|
|
|
@ -125,7 +125,7 @@ typedef void *(kexec_load_t)(struct kimage *image, char *kernel_buf,
|
||||||
unsigned long cmdline_len);
|
unsigned long cmdline_len);
|
||||||
typedef int (kexec_cleanup_t)(void *loader_data);
|
typedef int (kexec_cleanup_t)(void *loader_data);
|
||||||
|
|
||||||
#ifdef CONFIG_KEXEC_VERIFY_SIG
|
#ifdef CONFIG_KEXEC_SIG
|
||||||
typedef int (kexec_verify_sig_t)(const char *kernel_buf,
|
typedef int (kexec_verify_sig_t)(const char *kernel_buf,
|
||||||
unsigned long kernel_len);
|
unsigned long kernel_len);
|
||||||
#endif
|
#endif
|
||||||
|
@ -134,7 +134,7 @@ struct kexec_file_ops {
|
||||||
kexec_probe_t *probe;
|
kexec_probe_t *probe;
|
||||||
kexec_load_t *load;
|
kexec_load_t *load;
|
||||||
kexec_cleanup_t *cleanup;
|
kexec_cleanup_t *cleanup;
|
||||||
#ifdef CONFIG_KEXEC_VERIFY_SIG
|
#ifdef CONFIG_KEXEC_SIG
|
||||||
kexec_verify_sig_t *verify_sig;
|
kexec_verify_sig_t *verify_sig;
|
||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
|
|
|
@ -88,7 +88,7 @@ int __weak arch_kimage_file_post_load_cleanup(struct kimage *image)
|
||||||
return kexec_image_post_load_cleanup_default(image);
|
return kexec_image_post_load_cleanup_default(image);
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef CONFIG_KEXEC_VERIFY_SIG
|
#ifdef CONFIG_KEXEC_SIG
|
||||||
static int kexec_image_verify_sig_default(struct kimage *image, void *buf,
|
static int kexec_image_verify_sig_default(struct kimage *image, void *buf,
|
||||||
unsigned long buf_len)
|
unsigned long buf_len)
|
||||||
{
|
{
|
||||||
|
@ -177,6 +177,51 @@ void kimage_file_post_load_cleanup(struct kimage *image)
|
||||||
image->image_loader_data = NULL;
|
image->image_loader_data = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef CONFIG_KEXEC_SIG
|
||||||
|
static int
|
||||||
|
kimage_validate_signature(struct kimage *image)
|
||||||
|
{
|
||||||
|
const char *reason;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
ret = arch_kexec_kernel_verify_sig(image, image->kernel_buf,
|
||||||
|
image->kernel_buf_len);
|
||||||
|
switch (ret) {
|
||||||
|
case 0:
|
||||||
|
break;
|
||||||
|
|
||||||
|
/* Certain verification errors are non-fatal if we're not
|
||||||
|
* checking errors, provided we aren't mandating that there
|
||||||
|
* must be a valid signature.
|
||||||
|
*/
|
||||||
|
case -ENODATA:
|
||||||
|
reason = "kexec of unsigned image";
|
||||||
|
goto decide;
|
||||||
|
case -ENOPKG:
|
||||||
|
reason = "kexec of image with unsupported crypto";
|
||||||
|
goto decide;
|
||||||
|
case -ENOKEY:
|
||||||
|
reason = "kexec of image with unavailable key";
|
||||||
|
decide:
|
||||||
|
if (IS_ENABLED(CONFIG_KEXEC_SIG_FORCE)) {
|
||||||
|
pr_notice("%s rejected\n", reason);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
/* All other errors are fatal, including nomem, unparseable
|
||||||
|
* signatures and signature check failures - even if signatures
|
||||||
|
* aren't required.
|
||||||
|
*/
|
||||||
|
default:
|
||||||
|
pr_notice("kernel signature verification failed (%d).\n", ret);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* In file mode list of segments is prepared by kernel. Copy relevant
|
* In file mode list of segments is prepared by kernel. Copy relevant
|
||||||
* data from user space, do error checking, prepare segment list
|
* data from user space, do error checking, prepare segment list
|
||||||
|
@ -186,7 +231,7 @@ kimage_file_prepare_segments(struct kimage *image, int kernel_fd, int initrd_fd,
|
||||||
const char __user *cmdline_ptr,
|
const char __user *cmdline_ptr,
|
||||||
unsigned long cmdline_len, unsigned flags)
|
unsigned long cmdline_len, unsigned flags)
|
||||||
{
|
{
|
||||||
int ret = 0;
|
int ret;
|
||||||
void *ldata;
|
void *ldata;
|
||||||
loff_t size;
|
loff_t size;
|
||||||
|
|
||||||
|
@ -205,14 +250,11 @@ kimage_file_prepare_segments(struct kimage *image, int kernel_fd, int initrd_fd,
|
||||||
if (ret)
|
if (ret)
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
#ifdef CONFIG_KEXEC_VERIFY_SIG
|
#ifdef CONFIG_KEXEC_SIG
|
||||||
ret = arch_kexec_kernel_verify_sig(image, image->kernel_buf,
|
ret = kimage_validate_signature(image);
|
||||||
image->kernel_buf_len);
|
|
||||||
if (ret) {
|
if (ret)
|
||||||
pr_debug("kernel signature verification failed.\n");
|
|
||||||
goto out;
|
goto out;
|
||||||
}
|
|
||||||
pr_debug("kernel signature verification successful.\n");
|
|
||||||
#endif
|
#endif
|
||||||
/* It is possible that there no initramfs is being loaded */
|
/* It is possible that there no initramfs is being loaded */
|
||||||
if (!(flags & KEXEC_FILE_NO_INITRAMFS)) {
|
if (!(flags & KEXEC_FILE_NO_INITRAMFS)) {
|
||||||
|
|
|
@ -160,7 +160,7 @@ config IMA_APPRAISE
|
||||||
|
|
||||||
config IMA_ARCH_POLICY
|
config IMA_ARCH_POLICY
|
||||||
bool "Enable loading an IMA architecture specific policy"
|
bool "Enable loading an IMA architecture specific policy"
|
||||||
depends on KEXEC_VERIFY_SIG || IMA_APPRAISE && INTEGRITY_ASYMMETRIC_KEYS
|
depends on KEXEC_SIG || IMA_APPRAISE && INTEGRITY_ASYMMETRIC_KEYS
|
||||||
default n
|
default n
|
||||||
help
|
help
|
||||||
This option enables loading an IMA architecture specific policy
|
This option enables loading an IMA architecture specific policy
|
||||||
|
|
|
@ -541,7 +541,7 @@ int ima_load_data(enum kernel_load_data_id id)
|
||||||
|
|
||||||
switch (id) {
|
switch (id) {
|
||||||
case LOADING_KEXEC_IMAGE:
|
case LOADING_KEXEC_IMAGE:
|
||||||
if (IS_ENABLED(CONFIG_KEXEC_VERIFY_SIG)
|
if (IS_ENABLED(CONFIG_KEXEC_SIG)
|
||||||
&& arch_ima_get_secureboot()) {
|
&& arch_ima_get_secureboot()) {
|
||||||
pr_err("impossible to appraise a kernel image without a file descriptor; try using kexec_file_load syscall.\n");
|
pr_err("impossible to appraise a kernel image without a file descriptor; try using kexec_file_load syscall.\n");
|
||||||
return -EACCES;
|
return -EACCES;
|
||||||
|
|
Loading…
Reference in New Issue