[PATCH v1 1/1] Return the verified kernel image signature in kexec_file_load

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 




From: Lakshmi Ramasubramanian <nramas@xxxxxxxxxxxxx>

Signed-off-by: Lakshmi Ramasubramanian <nramas@xxxxxxxxxxxxx>
---
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




[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Index of Archives]     [Linux Kernel]     [Linux Kernel Hardening]     [Linux NFS]     [Linux NILFS]     [Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Yosemite News]     [Linux SCSI]

  Powered by Linux