From: Maxim Suhanov <dfirb...@gmail.com>

This commit adds the grub_cryptodisk_erasesecrets() function to wipe
master keys from all cryptodisks. This function is EFI-only.

Since there is no easy way to "force unmount" a given encrypted disk,
this function renders all mounted cryptodisks unusable. An attempt to
read them will return garbage.

This is why this function must be used in "no way back" conditions.

Currently, it is used when unloading the cryptodisk module and when
performing the "exit" command (it is often used to switch to the next
EFI application). This function is not called when performing the
"chainloader" command, because the callee may return to GRUB. For this
reason, users are encouraged to use "exit" instead of "chainloader" to
execute third-party boot applications.

This function does not guarantee that all secrets are wiped from RAM.
Console output, chunks from disk read requests and other may remain.

This function does not clear the IV prefix and rekey key for geli disks.

Also, this commit adds the relevant documentation improvements.

Signed-off-by: Maxim Suhanov <dfirb...@gmail.com>
Reviewed-by: Daniel Kiper <daniel.ki...@oracle.com>
---
 docs/grub.texi               |  6 ++++++
 grub-core/commands/minicmd.c | 11 +++++++++++
 grub-core/disk/cryptodisk.c  | 28 ++++++++++++++++++++++++++++
 include/grub/cryptodisk.h    |  1 +
 4 files changed, 46 insertions(+)

diff --git a/docs/grub.texi b/docs/grub.texi
index 48438c2b6..cc4acb27e 100644
--- a/docs/grub.texi
+++ b/docs/grub.texi
@@ -6788,6 +6788,11 @@ namespace in addition to the cryptodisk namespace.
 
 Support for plain encryption mode (plain dm-crypt) is provided via separate
 @command{@pxref{plainmount}} command.
+
+On the EFI platform, GRUB tries to erase master keys from memory when the 
cryptodisk
+module is unloaded or the command @command{exit} is executed. All secrets 
remain in
+memory when the command @command{chainloader} is issued, because execution can
+return to GRUB on the EFI platform.
 @end deffn
 
 @node cutmem
@@ -9406,6 +9411,7 @@ USB support provides benefits similar to ATA (for USB 
disks) or AT (for USB
 keyboards). In addition it allows USBserial.
 
 Chainloading refers to the ability to load another bootloader through the same 
protocol
+and on some platforms, like EFI, allow that bootloader to return to the GRUB.
 
 Hints allow faster disk discovery by already knowing in advance which is the 
disk in
 question. On some platforms hints are correct unless you move the disk between 
boots.
diff --git a/grub-core/commands/minicmd.c b/grub-core/commands/minicmd.c
index 8c5ee3e60..ff4ff021c 100644
--- a/grub-core/commands/minicmd.c
+++ b/grub-core/commands/minicmd.c
@@ -29,6 +29,10 @@
 #include <grub/command.h>
 #include <grub/i18n.h>
 
+#ifdef GRUB_MACHINE_EFI
+#include <grub/cryptodisk.h>
+#endif
+
 GRUB_MOD_LICENSE ("GPLv3+");
 
 /* cat FILE */
@@ -187,6 +191,13 @@ grub_mini_cmd_exit (struct grub_command *cmd __attribute__ 
((unused)),
                    int argc __attribute__ ((unused)),
                    char *argv[] __attribute__ ((unused)))
 {
+#ifdef GRUB_MACHINE_EFI
+  /*
+   * The "exit" command is often used to launch the next boot application.
+   * So, erase the secrets.
+   */
+  grub_cryptodisk_erasesecrets ();
+#endif
   grub_exit ();
   /* Not reached.  */
 }
diff --git a/grub-core/disk/cryptodisk.c b/grub-core/disk/cryptodisk.c
index 7a785a49c..544a30d61 100644
--- a/grub-core/disk/cryptodisk.c
+++ b/grub-core/disk/cryptodisk.c
@@ -1856,6 +1856,31 @@ grub_cryptodisk_challenge_password (void)
 
   return GRUB_ERR_NONE;
 }
+
+void
+grub_cryptodisk_erasesecrets (void)
+{
+  grub_cryptodisk_t i;
+  grub_uint8_t *buf;
+
+  buf = grub_zalloc (GRUB_CRYPTODISK_MAX_KEYLEN);
+  if (buf == NULL)
+    grub_fatal ("grub_cryptodisk_erasesecrets: cannot allocate memory");
+
+  for (i = cryptodisk_list; i != NULL; i = i->next)
+    if (grub_cryptodisk_setkey (i, buf, i->keysize))
+      grub_fatal ("grub_cryptodisk_erasesecrets: cannot erase secrets for %s", 
i->source);
+    else
+      grub_printf ("Erased crypto secrets for %s\n", i->source);
+      /*
+       * Unfortunately, there is no way to "force unmount" a given disk, it may
+       * have mounted "child" disks as well, e.g., an LVM volume. So, this
+       * function MUST be called when there is no way back, e.g., when exiting.
+       * Otherwise, subsequent read calls for a cryptodisk will return garbage.
+       */
+
+  grub_free (buf);
+}
 #endif /* GRUB_MACHINE_EFI */
 
 struct grub_procfs_entry luks_script =
@@ -1880,6 +1905,9 @@ GRUB_MOD_INIT (cryptodisk)
 
 GRUB_MOD_FINI (cryptodisk)
 {
+#ifdef GRUB_MACHINE_EFI
+  grub_cryptodisk_erasesecrets ();
+#endif
   grub_disk_dev_unregister (&grub_cryptodisk_dev);
   cryptodisk_cleanup ();
   grub_unregister_extcmd (cmd);
diff --git a/include/grub/cryptodisk.h b/include/grub/cryptodisk.h
index 5bb15751d..81e631778 100644
--- a/include/grub/cryptodisk.h
+++ b/include/grub/cryptodisk.h
@@ -205,5 +205,6 @@ grub_cryptodisk_t grub_cryptodisk_get_by_source_disk 
(grub_disk_t disk);
 
 #ifdef GRUB_MACHINE_EFI
 grub_err_t grub_cryptodisk_challenge_password (void);
+void grub_cryptodisk_erasesecrets (void);
 #endif
 #endif
-- 
2.11.0


_______________________________________________
Grub-devel mailing list
Grub-devel@gnu.org
https://lists.gnu.org/mailman/listinfo/grub-devel

Reply via email to