4ce656b
From 44cee23d139fe8faaca2622cc09041b1d684265b Mon Sep 17 00:00:00 2001
4ce656b
From: Peter Jones <pjones@redhat.com>
4ce656b
Date: Tue, 5 Jun 2012 09:23:25 -0400
4ce656b
Subject: [PATCH] Support secure boot.
4ce656b
4ce656b
If SecureBoot is enabled, treat all authentications as failure, and also
4ce656b
use shim's verify routine to verify the kernel before loading.
4ce656b
---
4ce656b
 grub-core/loader/i386/linux.c |   26 +++++++++++++
4ce656b
 grub-core/normal/auth.c       |   85 +++++++++++++++++++++++++++++++++++++++++
4ce656b
 grub-core/normal/main.c       |    4 +-
4ce656b
 grub-core/normal/menu_entry.c |    5 ++-
4ce656b
 include/grub/auth.h           |    3 ++
4ce656b
 5 files changed, 121 insertions(+), 2 deletions(-)
4ce656b
4ce656b
diff --git a/grub-core/loader/i386/linux.c b/grub-core/loader/i386/linux.c
4ce656b
index 6e8238e..090484c 100644
4ce656b
--- a/grub-core/loader/i386/linux.c
4ce656b
+++ b/grub-core/loader/i386/linux.c
4ce656b
@@ -34,6 +34,7 @@
4ce656b
 #include <grub/i386/relocator.h>
4ce656b
 #include <grub/i18n.h>
4ce656b
 #include <grub/lib/cmdline.h>
4ce656b
+#include <grub/auth.h>
4ce656b
 
4ce656b
 GRUB_MOD_LICENSE ("GPLv3+");
4ce656b
 
4ce656b
@@ -681,6 +682,9 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
4ce656b
   int relocatable;
4ce656b
   grub_uint64_t preffered_address = GRUB_LINUX_BZIMAGE_ADDR;
4ce656b
 
4ce656b
+  void *buffer;
4ce656b
+  grub_err_t verified;
4ce656b
+
4ce656b
   grub_dl_ref (my_mod);
4ce656b
 
4ce656b
   if (argc == 0)
4ce656b
@@ -693,6 +697,28 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
4ce656b
   if (! file)
4ce656b
     goto fail;
4ce656b
 
4ce656b
+  buffer = grub_malloc(grub_file_size(file));
4ce656b
+  if (!buffer)
4ce656b
+    return grub_errno;
4ce656b
+
4ce656b
+  if (grub_file_read (file, buffer, grub_file_size(file)))
4ce656b
+    {
4ce656b
+      if (!grub_errno)
4ce656b
+	grub_error (GRUB_ERR_BAD_OS, N_("premature end of file %s"),
4ce656b
+		    argv[0]);
4ce656b
+      goto fail;
4ce656b
+    }
4ce656b
+
4ce656b
+  verified = grub_auth_verify_signature(buffer, grub_file_size(file));
4ce656b
+  grub_free(buffer);
4ce656b
+  if (verified != GRUB_ERR_NONE)
4ce656b
+    {
4ce656b
+      grub_errno = verified;
4ce656b
+      goto fail;
4ce656b
+    }
4ce656b
+
4ce656b
+  grub_free(buffer);
4ce656b
+  grub_file_seek(file, 0);
4ce656b
   if (grub_file_read (file, &lh, sizeof (lh)) != sizeof (lh))
4ce656b
     {
4ce656b
       if (!grub_errno)
4ce656b
diff --git a/grub-core/normal/auth.c b/grub-core/normal/auth.c
4ce656b
index c6bd96e..3e83ee8 100644
4ce656b
--- a/grub-core/normal/auth.c
4ce656b
+++ b/grub-core/normal/auth.c
4ce656b
@@ -24,6 +24,8 @@
4ce656b
 #include <grub/normal.h>
4ce656b
 #include <grub/time.h>
4ce656b
 #include <grub/i18n.h>
4ce656b
+#include <grub/efi/api.h>
4ce656b
+#include <grub/efi/efi.h>
4ce656b
 
4ce656b
 struct grub_auth_user
4ce656b
 {
4ce656b
@@ -198,6 +200,89 @@ grub_username_get (char buf[], unsigned buf_size)
4ce656b
 }
4ce656b
 
4ce656b
 grub_err_t
4ce656b
+grub_auth_secure_boot (void)
4ce656b
+{
4ce656b
+#ifdef GRUB_MACHINE_EFI
4ce656b
+  grub_size_t datasize = 0;
4ce656b
+  grub_uint8_t *data;
4ce656b
+  grub_efi_guid_t guid = GRUB_EFI_GLOBAL_VARIABLE_GUID;
4ce656b
+  unsigned int x;
4ce656b
+
3490553
+  data = grub_efi_get_variable ("SecureBoot", &guid, &datasize);
4ce656b
+  if (!data)
4ce656b
+    return GRUB_ERR_NONE;
4ce656b
+
4ce656b
+  for (x = 0; x < datasize; x++)
4ce656b
+    if (data[x] == 1)
4ce656b
+      return GRUB_ACCESS_DENIED;
4ce656b
+#endif
4ce656b
+
4ce656b
+  return GRUB_ERR_NONE;
4ce656b
+}
4ce656b
+
4ce656b
+int
4ce656b
+grub_is_secure_boot (void)
4ce656b
+{
4ce656b
+  return grub_auth_secure_boot() == GRUB_ACCESS_DENIED;
4ce656b
+}
4ce656b
+
4ce656b
+#define SHIM_LOCK_GUID \
4ce656b
+  { 0x605dab50, 0xe046, 0x4300, {0xab,0xb6,0x3d,0xd8,0x10,0xdd,0x8b,0x23} }
4ce656b
+
4ce656b
+typedef grub_efi_status_t (*EFI_SHIM_LOCK_VERIFY)(void *buffer, grub_efi_uint32_t size);
4ce656b
+
4ce656b
+typedef struct _SHIM_LOCK {
4ce656b
+    EFI_SHIM_LOCK_VERIFY Verify;
4ce656b
+} SHIM_LOCK;
4ce656b
+
4ce656b
+grub_err_t
4ce656b
+grub_auth_verify_signature (void *buffer, grub_uint32_t size)
4ce656b
+{
4ce656b
+#ifdef GRUB_MACHINE_EFI
4ce656b
+  grub_efi_guid_t shim_guid = SHIM_LOCK_GUID;
4ce656b
+  SHIM_LOCK *shim = NULL;
4ce656b
+  grub_efi_handle_t *handles, shim_handle = NULL;
4ce656b
+  grub_efi_uintn_t num_handles, i;
4ce656b
+  grub_efi_status_t status;
4ce656b
+
4ce656b
+  if (!grub_is_secure_boot())
4ce656b
+    return GRUB_ERR_NONE;
4ce656b
+
4ce656b
+  handles = grub_efi_locate_handle (GRUB_EFI_BY_PROTOCOL, &shim_guid, NULL,
4ce656b
+				    &num_handles);
4ce656b
+  if (!handles || num_handles == 0)
4ce656b
+no_verify:
4ce656b
+    return grub_error (GRUB_ACCESS_DENIED, "Could not find signature verification routine");
4ce656b
+
4ce656b
+  for (i = 0; i < num_handles; i++)
4ce656b
+    {
4ce656b
+      shim_handle = handles[i];
4ce656b
+      shim = grub_efi_open_protocol (shim_handle, &shim_guid,
4ce656b
+				     GRUB_EFI_OPEN_PROTOCOL_GET_PROTOCOL);
4ce656b
+      if (shim)
4ce656b
+	break;
4ce656b
+    }
4ce656b
+
4ce656b
+  if (!shim)
4ce656b
+    {
4ce656b
+      grub_free(handles);
4ce656b
+      goto no_verify;
4ce656b
+    }
4ce656b
+
4ce656b
+  status = shim->Verify(buffer, size);
4ce656b
+
4ce656b
+  grub_free(handles);
4ce656b
+
4ce656b
+  if (status == GRUB_EFI_SUCCESS)
4ce656b
+    return GRUB_ERR_NONE;
4ce656b
+
4ce656b
+  return grub_error (GRUB_ACCESS_DENIED, "Signature verification failed");
4ce656b
+#else
4ce656b
+  return GRUB_ERR_NONE;
4ce656b
+#endif
4ce656b
+}
4ce656b
+
4ce656b
+grub_err_t
4ce656b
 grub_auth_check_authentication (const char *userlist)
4ce656b
 {
4ce656b
   char login[1024];
4ce656b
diff --git a/grub-core/normal/main.c b/grub-core/normal/main.c
4ce656b
index 193d7d3..1e321a4 100644
4ce656b
--- a/grub-core/normal/main.c
4ce656b
+++ b/grub-core/normal/main.c
4ce656b
@@ -455,7 +455,9 @@ grub_cmdline_run (int nested)
4ce656b
 {
4ce656b
   grub_err_t err = GRUB_ERR_NONE;
4ce656b
 
4ce656b
-  err = grub_auth_check_authentication (NULL);
4ce656b
+  err = grub_auth_secure_boot ();
4ce656b
+  if (err == GRUB_ERR_NONE)
4ce656b
+    err = grub_auth_check_authentication (NULL);
4ce656b
 
4ce656b
   if (err)
4ce656b
     {
4ce656b
diff --git a/grub-core/normal/menu_entry.c b/grub-core/normal/menu_entry.c
4ce656b
index 7fc890d..4e7a08c 100644
4ce656b
--- a/grub-core/normal/menu_entry.c
4ce656b
+++ b/grub-core/normal/menu_entry.c
4ce656b
@@ -1287,7 +1287,10 @@ grub_menu_entry_run (grub_menu_entry_t entry)
4ce656b
   unsigned i;
4ce656b
   grub_term_output_t term;
4ce656b
 
4ce656b
-  err = grub_auth_check_authentication (NULL);
4ce656b
+
4ce656b
+  err = grub_auth_secure_boot ();
4ce656b
+  if (err == GRUB_ERR_NONE)
4ce656b
+    err = grub_auth_check_authentication (NULL);
4ce656b
 
4ce656b
   if (err)
4ce656b
     {
4ce656b
diff --git a/include/grub/auth.h b/include/grub/auth.h
4ce656b
index 7473344..b933fa1 100644
4ce656b
--- a/include/grub/auth.h
4ce656b
+++ b/include/grub/auth.h
4ce656b
@@ -32,6 +32,9 @@ grub_err_t grub_auth_unregister_authentication (const char *user);
4ce656b
 
4ce656b
 grub_err_t grub_auth_authenticate (const char *user);
4ce656b
 grub_err_t grub_auth_deauthenticate (const char *user);
4ce656b
+grub_err_t grub_auth_secure_boot (void);
4ce656b
+int grub_is_secure_boot (void);
4ce656b
+grub_err_t grub_auth_verify_signature (void *buffer, grub_uint32_t size);
4ce656b
 grub_err_t grub_auth_check_authentication (const char *userlist);
4ce656b
 
4ce656b
 #endif /* ! GRUB_AUTH_HEADER */
4ce656b
-- 
4ce656b
1.7.10.2
4ce656b