s390/kexec_file: Signature verification prototype
authorPhilipp Rudo <prudo@linux.ibm.com>
Tue, 26 Feb 2019 09:50:39 +0000 (10:50 +0100)
committerMartin Schwidefsky <schwidefsky@de.ibm.com>
Mon, 29 Apr 2019 08:44:01 +0000 (10:44 +0200)
Add kernel signature verification to kexec_file. The verification is based
on module signature verification and works with kernel images signed via
scripts/sign-file.

Signed-off-by: Philipp Rudo <prudo@linux.ibm.com>
Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
arch/s390/Kconfig
arch/s390/configs/debug_defconfig
arch/s390/configs/performance_defconfig
arch/s390/defconfig
arch/s390/include/asm/kexec.h
arch/s390/kernel/kexec_elf.c
arch/s390/kernel/kexec_image.c
arch/s390/kernel/machine_kexec_file.c

index 1c3fcf19c3af558de0852b68507ad82cd8d8a197..21e851b0a989be93bffc7f658ec14d0a5e9e3fdf 100644 (file)
@@ -553,6 +553,17 @@ config ARCH_HAS_KEXEC_PURGATORY
        def_bool y
        depends on KEXEC_FILE
 
+config KEXEC_VERIFY_SIG
+       bool "Verify kernel signature during kexec_file_load() syscall"
+       depends on KEXEC_FILE && SYSTEM_DATA_VERIFICATION
+       help
+         This option makes kernel signature verification mandatory for
+         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 ARCH_RANDOM
        def_bool y
        prompt "s390 architectural random number generation API"
index 9824c7bad9d48592afa1b7a530fd02f30858eecb..b0920b35f87b8b5a64a983921393d1d21ff75ba3 100644 (file)
@@ -64,6 +64,7 @@ CONFIG_NUMA=y
 CONFIG_PREEMPT=y
 CONFIG_HZ_100=y
 CONFIG_KEXEC_FILE=y
+CONFIG_KEXEC_VERIFY_SIG=y
 CONFIG_EXPOLINE=y
 CONFIG_EXPOLINE_AUTO=y
 CONFIG_MEMORY_HOTPLUG=y
index 4fcbe5792744b4d59f4fc731b082c80d05b6990c..09aa5cb148737eac85000af34e52a38efd1b1a69 100644 (file)
@@ -65,6 +65,7 @@ CONFIG_NR_CPUS=512
 CONFIG_NUMA=y
 CONFIG_HZ_100=y
 CONFIG_KEXEC_FILE=y
+CONFIG_KEXEC_VERIFY_SIG=y
 CONFIG_EXPOLINE=y
 CONFIG_EXPOLINE_AUTO=y
 CONFIG_MEMORY_HOTPLUG=y
index 4d58a92b5d979f15e3469240c47a8e6f5fc4c189..c59b922cb6c561402134e03a0784654ac1500580 100644 (file)
@@ -39,6 +39,7 @@ CONFIG_NR_CPUS=256
 CONFIG_NUMA=y
 CONFIG_HZ_100=y
 CONFIG_KEXEC_FILE=y
+CONFIG_KEXEC_VERIFY_SIG=y
 CONFIG_CRASH_DUMP=y
 CONFIG_HIBERNATION=y
 CONFIG_PM_DEBUG=y
index 9ec077b0fb4d83d6549b37080cb115431afadd40..59026899e7669f8d643101a3071d42a0306e47dd 100644 (file)
@@ -65,6 +65,7 @@ struct s390_load_data {
        size_t memsz;
 };
 
+int s390_verify_sig(const char *kernel, unsigned long kernel_len);
 void *kexec_file_add_components(struct kimage *image,
                                int (*add_kernel)(struct kimage *image,
                                                  struct s390_load_data *data));
index 42bcd93f4318b16b51a7ebba4616057da9978ca3..01e45d89b636e4ca8e9e36e2a721502795dab2c2 100644 (file)
@@ -125,4 +125,7 @@ static int s390_elf_probe(const char *buf, unsigned long len)
 const struct kexec_file_ops s390_kexec_elf_ops = {
        .probe = s390_elf_probe,
        .load = s390_elf_load,
+#ifdef CONFIG_KEXEC_VERIFY_SIG
+       .verify_sig = s390_verify_sig,
+#endif /* CONFIG_KEXEC_VERIFY_SIG */
 };
index 7281540605b70b0c43b8516f699dba7c2e438305..c378bbac5b35a7dba9799a5bfa0c52878d051879 100644 (file)
@@ -54,4 +54,7 @@ static int s390_image_probe(const char *buf, unsigned long len)
 const struct kexec_file_ops s390_kexec_image_ops = {
        .probe = s390_image_probe,
        .load = s390_image_load,
+#ifdef CONFIG_KEXEC_VERIFY_SIG
+       .verify_sig = s390_verify_sig,
+#endif /* CONFIG_KEXEC_VERIFY_SIG */
 };
index 0e2a5a7a1b7c4593dfec9d52efb370f3c9b6968a..e0f6e618e1bfc97ea5466adb56f8d42f7ffa1658 100644 (file)
@@ -8,7 +8,11 @@
  */
 
 #include <linux/elf.h>
+#include <linux/errno.h>
 #include <linux/kexec.h>
+#include <linux/module.h>
+#include <linux/verification.h>
+#include <asm/ipl.h>
 #include <asm/setup.h>
 
 const struct kexec_file_ops * const kexec_file_loaders[] = {
@@ -17,6 +21,76 @@ const struct kexec_file_ops * const kexec_file_loaders[] = {
        NULL,
 };
 
+#ifdef CONFIG_KEXEC_VERIFY_SIG
+/*
+ * Module signature information block.
+ *
+ * The constituents of the signature section are, in order:
+ *
+ *     - Signer's name
+ *     - Key identifier
+ *     - Signature data
+ *     - Information block
+ */
+struct module_signature {
+       u8      algo;           /* Public-key crypto algorithm [0] */
+       u8      hash;           /* Digest algorithm [0] */
+       u8      id_type;        /* Key identifier type [PKEY_ID_PKCS7] */
+       u8      signer_len;     /* Length of signer's name [0] */
+       u8      key_id_len;     /* Length of key identifier [0] */
+       u8      __pad[3];
+       __be32  sig_len;        /* Length of signature data */
+};
+
+#define PKEY_ID_PKCS7 2
+
+int s390_verify_sig(const char *kernel, unsigned long kernel_len)
+{
+       const unsigned long marker_len = sizeof(MODULE_SIG_STRING) - 1;
+       struct module_signature *ms;
+       unsigned long sig_len;
+
+       /* Skip signature verification when not secure IPLed. */
+       if (!ipl_secure_flag)
+               return 0;
+
+       if (marker_len > kernel_len)
+               return -EKEYREJECTED;
+
+       if (memcmp(kernel + kernel_len - marker_len, MODULE_SIG_STRING,
+                  marker_len))
+               return -EKEYREJECTED;
+       kernel_len -= marker_len;
+
+       ms = (void *)kernel + kernel_len - sizeof(*ms);
+       kernel_len -= sizeof(*ms);
+
+       sig_len = be32_to_cpu(ms->sig_len);
+       if (sig_len >= kernel_len)
+               return -EKEYREJECTED;
+       kernel_len -= sig_len;
+
+       if (ms->id_type != PKEY_ID_PKCS7)
+               return -EKEYREJECTED;
+
+       if (ms->algo != 0 ||
+           ms->hash != 0 ||
+           ms->signer_len != 0 ||
+           ms->key_id_len != 0 ||
+           ms->__pad[0] != 0 ||
+           ms->__pad[1] != 0 ||
+           ms->__pad[2] != 0) {
+               return -EBADMSG;
+       }
+
+       return verify_pkcs7_signature(kernel, kernel_len,
+                                     kernel + kernel_len, sig_len,
+                                     VERIFY_USE_PLATFORM_KEYRING,
+                                     VERIFYING_MODULE_SIGNATURE,
+                                     NULL, NULL);
+}
+#endif /* CONFIG_KEXEC_VERIFY_SIG */
+
 static int kexec_file_update_purgatory(struct kimage *image,
                                       struct s390_load_data *data)
 {