From 5f1e19e3c86d996633c5040744055d5f775abe11 Mon Sep 17 00:00:00 2001
From: Marco A Benatto <mbenatto@redhat.com>
Date: Wed, 23 Sep 2020 14:21:14 -0400
Subject: [PATCH 08/45] efi: Move the shim_lock verifier to the GRUB core

Move the shim_lock verifier from its own module into the core image. The
Secure Boot lockdown mechanism has the intent to prevent the load of any
unsigned code or binary when Secure Boot is enabled.

The reason is that GRUB must be able to prevent executing untrusted code
if UEFI Secure Boot is enabled, without depending on external modules.

Signed-off-by: Marco A Benatto <mbenatto@redhat.com>
Signed-off-by: Javier Martinez Canillas <javierm@redhat.com>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
---
 docs/grub.texi                     |   9 +-
 grub-core/Makefile.core.def        |   6 --
 grub-core/commands/efi/shim_lock.c | 133 -----------------------------
 grub-core/kern/efi/init.c          |   4 +
 grub-core/kern/efi/sb.c            | 105 +++++++++++++++++++++++
 include/grub/efi/sb.h              |   3 +
 6 files changed, 117 insertions(+), 143 deletions(-)
 delete mode 100644 grub-core/commands/efi/shim_lock.c

diff --git a/docs/grub.texi b/docs/grub.texi
index 26e134988..1107db016 100644
--- a/docs/grub.texi
+++ b/docs/grub.texi
@@ -5764,15 +5764,16 @@ secure boot chain.
 @section UEFI secure boot and shim support
 
 The GRUB, except the @command{chainloader} command, works with the UEFI secure
-boot and the shim. This functionality is provided by the shim_lock module. It
-is recommend to build in this and other required modules into the @file{core.img}.
+boot and the shim. This functionality is provided by the shim_lock verifier. It
+is built into the @file{core.img} and is registered if the UEFI secure boot is
+enabled.
+
 All modules not stored in the @file{core.img} and the ACPI tables for the
 @command{acpi} command have to be signed, e.g. using PGP. Additionally, the
 @command{iorw}, the @command{memrw} and the @command{wrmsr} commands are
 prohibited if the UEFI secure boot is enabled. This is done due to
 security reasons. All above mentioned requirements are enforced by the
-shim_lock module. And itself it is a persistent module which means that
-it cannot be unloaded if it was loaded into the memory.
+shim_lock verifier logic.
 
 @node Measured Boot
 @section Measuring boot components
diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def
index 5184aea24..bccffa5a3 100644
--- a/grub-core/Makefile.core.def
+++ b/grub-core/Makefile.core.def
@@ -944,12 +944,6 @@ module = {
   cppflags = '-I$(srcdir)/lib/posix_wrap';
 };
 
-module = {
-  name = shim_lock;
-  common = commands/efi/shim_lock.c;
-  enable = x86_64_efi;
-};
-
 module = {
   name = hdparm;
   common = commands/hdparm.c;
diff --git a/grub-core/commands/efi/shim_lock.c b/grub-core/commands/efi/shim_lock.c
deleted file mode 100644
index f7f3109d6..000000000
--- a/grub-core/commands/efi/shim_lock.c
+++ /dev/null
@@ -1,133 +0,0 @@
-/*
- *  GRUB  --  GRand Unified Bootloader
- *  Copyright (C) 2017  Free Software Foundation, Inc.
- *
- *  GRUB is free software: you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation, either version 3 of the License, or
- *  (at your option) any later version.
- *
- *  GRUB is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
- *
- *  EFI shim lock verifier.
- */
-
-#include <grub/dl.h>
-#include <grub/efi/efi.h>
-#include <grub/efi/sb.h>
-#include <grub/err.h>
-#include <grub/file.h>
-#include <grub/misc.h>
-#include <grub/verify.h>
-
-GRUB_MOD_LICENSE ("GPLv3+");
-
-static grub_efi_guid_t shim_lock_guid = GRUB_EFI_SHIM_LOCK_GUID;
-
-/* List of modules which cannot be loaded if UEFI secure boot mode is enabled. */
-static const char * const disabled_mods[] = {"iorw", "memrw", "wrmsr", NULL};
-
-static grub_err_t
-shim_lock_init (grub_file_t io, enum grub_file_type type,
-		void **context __attribute__ ((unused)),
-		enum grub_verify_flags *flags)
-{
-  const char *b, *e;
-  int i;
-
-  *flags = GRUB_VERIFY_FLAGS_SKIP_VERIFICATION;
-
-  switch (type & GRUB_FILE_TYPE_MASK)
-    {
-    case GRUB_FILE_TYPE_GRUB_MODULE:
-      /* Establish GRUB module name. */
-      b = grub_strrchr (io->name, '/');
-      e = grub_strrchr (io->name, '.');
-
-      b = b ? (b + 1) : io->name;
-      e = e ? e : io->name + grub_strlen (io->name);
-      e = (e > b) ? e : io->name + grub_strlen (io->name);
-
-      for (i = 0; disabled_mods[i]; i++)
-	if (!grub_strncmp (b, disabled_mods[i], grub_strlen (b) - grub_strlen (e)))
-	  {
-	    grub_error (GRUB_ERR_ACCESS_DENIED,
-			N_("module cannot be loaded in UEFI secure boot mode: %s"),
-			io->name);
-	    return GRUB_ERR_ACCESS_DENIED;
-	  }
-
-      /* Fall through. */
-
-    case GRUB_FILE_TYPE_ACPI_TABLE:
-    case GRUB_FILE_TYPE_DEVICE_TREE_IMAGE:
-      *flags = GRUB_VERIFY_FLAGS_DEFER_AUTH;
-
-      return GRUB_ERR_NONE;
-
-    case GRUB_FILE_TYPE_LINUX_KERNEL:
-    case GRUB_FILE_TYPE_MULTIBOOT_KERNEL:
-    case GRUB_FILE_TYPE_BSD_KERNEL:
-    case GRUB_FILE_TYPE_XNU_KERNEL:
-    case GRUB_FILE_TYPE_PLAN9_KERNEL:
-      for (i = 0; disabled_mods[i]; i++)
-	if (grub_dl_get (disabled_mods[i]))
-	  {
-	    grub_error (GRUB_ERR_ACCESS_DENIED,
-			N_("cannot boot due to dangerous module in memory: %s"),
-			disabled_mods[i]);
-	    return GRUB_ERR_ACCESS_DENIED;
-	  }
-
-      *flags = GRUB_VERIFY_FLAGS_SINGLE_CHUNK;
-
-      /* Fall through. */
-
-    default:
-      return GRUB_ERR_NONE;
-    }
-}
-
-static grub_err_t
-shim_lock_write (void *context __attribute__ ((unused)), void *buf, grub_size_t size)
-{
-  grub_efi_shim_lock_protocol_t *sl = grub_efi_locate_protocol (&shim_lock_guid, 0);
-
-  if (sl == NULL)
-    return grub_error (GRUB_ERR_ACCESS_DENIED, N_("shim_lock protocol not found"));
-
-  if (sl->verify (buf, size) != GRUB_EFI_SUCCESS)
-    return grub_error (GRUB_ERR_BAD_SIGNATURE, N_("bad shim signature"));
-
-  return GRUB_ERR_NONE;
-}
-
-struct grub_file_verifier shim_lock =
-  {
-    .name = "shim_lock",
-    .init = shim_lock_init,
-    .write = shim_lock_write
-  };
-
-GRUB_MOD_INIT(shim_lock)
-{
-  grub_efi_shim_lock_protocol_t *sl = grub_efi_locate_protocol (&shim_lock_guid, 0);
-
-  if (sl == NULL || grub_efi_get_secureboot () != GRUB_EFI_SECUREBOOT_MODE_ENABLED)
-    return;
-
-  grub_verifier_register (&shim_lock);
-
-  grub_dl_set_persistent (mod);
-}
-
-GRUB_MOD_FINI(shim_lock)
-{
-  grub_verifier_unregister (&shim_lock);
-}
diff --git a/grub-core/kern/efi/init.c b/grub-core/kern/efi/init.c
index 5c7876e42..9c143eed7 100644
--- a/grub-core/kern/efi/init.c
+++ b/grub-core/kern/efi/init.c
@@ -20,6 +20,7 @@
 #include <grub/efi/efi.h>
 #include <grub/efi/console.h>
 #include <grub/efi/disk.h>
+#include <grub/efi/sb.h>
 #include <grub/term.h>
 #include <grub/misc.h>
 #include <grub/env.h>
@@ -40,6 +41,9 @@ grub_efi_init (void)
   /* Initialize the memory management system.  */
   grub_efi_mm_init ();
 
+  /* Register the shim_lock verifier if UEFI Secure Boot is enabled. */
+  grub_shim_lock_verifier_setup ();
+
   efi_call_4 (grub_efi_system_table->boot_services->set_watchdog_timer,
 	      0, 0, 0, NULL);
 
diff --git a/grub-core/kern/efi/sb.c b/grub-core/kern/efi/sb.c
index 19658d962..8bd5e936d 100644
--- a/grub-core/kern/efi/sb.c
+++ b/grub-core/kern/efi/sb.c
@@ -22,9 +22,16 @@
 #include <grub/efi/pe32.h>
 #include <grub/efi/sb.h>
 #include <grub/err.h>
+#include <grub/file.h>
 #include <grub/i386/linux.h>
 #include <grub/mm.h>
 #include <grub/types.h>
+#include <grub/verify.h>
+
+static grub_efi_guid_t shim_lock_guid = GRUB_EFI_SHIM_LOCK_GUID;
+
+/* List of modules which cannot be loaded if UEFI secure boot mode is enabled. */
+static const char * const disabled_mods[] = {"iorw", "memrw", "wrmsr", NULL};
 
 /*
  * Determine whether we're in secure boot mode.
@@ -107,3 +114,101 @@ grub_efi_get_secureboot (void)
 
   return secureboot;
 }
+
+static grub_err_t
+shim_lock_verifier_init (grub_file_t io __attribute__ ((unused)),
+			 enum grub_file_type type,
+			 void **context __attribute__ ((unused)),
+			 enum grub_verify_flags *flags)
+{
+  const char *b, *e;
+  int i;
+
+  *flags = GRUB_VERIFY_FLAGS_SKIP_VERIFICATION;
+
+  switch (type & GRUB_FILE_TYPE_MASK)
+    {
+    case GRUB_FILE_TYPE_GRUB_MODULE:
+      /* Establish GRUB module name. */
+      b = grub_strrchr (io->name, '/');
+      e = grub_strrchr (io->name, '.');
+
+      b = b ? (b + 1) : io->name;
+      e = e ? e : io->name + grub_strlen (io->name);
+      e = (e > b) ? e : io->name + grub_strlen (io->name);
+
+      for (i = 0; disabled_mods[i]; i++)
+	if (!grub_strncmp (b, disabled_mods[i], grub_strlen (b) - grub_strlen (e)))
+	  {
+	    grub_error (GRUB_ERR_ACCESS_DENIED,
+			N_("module cannot be loaded in UEFI secure boot mode: %s"),
+			io->name);
+	    return GRUB_ERR_ACCESS_DENIED;
+	  }
+
+      /* Fall through. */
+
+    case GRUB_FILE_TYPE_ACPI_TABLE:
+    case GRUB_FILE_TYPE_DEVICE_TREE_IMAGE:
+      *flags = GRUB_VERIFY_FLAGS_DEFER_AUTH;
+
+      return GRUB_ERR_NONE;
+
+    case GRUB_FILE_TYPE_LINUX_KERNEL:
+    case GRUB_FILE_TYPE_MULTIBOOT_KERNEL:
+    case GRUB_FILE_TYPE_BSD_KERNEL:
+    case GRUB_FILE_TYPE_XNU_KERNEL:
+    case GRUB_FILE_TYPE_PLAN9_KERNEL:
+      for (i = 0; disabled_mods[i]; i++)
+	if (grub_dl_get (disabled_mods[i]))
+	  {
+	    grub_error (GRUB_ERR_ACCESS_DENIED,
+			N_("cannot boot due to dangerous module in memory: %s"),
+			disabled_mods[i]);
+	    return GRUB_ERR_ACCESS_DENIED;
+	  }
+
+      *flags = GRUB_VERIFY_FLAGS_SINGLE_CHUNK;
+
+      /* Fall through. */
+
+    default:
+      return GRUB_ERR_NONE;
+    }
+}
+
+static grub_err_t
+shim_lock_verifier_write (void *context __attribute__ ((unused)), void *buf, grub_size_t size)
+{
+  grub_efi_shim_lock_protocol_t *sl = grub_efi_locate_protocol (&shim_lock_guid, 0);
+
+  if (!sl)
+    return grub_error (GRUB_ERR_ACCESS_DENIED, N_("shim_lock protocol not found"));
+
+  if (sl->verify (buf, size) != GRUB_EFI_SUCCESS)
+    return grub_error (GRUB_ERR_BAD_SIGNATURE, N_("bad shim signature"));
+
+  return GRUB_ERR_NONE;
+}
+
+struct grub_file_verifier shim_lock_verifier =
+  {
+    .name = "shim_lock_verifier",
+    .init = shim_lock_verifier_init,
+    .write = shim_lock_verifier_write
+  };
+
+void
+grub_shim_lock_verifier_setup (void)
+{
+  grub_efi_shim_lock_protocol_t *sl =
+    grub_efi_locate_protocol (&shim_lock_guid, 0);
+
+  if (!sl)
+    return;
+
+  if (grub_efi_get_secureboot () != GRUB_EFI_SECUREBOOT_MODE_ENABLED)
+    return;
+
+  grub_verifier_register (&shim_lock_verifier);
+}
diff --git a/include/grub/efi/sb.h b/include/grub/efi/sb.h
index a33d985e3..30c4335bb 100644
--- a/include/grub/efi/sb.h
+++ b/include/grub/efi/sb.h
@@ -30,6 +30,9 @@
 #ifdef GRUB_MACHINE_EFI
 extern grub_uint8_t
 EXPORT_FUNC (grub_efi_get_secureboot) (void);
+
+extern void
+grub_shim_lock_verifier_setup (void);
 #else
 static inline grub_uint8_t
 grub_efi_get_secureboot (void)
-- 
2.26.2

