From: Lakshmi Ramasubramanian <nra...@microsoft.com>

Signed-off-by: Lakshmi Ramasubramanian <nra...@microsoft.com>
---
When CONFIG_KEXEC_VERIFY_SIG is selected the signature on the new kernel image is verified in kexec_file_load.
The signature is embedded in the kernel image file.

This change returns the pointer to the verified signature and the length of that signature. kexec_file_load can log this
signature for attestation (To attest the signer of the new kernel).
The change to log the kernel signature for attestation will be added
in a future change set.


 arch/x86/kernel/kexec-bzimage64.c      |  7 +++++--
 arch/x86/kernel/machine_kexec_64.c     | 10 +++++++---
 crypto/asymmetric_keys/verify_pefile.c | 18 +++++++++++++++++-
 include/linux/kexec.h                  |  8 ++++++--
 include/linux/verification.h           |  4 +++-
 kernel/kexec_file.c                    | 14 +++++++++++---
 6 files changed, 49 insertions(+), 12 deletions(-)

diff --git a/arch/x86/kernel/kexec-bzimage64.c 
b/arch/x86/kernel/kexec-bzimage64.c
index 9d7fd5e6689a..030abd8adbce 100644
--- a/arch/x86/kernel/kexec-bzimage64.c
+++ b/arch/x86/kernel/kexec-bzimage64.c
@@ -530,11 +530,14 @@ static int bzImage64_cleanup(void *loader_data)
 }

 #ifdef CONFIG_KEXEC_BZIMAGE_VERIFY_SIG
-static int bzImage64_verify_sig(const char *kernel, unsigned long kernel_len)
+static int bzImage64_verify_sig(const char *kernel, unsigned long kernel_len,
+                               unsigned int *signature_len, void **signature)
 {
        return verify_pefile_signature(kernel, kernel_len,
                                       NULL,
-                                      VERIFYING_KEXEC_PE_SIGNATURE);
+                                      VERIFYING_KEXEC_PE_SIGNATURE,
+                                          signature_len,
+                                          signature);
 }
 #endif

diff --git a/arch/x86/kernel/machine_kexec_64.c 
b/arch/x86/kernel/machine_kexec_64.c
index 6f5ca4ebe6e5..b556a9750dd4 100644
--- a/arch/x86/kernel/machine_kexec_64.c
+++ b/arch/x86/kernel/machine_kexec_64.c
@@ -405,15 +405,19 @@ int arch_kimage_file_post_load_cleanup(struct kimage 
*image)
 }

 #ifdef CONFIG_KEXEC_VERIFY_SIG
-int arch_kexec_kernel_verify_sig(struct kimage *image, void *kernel,
-                                unsigned long kernel_len)
+int arch_kexec_kernel_verify_sig(struct kimage *image,
+                               void *kernel,
+                               unsigned long kernel_len,
+                               unsigned int *signature_len,
+                               void **signature)
 {
        if (!image->fops || !image->fops->verify_sig) {
                pr_debug("kernel loader does not support signature 
verification.");
                return -EKEYREJECTED;
        }

-       return image->fops->verify_sig(kernel, kernel_len);
+       return image->fops->verify_sig(kernel, kernel_len,
+                                               signature_len, signature);
 }
 #endif

diff --git a/crypto/asymmetric_keys/verify_pefile.c 
b/crypto/asymmetric_keys/verify_pefile.c
index 672a94c2c3ff..588a7966922f 100644
--- a/crypto/asymmetric_keys/verify_pefile.c
+++ b/crypto/asymmetric_keys/verify_pefile.c
@@ -394,6 +394,12 @@ static int pefile_digest_pe(const void *pebuf, unsigned 
int pelen,
  * @pelen: Length of the binary image
  * @trust_keys: Signing certificate(s) to use as starting points
  * @usage: The use to which the key is being put.
+ * @signature_len: If non-NULL the number of bytes in the signature
+ *                 will be returned in this out parameter
+ * @signature: If non-NULL a pointer to the buffer containing
+ *             the file signature will be returned in this out parameter.
+ *             The pointer being returned is actually within the buffer
+ *             pointed to by pebuf. So the caller should not try to free it.
  *
  * Validate that the certificate chain inside the PKCS#7 message inside the PE
  * binary image intersects keys we already know and trust.
@@ -418,7 +424,9 @@ static int pefile_digest_pe(const void *pebuf, unsigned int 
pelen,
  */
 int verify_pefile_signature(const void *pebuf, unsigned pelen,
                            struct key *trusted_keys,
-                           enum key_being_used_for usage)
+                           enum key_being_used_for usage,
+                               unsigned int *signature_len,
+                               void **signature)
 {
        struct pefile_context ctx;
        int ret;
@@ -448,6 +456,14 @@ int verify_pefile_signature(const void *pebuf, unsigned 
pelen,
         * contents.
         */
        ret = pefile_digest_pe(pebuf, pelen, &ctx);
+       if (ret < 0)
+               goto error;
+
+       /* Check if the caller needs the file signature */
+       if (signature_len != NULL && signature != NULL) {
+               *signature_len = ctx.sig_len;
+               *signature = pebuf + ctx.sig_offset;
+       }

 error:
        kfree(ctx.digest);
diff --git a/include/linux/kexec.h b/include/linux/kexec.h
index c9481ebcbc0c..1c790a5b03a0 100644
--- a/include/linux/kexec.h
+++ b/include/linux/kexec.h
@@ -131,7 +131,9 @@ typedef int (kexec_cleanup_t)(void *loader_data);

 #ifdef CONFIG_KEXEC_VERIFY_SIG
 typedef int (kexec_verify_sig_t)(const char *kernel_buf,
-                                unsigned long kernel_len);
+                                unsigned long kernel_len,
+                                unsigned int *signature_len,
+                                void **signature);
 #endif

 struct kexec_file_ops {
@@ -288,7 +290,9 @@ int __weak arch_kexec_kernel_image_probe(struct kimage 
*image, void *buf,
 void * __weak arch_kexec_kernel_image_load(struct kimage *image);
 int __weak arch_kimage_file_post_load_cleanup(struct kimage *image);
 int __weak arch_kexec_kernel_verify_sig(struct kimage *image, void *buf,
-                                       unsigned long buf_len);
+                                       unsigned long buf_len,
+                                       unsigned int *signature_len,
+                                       void **signature);
 int __weak arch_kexec_apply_relocations_add(const Elf_Ehdr *ehdr,
                                        Elf_Shdr *sechdrs, unsigned int relsec);
 int __weak arch_kexec_apply_relocations(const Elf_Ehdr *ehdr, Elf_Shdr 
*sechdrs,
diff --git a/include/linux/verification.h b/include/linux/verification.h
index a10549a6c7cd..2ad9ff1dab5e 100644
--- a/include/linux/verification.h
+++ b/include/linux/verification.h
@@ -42,7 +42,9 @@ extern int verify_pkcs7_signature(const void *data, size_t 
len,
 #ifdef CONFIG_SIGNED_PE_FILE_VERIFICATION
 extern int verify_pefile_signature(const void *pebuf, unsigned pelen,
                                   struct key *trusted_keys,
-                                  enum key_being_used_for usage);
+                                  enum key_being_used_for usage,
+                                  unsigned int *signature_len,
+                                  void **signature);
 #endif

 #endif /* CONFIG_SYSTEM_DATA_VERIFICATION */
diff --git a/kernel/kexec_file.c b/kernel/kexec_file.c
index b118735fea9d..fb0c94b8e52b 100644
--- a/kernel/kexec_file.c
+++ b/kernel/kexec_file.c
@@ -54,7 +54,9 @@ int __weak arch_kimage_file_post_load_cleanup(struct kimage 
*image)

 #ifdef CONFIG_KEXEC_VERIFY_SIG
 int __weak arch_kexec_kernel_verify_sig(struct kimage *image, void *buf,
-                                       unsigned long buf_len)
+                                       unsigned long buf_len,
+                                       unsigned int *signature_len,
+                                       void **signature)
 {
        return -EKEYREJECTED;
 }
@@ -126,6 +128,10 @@ kimage_file_prepare_segments(struct kimage *image, int 
kernel_fd, int initrd_fd,
        int ret = 0;
        void *ldata;
        loff_t size;
+#ifdef CONFIG_KEXEC_VERIFY_SIG
+       unsigned int signature_len;
+       void *signature;
+#endif

        ret = kernel_read_file_from_fd(kernel_fd, &image->kernel_buf,
                                       &size, INT_MAX, READING_KEXEC_IMAGE);
@@ -144,12 +150,14 @@ kimage_file_prepare_segments(struct kimage *image, int 
kernel_fd, int initrd_fd,

 #ifdef CONFIG_KEXEC_VERIFY_SIG
        ret = arch_kexec_kernel_verify_sig(image, image->kernel_buf,
-                                          image->kernel_buf_len);
+                                          image->kernel_buf_len,
+                                          &signature_len,
+                                          &signature);
        if (ret) {
                pr_debug("kernel signature verification failed.\n");
                goto out;
        }
-       pr_debug("kernel signature verification successful.\n");
+       pr_debug("Verified kernel signature. Sig len %d\n", signature_len);
 #endif
        /* It is possible that there no initramfs is being loaded */
        if (!(flags & KEXEC_FILE_NO_INITRAMFS)) {
--
2.17.1

Reply via email to