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