46968b6
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
46968b6
From: Dimitri John Ledkov <xnox@ubuntu.com>
46968b6
Date: Wed, 22 Jul 2020 11:31:43 +0100
46968b6
Subject: [PATCH] linuxefi: fail kernel validation without shim protocol.
46968b6
46968b6
If certificates that signed grub are installed into db, grub can be
46968b6
booted directly. It will then boot any kernel without signature
46968b6
validation. The booted kernel will think it was booted in secureboot
46968b6
mode and will implement lockdown, yet it could have been tampered.
46968b6
46968b6
This version of the patch skips calling verification, when booted
46968b6
without secureboot. And is indented with gnu ident.
46968b6
46968b6
CVE-2020-15705
46968b6
46968b6
Reported-by: Mathieu Trudel-Lapierre <cyphermox@ubuntu.com>
46968b6
Signed-off-by: Dimitri John Ledkov <xnox@ubuntu.com>
46968b6
---
46968b6
 grub-core/loader/arm64/linux.c     | 13 +++++++++----
46968b6
 grub-core/loader/efi/chainloader.c |  1 +
46968b6
 grub-core/loader/efi/linux.c       |  1 +
46968b6
 grub-core/loader/i386/efi/linux.c  | 17 +++++++++++------
46968b6
 4 files changed, 22 insertions(+), 10 deletions(-)
46968b6
46968b6
diff --git a/grub-core/loader/arm64/linux.c b/grub-core/loader/arm64/linux.c
e622855
index 70a0075ec5..47f8cf0d84 100644
46968b6
--- a/grub-core/loader/arm64/linux.c
46968b6
+++ b/grub-core/loader/arm64/linux.c
46968b6
@@ -34,6 +34,7 @@
46968b6
 #include <grub/i18n.h>
46968b6
 #include <grub/lib/cmdline.h>
46968b6
 #include <grub/verify.h>
46968b6
+#include <grub/efi/sb.h>
46968b6
 
46968b6
 GRUB_MOD_LICENSE ("GPLv3+");
46968b6
 
46968b6
@@ -363,11 +364,15 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
46968b6
 
46968b6
   grub_dprintf ("linux", "kernel @ %p\n", kernel_addr);
46968b6
 
46968b6
-  rc = grub_linuxefi_secure_validate (kernel_addr, kernel_size);
46968b6
-  if (rc < 0)
46968b6
+  if (grub_efi_get_secureboot () == GRUB_EFI_SECUREBOOT_MODE_ENABLED)
46968b6
     {
46968b6
-      grub_error (GRUB_ERR_INVALID_COMMAND, N_("%s has invalid signature"), argv[0]);
46968b6
-      goto fail;
46968b6
+      rc = grub_linuxefi_secure_validate (kernel_addr, kernel_size);
46968b6
+      if (rc <= 0)
46968b6
+	{
46968b6
+	  grub_error (GRUB_ERR_INVALID_COMMAND,
46968b6
+		      N_("%s has invalid signature"), argv[0]);
46968b6
+	  goto fail;
46968b6
+	}
46968b6
     }
46968b6
 
46968b6
   pe = (void *)((unsigned long)kernel_addr + lh.hdr_offset);
46968b6
diff --git a/grub-core/loader/efi/chainloader.c b/grub-core/loader/efi/chainloader.c
e622855
index ac8dfd40c6..d41e8ea14a 100644
46968b6
--- a/grub-core/loader/efi/chainloader.c
46968b6
+++ b/grub-core/loader/efi/chainloader.c
46968b6
@@ -1084,6 +1084,7 @@ grub_cmd_chainloader (grub_command_t cmd __attribute__ ((unused)),
46968b6
 
46968b6
       return 0;
46968b6
     }
46968b6
+  // -1 fall-through to fail
46968b6
 
46968b6
 fail:
46968b6
   if (dev)
46968b6
diff --git a/grub-core/loader/efi/linux.c b/grub-core/loader/efi/linux.c
e622855
index e8b9ecb17f..9260731c10 100644
46968b6
--- a/grub-core/loader/efi/linux.c
46968b6
+++ b/grub-core/loader/efi/linux.c
46968b6
@@ -33,6 +33,7 @@ struct grub_efi_shim_lock
46968b6
 };
46968b6
 typedef struct grub_efi_shim_lock grub_efi_shim_lock_t;
46968b6
 
46968b6
+// Returns 1 on success, -1 on error, 0 when not available
46968b6
 int
46968b6
 grub_linuxefi_secure_validate (void *data, grub_uint32_t size)
46968b6
 {
46968b6
diff --git a/grub-core/loader/i386/efi/linux.c b/grub-core/loader/i386/efi/linux.c
e622855
index f992ceeef2..3cf0f9b330 100644
46968b6
--- a/grub-core/loader/i386/efi/linux.c
46968b6
+++ b/grub-core/loader/i386/efi/linux.c
46968b6
@@ -30,6 +30,7 @@
46968b6
 #include <grub/cpu/efi/memory.h>
46968b6
 #include <grub/tpm.h>
46968b6
 #include <grub/safemath.h>
46968b6
+#include <grub/efi/sb.h>
46968b6
 
46968b6
 GRUB_MOD_LICENSE ("GPLv3+");
46968b6
 
46968b6
@@ -101,7 +102,7 @@ kernel_alloc(grub_efi_uintn_t size, const char * const errmsg)
46968b6
 
46968b6
       pages = BYTES_TO_PAGES(size);
46968b6
       grub_dprintf ("linux", "Trying to allocate %lu pages from %p\n",
46968b6
-		    pages, (void *)max);
46968b6
+		    (unsigned long)pages, (void *)(unsigned long)max);
46968b6
 
46968b6
       prev_max = max;
46968b6
       addr = grub_efi_allocate_pages_real (max, pages,
46968b6
@@ -307,12 +308,15 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
46968b6
       goto fail;
46968b6
     }
46968b6
 
46968b6
-  rc = grub_linuxefi_secure_validate (kernel, filelen);
46968b6
-  if (rc < 0)
46968b6
+  if (grub_efi_get_secureboot () == GRUB_EFI_SECUREBOOT_MODE_ENABLED)
46968b6
     {
46968b6
-      grub_error (GRUB_ERR_INVALID_COMMAND, N_("%s has invalid signature"),
46968b6
-		  argv[0]);
46968b6
-      goto fail;
46968b6
+      rc = grub_linuxefi_secure_validate (kernel, filelen);
46968b6
+      if (rc <= 0)
46968b6
+	{
46968b6
+	  grub_error (GRUB_ERR_INVALID_COMMAND,
46968b6
+		      N_("%s has invalid signature"), argv[0]);
46968b6
+	  goto fail;
46968b6
+	}
46968b6
     }
46968b6
 
46968b6
   lh = (struct linux_i386_kernel_header *)kernel;
46968b6
@@ -386,6 +390,7 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
46968b6
 
46968b6
   setup_header_end_offset = *((grub_uint8_t *)kernel + 0x201);
46968b6
   grub_dprintf ("linux", "copying %lu bytes from %p to %p\n",
46968b6
+		(unsigned long)
46968b6
 		MIN((grub_size_t)0x202+setup_header_end_offset,
46968b6
 		    sizeof (*params)) - 0x1f1,
46968b6
 		(grub_uint8_t *)kernel + 0x1f1,