]> git.ipfire.org Git - thirdparty/grub.git/commitdiff
disk/cryptodisk: Add the "erase secrets" function
authorMaxim Suhanov <dfirblog@gmail.com>
Tue, 4 Mar 2025 11:02:25 +0000 (14:02 +0300)
committerDaniel Kiper <daniel.kiper@oracle.com>
Tue, 6 May 2025 15:14:03 +0000 (17:14 +0200)
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 <dfirblog@gmail.com>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
docs/grub.texi
grub-core/commands/minicmd.c
grub-core/disk/cryptodisk.c
include/grub/cryptodisk.h

index 48438c2b6fac5ca551b97c5432c398186a7629e1..cc4acb27eafa1e83b37a6119c7584ce2c9f47fc8 100644 (file)
@@ -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.
index 8c5ee3e6044c8575b517902413fac7d05dd1d36c..ff4ff021c0b4d4f0b6791efa98a60b17ee470df9 100644 (file)
 #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.  */
 }
index 7a785a49cc86222fa4a2772d63c84c18545b7ccd..544a30d61517ce1d3076a9aa35b40747a8b696e4 100644 (file)
@@ -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);
index 5bb15751d9b90a26cb9d6a928643c6255545a2a7..81e631778caea50e55d81871bb9974d102cb333b 100644 (file)
@@ -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