Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package grub2 for openSUSE:Factory checked in at 2025-05-13 20:12:05 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/grub2 (Old) and /work/SRC/openSUSE:Factory/.grub2.new.30101 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "grub2" Tue May 13 20:12:05 2025 rev:361 rq:1276721 version:2.12 Changes: -------- --- /work/SRC/openSUSE:Factory/grub2/grub2.changes 2025-04-29 16:39:54.332993295 +0200 +++ /work/SRC/openSUSE:Factory/.grub2.new.30101/grub2.changes 2025-05-13 20:12:20.124126808 +0200 @@ -1,0 +2,19 @@ +Mon May 5 12:00:12 UTC 2025 - Michael Chang <mch...@suse.com> + +- Fix CVE-2025-4382: TPM auto-decryption data exposure (bsc#1242971) + * 0001-kern-rescue_reader-Block-the-rescue-mode-until-the-C.patch + * 0002-commands-search-Introduce-the-cryptodisk-only-argume.patch + * 0003-disk-diskfilter-Introduce-the-cryptocheck-command.patch + * 0004-commands-search-Add-the-diskfilter-support.patch + * 0005-docs-Document-available-crypto-disks-checks.patch + * 0006-disk-cryptodisk-Add-the-erase-secrets-function.patch + * 0007-disk-cryptodisk-Wipe-the-passphrase-from-memory.patch + * 0008-cryptocheck-Add-quiet-option.patch +- patch rebased + * 0001-Improve-TPM-key-protection-on-boot-interruptions.patch + * 0004-Key-revocation-on-out-of-bound-file-access.patch +- patch refrehed + * 0001-Fix-PowerPC-CAS-reboot-to-evaluate-menu-context.patch + * 0002-Requiring-authentication-after-tpm-unlock-for-CLI-ac.patch + +------------------------------------------------------------------- New: ---- 0001-kern-rescue_reader-Block-the-rescue-mode-until-the-C.patch 0002-commands-search-Introduce-the-cryptodisk-only-argume.patch 0003-disk-diskfilter-Introduce-the-cryptocheck-command.patch 0004-commands-search-Add-the-diskfilter-support.patch 0005-docs-Document-available-crypto-disks-checks.patch 0006-disk-cryptodisk-Add-the-erase-secrets-function.patch 0007-disk-cryptodisk-Wipe-the-passphrase-from-memory.patch 0008-cryptocheck-Add-quiet-option.patch BETA DEBUG BEGIN: New:- Fix CVE-2025-4382: TPM auto-decryption data exposure (bsc#1242971) * 0001-kern-rescue_reader-Block-the-rescue-mode-until-the-C.patch * 0002-commands-search-Introduce-the-cryptodisk-only-argume.patch New: * 0001-kern-rescue_reader-Block-the-rescue-mode-until-the-C.patch * 0002-commands-search-Introduce-the-cryptodisk-only-argume.patch * 0003-disk-diskfilter-Introduce-the-cryptocheck-command.patch New: * 0002-commands-search-Introduce-the-cryptodisk-only-argume.patch * 0003-disk-diskfilter-Introduce-the-cryptocheck-command.patch * 0004-commands-search-Add-the-diskfilter-support.patch New: * 0003-disk-diskfilter-Introduce-the-cryptocheck-command.patch * 0004-commands-search-Add-the-diskfilter-support.patch * 0005-docs-Document-available-crypto-disks-checks.patch New: * 0004-commands-search-Add-the-diskfilter-support.patch * 0005-docs-Document-available-crypto-disks-checks.patch * 0006-disk-cryptodisk-Add-the-erase-secrets-function.patch New: * 0005-docs-Document-available-crypto-disks-checks.patch * 0006-disk-cryptodisk-Add-the-erase-secrets-function.patch * 0007-disk-cryptodisk-Wipe-the-passphrase-from-memory.patch New: * 0006-disk-cryptodisk-Add-the-erase-secrets-function.patch * 0007-disk-cryptodisk-Wipe-the-passphrase-from-memory.patch * 0008-cryptocheck-Add-quiet-option.patch New: * 0007-disk-cryptodisk-Wipe-the-passphrase-from-memory.patch * 0008-cryptocheck-Add-quiet-option.patch - patch rebased BETA DEBUG END: ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ grub2.spec ++++++ --- /var/tmp/diff_new_pack.izAuMX/_old 2025-05-13 20:12:23.980288653 +0200 +++ /var/tmp/diff_new_pack.izAuMX/_new 2025-05-13 20:12:23.980288653 +0200 @@ -375,8 +375,6 @@ Patch189: arm64-Use-proper-memory-type-for-kernel-allocation.patch Patch190: 0001-luks2-Use-grub-tpm2-token-for-TPM2-protected-volume-.patch Patch191: Fix-the-size-calculation-for-the-synthesized-initrd.patch -Patch192: 0001-Improve-TPM-key-protection-on-boot-interruptions.patch -Patch195: 0004-Key-revocation-on-out-of-bound-file-access.patch # Workaround for 2.12 tarball Patch196: fix_no_extra_deps_in_release_tarball.patch Patch197: 0001-fs-xfs-always-verify-the-total-number-of-entries-is-.patch @@ -471,6 +469,16 @@ Patch298: grub2-bls-boot-show-snapshot.patch Patch299: grub2-blscfg-fix-hang.patch Patch300: grub2-blscfg-set-efivars.patch +Patch301: 0001-kern-rescue_reader-Block-the-rescue-mode-until-the-C.patch +Patch302: 0002-commands-search-Introduce-the-cryptodisk-only-argume.patch +Patch303: 0003-disk-diskfilter-Introduce-the-cryptocheck-command.patch +Patch304: 0004-commands-search-Add-the-diskfilter-support.patch +Patch305: 0005-docs-Document-available-crypto-disks-checks.patch +Patch306: 0006-disk-cryptodisk-Add-the-erase-secrets-function.patch +Patch307: 0007-disk-cryptodisk-Wipe-the-passphrase-from-memory.patch +Patch308: 0008-cryptocheck-Add-quiet-option.patch +Patch309: 0001-Improve-TPM-key-protection-on-boot-interruptions.patch +Patch310: 0004-Key-revocation-on-out-of-bound-file-access.patch %if 0%{?suse_version} < 1600 Requires: gettext-runtime ++++++ 0001-Fix-PowerPC-CAS-reboot-to-evaluate-menu-context.patch ++++++ --- /var/tmp/diff_new_pack.izAuMX/_old 2025-05-13 20:12:24.020290332 +0200 +++ /var/tmp/diff_new_pack.izAuMX/_new 2025-05-13 20:12:24.024290499 +0200 @@ -43,11 +43,9 @@ grub-core/script/execute.c | 7 ---- 4 files changed, 154 insertions(+), 28 deletions(-) -diff --git a/grub-core/normal/main.c b/grub-core/normal/main.c -index c9eda889ca..091450e53c 100644 --- a/grub-core/normal/main.c +++ b/grub-core/normal/main.c -@@ -365,21 +365,6 @@ grub_normal_execute (const char *config, int nested, int batch) +@@ -365,21 +365,6 @@ { menu = read_config_file (config); @@ -69,16 +67,15 @@ /* Ignore any error. */ grub_errno = GRUB_ERR_NONE; } -@@ -393,7 +378,50 @@ grub_normal_execute (const char *config, int nested, int batch) +@@ -393,7 +378,50 @@ { if (menu && menu->size) { -- +#ifdef GRUB_MACHINE_IEEE1275 + char *entry_id = NULL; + char *delim; + const char *chosen; -+ + + if (grub_ieee1275_cas_reboot (&entry_id) != 0) + goto enter_menu; + @@ -121,21 +118,19 @@ grub_boot_time ("Entering menu"); grub_show_menu (menu, nested, 0); if (nested) -diff --git a/grub-core/normal/menu.c b/grub-core/normal/menu.c -index dfdf0c7268..897da6abac 100644 --- a/grub-core/normal/menu.c +++ b/grub-core/normal/menu.c -@@ -33,6 +33,9 @@ +@@ -32,6 +32,9 @@ + #include <grub/script_sh.h> #include <grub/gfxterm.h> #include <grub/dl.h> - #include <grub/crypttab.h> +#ifdef GRUB_MACHINE_IEEE1275 +#include <grub/ieee1275/ieee1275.h> +#endif /* Time to delay after displaying an error message about a default/fallback entry failing to boot. */ -@@ -318,8 +321,31 @@ grub_menu_execute_entry(grub_menu_entry_t entry, int auto_boot) +@@ -317,8 +320,31 @@ grub_env_set ("default", ptr + 1); else grub_env_unset ("default"); @@ -167,7 +162,7 @@ if (errs_before != grub_err_printed_errors) grub_wait_after_message (); -@@ -327,8 +353,23 @@ grub_menu_execute_entry(grub_menu_entry_t entry, int auto_boot) +@@ -326,8 +352,23 @@ errs_before = grub_err_printed_errors; if (grub_errno == GRUB_ERR_NONE && grub_loader_is_loaded ()) @@ -193,8 +188,6 @@ if (errs_before != grub_err_printed_errors) grub_wait_after_message (); -diff --git a/grub-core/normal/menu_entry.c b/grub-core/normal/menu_entry.c -index 06682a396d..bbd05e5638 100644 --- a/grub-core/normal/menu_entry.c +++ b/grub-core/normal/menu_entry.c @@ -29,6 +29,9 @@ @@ -207,7 +200,7 @@ enum update_mode { -@@ -78,6 +81,9 @@ struct screen +@@ -78,6 +81,9 @@ int completion_shown; int submenu; @@ -217,7 +210,7 @@ struct per_term_screen *terms; unsigned nterms; -@@ -578,6 +584,9 @@ destroy_screen (struct screen *screen) +@@ -578,6 +584,9 @@ grub_free (screen->killed_text); grub_free (screen->lines); grub_free (screen->terms); @@ -227,7 +220,7 @@ grub_free (screen); } -@@ -599,6 +608,11 @@ make_screen (grub_menu_entry_t entry) +@@ -599,6 +608,11 @@ screen->lines = grub_malloc (sizeof (struct line)); if (! screen->lines) goto fail; @@ -239,7 +232,7 @@ /* Initialize the first line which must be always present. */ if (! init_line (screen, screen->lines)) -@@ -1215,14 +1229,64 @@ run (struct screen *screen) +@@ -1215,14 +1229,64 @@ script[size] = '\0'; } grub_script_execute_new_scope (script, 0, dummy); @@ -307,8 +300,6 @@ if (screen->submenu) { -diff --git a/grub-core/script/execute.c b/grub-core/script/execute.c -index dab8fd2aeb..14ff09094f 100644 --- a/grub-core/script/execute.c +++ b/grub-core/script/execute.c @@ -28,9 +28,6 @@ @@ -321,7 +312,7 @@ /* Max digits for a char is 3 (0xFF is 255), similarly for an int it is sizeof (int) * 3, and one extra for a possible -ve sign. */ -@@ -886,10 +883,6 @@ grub_script_execute_sourcecode (const char *source) +@@ -886,10 +883,6 @@ grub_err_t ret = 0; struct grub_script *parsed_script; @@ -332,7 +323,4 @@ while (source) { char *line; --- -2.49.0 - ++++++ 0001-Improve-TPM-key-protection-on-boot-interruptions.patch ++++++ --- /var/tmp/diff_new_pack.izAuMX/_old 2025-05-13 20:12:24.036291003 +0200 +++ /var/tmp/diff_new_pack.izAuMX/_new 2025-05-13 20:12:24.044291339 +0200 @@ -1,7 +1,7 @@ -From 27b3e919b9b51a4fedeb3a5aef19c87f0cd7b687 Mon Sep 17 00:00:00 2001 +From 7b6cdb8ff71e43f95de9cefc19a7949e924c2be9 Mon Sep 17 00:00:00 2001 From: Michael Chang <mch...@suse.com> Date: Fri, 17 Nov 2023 12:32:59 +0800 -Subject: [PATCH] Improve TPM key protection on boot interruptions +Subject: [PATCH 1/2] Improve TPM key protection on boot interruptions The unattended boot process for full disk encryption relies on an authorized TPM policy to ensure the system's integrity before releasing @@ -25,19 +25,21 @@ protection of TPM keys, thereby ensuring a more robust defense against potential unauthorized modifications during the boot process. +v2: erase cached credentials in grub_cryptodisk_erasesecrets + Signed-Off-by Michael Chang <mch...@suse.com> --- grub-core/commands/crypttab.c | 38 ++++++++++++++++++++++++++--------- - grub-core/disk/cryptodisk.c | 8 +++++++- + grub-core/disk/cryptodisk.c | 10 ++++++++- grub-core/loader/linux.c | 6 +++--- grub-core/normal/main.c | 2 +- grub-core/normal/menu.c | 7 +++++++ grub-core/normal/menu_entry.c | 2 +- include/grub/crypttab.h | 18 ++++++++++------- - 7 files changed, 59 insertions(+), 22 deletions(-) + 7 files changed, 61 insertions(+), 22 deletions(-) diff --git a/grub-core/commands/crypttab.c b/grub-core/commands/crypttab.c -index c2217ca98..9397bede9 100644 +index c2217ca980..9397bede9e 100644 --- a/grub-core/commands/crypttab.c +++ b/grub-core/commands/crypttab.c @@ -9,17 +9,20 @@ @@ -125,7 +127,7 @@ static grub_command_t cmd; diff --git a/grub-core/disk/cryptodisk.c b/grub-core/disk/cryptodisk.c -index aa0d43562..babc94868 100644 +index cb87d337ac..5fd68f4549 100644 --- a/grub-core/disk/cryptodisk.c +++ b/grub-core/disk/cryptodisk.c @@ -1071,6 +1071,9 @@ grub_cryptodisk_scan_device_real (const char *name, @@ -138,17 +140,15 @@ dev = grub_cryptodisk_get_by_source_disk (source); -@@ -1183,6 +1186,9 @@ grub_cryptodisk_scan_device_real (const char *name, - ret = grub_cryptodisk_insert (dev, name, source); - if (ret != GRUB_ERR_NONE) +@@ -1185,6 +1188,7 @@ grub_cryptodisk_scan_device_real (const char *name, goto error; -+#ifndef GRUB_UTIL + #ifndef GRUB_UTIL + grub_cli_set_auth_needed (); + is_tpmkey = 1; -+#endif + #endif goto cleanup; } - } -@@ -1244,7 +1250,7 @@ grub_cryptodisk_scan_device_real (const char *name, +@@ -1247,7 +1251,7 @@ grub_cryptodisk_scan_device_real (const char *name, #ifndef GRUB_UTIL if (cargs->key_data && dev) @@ -157,8 +157,19 @@ #endif if (askpass) { +@@ -1792,6 +1796,10 @@ grub_cryptodisk_erasesecrets (void) + grub_cryptodisk_t i; + grub_uint8_t *buf; + ++#ifndef GRUB_UTIL ++ grub_cryptokey_discard (); ++#endif ++ + buf = grub_zalloc (GRUB_CRYPTODISK_MAX_KEYLEN); + if (buf == NULL) + grub_fatal ("grub_cryptodisk_erasesecrets: cannot allocate memory"); diff --git a/grub-core/loader/linux.c b/grub-core/loader/linux.c -index 9ee8f3790..e5e792958 100644 +index 9ee8f37907..e5e7929581 100644 --- a/grub-core/loader/linux.c +++ b/grub-core/loader/linux.c @@ -226,13 +226,13 @@ grub_initrd_init (int argc, char *argv[], @@ -187,10 +198,10 @@ { grub_initrd_component (pk->key, pk->key_len, pk->path, initrd_ctx); diff --git a/grub-core/normal/main.c b/grub-core/normal/main.c -index a3f711d1d..1b426af69 100644 +index 320adbe337..343cdbae2c 100644 --- a/grub-core/normal/main.c +++ b/grub-core/normal/main.c -@@ -479,7 +479,7 @@ grub_cmdline_run (int nested, int force_auth) +@@ -599,7 +599,7 @@ grub_cmdline_run (int nested, int force_auth) return; } @@ -200,7 +211,7 @@ while (1) diff --git a/grub-core/normal/menu.c b/grub-core/normal/menu.c -index 14b0ab1ec..1df2638d7 100644 +index f243c5e0bd..897da6abac 100644 --- a/grub-core/normal/menu.c +++ b/grub-core/normal/menu.c @@ -32,6 +32,7 @@ @@ -208,10 +219,10 @@ #include <grub/gfxterm.h> #include <grub/dl.h> +#include <grub/crypttab.h> - - /* Time to delay after displaying an error message about a default/fallback - entry failing to boot. */ -@@ -708,6 +709,7 @@ run_menu (grub_menu_t menu, int nested, int *auto_boot, int *notify_boot) + #ifdef GRUB_MACHINE_IEEE1275 + #include <grub/ieee1275/ieee1275.h> + #endif +@@ -769,6 +770,7 @@ run_menu (grub_menu_t menu, int nested, int *auto_boot, int *notify_boot) if (grub_key_is_interrupt (key)) { timeout = -1; @@ -219,7 +230,7 @@ break; } -@@ -790,6 +792,11 @@ run_menu (grub_menu_t menu, int nested, int *auto_boot, int *notify_boot) +@@ -851,6 +853,11 @@ run_menu (grub_menu_t menu, int nested, int *auto_boot, int *notify_boot) clear_timeout (); } @@ -232,10 +243,10 @@ { case GRUB_TERM_KEY_HOME: diff --git a/grub-core/normal/menu_entry.c b/grub-core/normal/menu_entry.c -index 384ab9ce3..e5ba91ea4 100644 +index 38c958e657..bbd05e5638 100644 --- a/grub-core/normal/menu_entry.c +++ b/grub-core/normal/menu_entry.c -@@ -1263,7 +1263,7 @@ grub_menu_entry_run (grub_menu_entry_t entry) +@@ -1331,7 +1331,7 @@ grub_menu_entry_run (grub_menu_entry_t entry) return; } @@ -245,7 +256,7 @@ screen = make_screen (entry); if (! screen) diff --git a/include/grub/crypttab.h b/include/grub/crypttab.h -index 113c53cfc..f86404686 100644 +index 113c53cfce..f86404686f 100644 --- a/include/grub/crypttab.h +++ b/include/grub/crypttab.h @@ -4,21 +4,25 @@ @@ -282,6 +293,6 @@ +grub_cryptokey_tpmkey_discard (void); #endif /* ! GRUB_CRYPTTAB_HEADER */ -- -2.35.3 +2.49.0 ++++++ 0001-kern-rescue_reader-Block-the-rescue-mode-until-the-C.patch ++++++ >From 4f45e963ea913000fd8e3fe20f9afb3722073cea Mon Sep 17 00:00:00 2001 From: Maxim Suhanov <dfirb...@gmail.com> Date: Thu, 8 May 2025 19:02:07 +0200 Subject: [PATCH 1/8] kern/rescue_reader: Block the rescue mode until the CLI authentication This further mitigates potential misuse of the CLI after the root device has been successfully unlocked via TPM. Fixes: CVE-2025-4382 Signed-off-by: Maxim Suhanov <dfirb...@gmail.com> Reviewed-by: Daniel Kiper <daniel.ki...@oracle.com> --- grub-core/kern/rescue_reader.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/grub-core/kern/rescue_reader.c b/grub-core/kern/rescue_reader.c index 4259857ba9..a71ada8fb7 100644 --- a/grub-core/kern/rescue_reader.c +++ b/grub-core/kern/rescue_reader.c @@ -79,7 +79,7 @@ void __attribute__ ((noreturn)) grub_rescue_run (void) { /* Stall if the CLI has been disabled */ - if (grub_is_cli_disabled ()) + if (grub_is_cli_disabled () || grub_is_cli_need_auth ()) { grub_printf ("Rescue mode has been disabled...\n"); -- 2.49.0 ++++++ 0002-Requiring-authentication-after-tpm-unlock-for-CLI-ac.patch ++++++ --- /var/tmp/diff_new_pack.izAuMX/_old 2025-05-13 20:12:24.240299565 +0200 +++ /var/tmp/diff_new_pack.izAuMX/_new 2025-05-13 20:12:24.244299733 +0200 @@ -38,19 +38,19 @@ include/grub/misc.h | 2 + 8 files changed, 140 insertions(+) -diff --git a/grub-core/disk/cryptodisk.c b/grub-core/disk/cryptodisk.c -index babc94868d..21bf22ead1 100644 --- a/grub-core/disk/cryptodisk.c +++ b/grub-core/disk/cryptodisk.c -@@ -1188,6 +1188,7 @@ grub_cryptodisk_scan_device_real (const char *name, +@@ -1183,6 +1183,9 @@ + ret = grub_cryptodisk_insert (dev, name, source); + if (ret != GRUB_ERR_NONE) goto error; - #ifndef GRUB_UTIL - is_tpmkey = 1; ++#ifndef GRUB_UTIL + grub_cli_set_auth_needed (); - #endif ++#endif goto cleanup; } -@@ -1706,6 +1707,89 @@ luks_script_get (grub_size_t *sz) + } +@@ -1700,6 +1703,89 @@ return ret; } @@ -140,8 +140,6 @@ struct grub_procfs_entry luks_script = { .name = "luks_script", -diff --git a/grub-core/kern/main.c b/grub-core/kern/main.c -index 07b6940d2e..ef3b3756de 100644 --- a/grub-core/kern/main.c +++ b/grub-core/kern/main.c @@ -37,6 +37,7 @@ @@ -152,7 +150,7 @@ grub_addr_t grub_modules_get_end (void) -@@ -246,6 +247,17 @@ grub_is_cli_disabled (void) +@@ -246,6 +247,17 @@ return cli_disabled; } @@ -170,8 +168,6 @@ static void check_is_cli_disabled (void) { -diff --git a/grub-core/normal/auth.c b/grub-core/normal/auth.c -index d940201866..2931ba604a 100644 --- a/grub-core/normal/auth.c +++ b/grub-core/normal/auth.c @@ -25,6 +25,10 @@ @@ -185,11 +181,10 @@ struct grub_auth_user { struct grub_auth_user *next; -@@ -200,6 +204,32 @@ grub_username_get (char buf[], unsigned buf_size) - return (key != GRUB_TERM_ESC); +@@ -201,6 +205,32 @@ } -+grub_err_t + grub_err_t +grub_auth_check_cli_access (void) +{ + if (grub_is_cli_need_auth () == true) @@ -211,18 +206,17 @@ + return GRUB_ACCESS_DENIED; +#endif + } -+ ++ + return GRUB_ERR_NONE; +} + - grub_err_t ++grub_err_t grub_auth_check_authentication (const char *userlist) { -diff --git a/grub-core/normal/main.c b/grub-core/normal/main.c -index 8e58ced679..b08fd6977d 100644 + char login[1024]; --- a/grub-core/normal/main.c +++ b/grub-core/normal/main.c -@@ -560,9 +560,13 @@ grub_cmdline_run (int nested, int force_auth) +@@ -560,9 +560,13 @@ } while (err && force_auth); @@ -236,11 +230,9 @@ grub_errno = GRUB_ERR_NONE; return; } -diff --git a/grub-core/normal/menu_entry.c b/grub-core/normal/menu_entry.c -index e5ba91ea4d..06682a396d 100644 --- a/grub-core/normal/menu_entry.c +++ b/grub-core/normal/menu_entry.c -@@ -1256,9 +1256,13 @@ grub_menu_entry_run (grub_menu_entry_t entry) +@@ -1256,9 +1256,13 @@ err = grub_auth_check_authentication (NULL); @@ -254,22 +246,18 @@ grub_errno = GRUB_ERR_NONE; return; } -diff --git a/include/grub/auth.h b/include/grub/auth.h -index 7473344517..21d5190f04 100644 --- a/include/grub/auth.h +++ b/include/grub/auth.h -@@ -33,5 +33,6 @@ grub_err_t grub_auth_unregister_authentication (const char *user); +@@ -33,5 +33,6 @@ grub_err_t grub_auth_authenticate (const char *user); grub_err_t grub_auth_deauthenticate (const char *user); grub_err_t grub_auth_check_authentication (const char *userlist); +grub_err_t grub_auth_check_cli_access (void); #endif /* ! GRUB_AUTH_HEADER */ -diff --git a/include/grub/cryptodisk.h b/include/grub/cryptodisk.h -index 0b41e249e8..b3291519b1 100644 --- a/include/grub/cryptodisk.h +++ b/include/grub/cryptodisk.h -@@ -203,4 +203,7 @@ grub_util_get_geli_uuid (const char *dev); +@@ -203,4 +203,7 @@ grub_cryptodisk_t grub_cryptodisk_get_by_uuid (const char *uuid); grub_cryptodisk_t grub_cryptodisk_get_by_source_disk (grub_disk_t disk); @@ -277,11 +265,9 @@ +grub_err_t grub_cryptodisk_challenge_password (void); +#endif #endif -diff --git a/include/grub/misc.h b/include/grub/misc.h -index 1578f36c3c..6e94d18f5a 100644 --- a/include/grub/misc.h +++ b/include/grub/misc.h -@@ -392,6 +392,8 @@ grub_uint64_t EXPORT_FUNC(grub_divmod64) (grub_uint64_t n, +@@ -392,6 +392,8 @@ grub_uint64_t *r); extern bool EXPORT_FUNC(grub_is_cli_disabled) (void); @@ -290,7 +276,4 @@ /* Must match softdiv group in gentpl.py. */ #if !defined(GRUB_MACHINE_EMU) && (defined(__arm__) || defined(__ia64__) || \ --- -2.47.1 - ++++++ 0002-commands-search-Introduce-the-cryptodisk-only-argume.patch ++++++ >From 9ad07efefe389568c2cedc77a4a6b48cb830dc0a Mon Sep 17 00:00:00 2001 From: Maxim Suhanov <dfirb...@gmail.com> Date: Thu, 8 May 2025 19:02:08 +0200 Subject: [PATCH 2/8] commands/search: Introduce the --cryptodisk-only argument This allows users to restrict the "search" command's scope to encrypted disks only. Typically, this command is used to "rebase" $root and $prefix before loading additional configuration files via "source" or "configfile". Unfortunately, this leads to security problems, like CVE-2023-4001, when an unexpected, attacker-controlled device is chosen by the "search" command. The --cryptodisk-only argument allows users to ensure that the file system picked is encrypted. This feature supports the CLI authentication, blocking bypass attempts. Signed-off-by: Maxim Suhanov <dfirb...@gmail.com> Reviewed-by: Daniel Kiper <daniel.ki...@oracle.com> --- grub-core/commands/search.c | 20 ++++++++++++++++++++ grub-core/commands/search_wrap.c | 7 ++++++- grub-core/normal/main.c | 3 ++- include/grub/search.h | 7 ++++--- 4 files changed, 32 insertions(+), 5 deletions(-) diff --git a/grub-core/commands/search.c b/grub-core/commands/search.c index 263f1501cd..f6bfef9585 100644 --- a/grub-core/commands/search.c +++ b/grub-core/commands/search.c @@ -86,6 +86,26 @@ iterate_device (const char *name, void *data) grub_device_close (dev); } + /* Limit to encrypted disks when requested. */ + if (ctx->flags & SEARCH_FLAGS_CRYPTODISK_ONLY) + { + grub_device_t dev; + + dev = grub_device_open (name); + if (dev == NULL) + { + grub_errno = GRUB_ERR_NONE; + return 0; + } + if (dev->disk == NULL || dev->disk->dev->id != GRUB_DISK_DEVICE_CRYPTODISK_ID) + { + grub_device_close (dev); + grub_errno = GRUB_ERR_NONE; + return 0; + } + grub_device_close (dev); + } + #ifdef DO_SEARCH_FS_UUID #define compare_fn grub_strcasecmp #else diff --git a/grub-core/commands/search_wrap.c b/grub-core/commands/search_wrap.c index 318581f3b1..5f536006cf 100644 --- a/grub-core/commands/search_wrap.c +++ b/grub-core/commands/search_wrap.c @@ -41,6 +41,7 @@ static const struct grub_arg_option options[] = ARG_TYPE_STRING}, {"no-floppy", 'n', 0, N_("Do not probe any floppy drive."), 0, 0}, {"efidisk-only", 0, 0, N_("Only probe EFI disks."), 0, 0}, + {"cryptodisk-only", 0, 0, N_("Only probe encrypted disks."), 0, 0}, {"hint", 'h', GRUB_ARG_OPTION_REPEATABLE, N_("First try the device HINT. If HINT ends in comma, " "also try subpartitions"), N_("HINT"), ARG_TYPE_STRING}, @@ -75,6 +76,7 @@ enum options SEARCH_SET, SEARCH_NO_FLOPPY, SEARCH_EFIDISK_ONLY, + SEARCH_CRYPTODISK_ONLY, SEARCH_HINT, SEARCH_HINT_IEEE1275, SEARCH_HINT_BIOS, @@ -189,6 +191,9 @@ grub_cmd_search (grub_extcmd_context_t ctxt, int argc, char **args) if (state[SEARCH_EFIDISK_ONLY].set) flags |= SEARCH_FLAGS_EFIDISK_ONLY; + if (state[SEARCH_CRYPTODISK_ONLY].set) + flags |= SEARCH_FLAGS_CRYPTODISK_ONLY; + if (state[SEARCH_LABEL].set) grub_search_label (id, var, flags, hints, nhints); else if (state[SEARCH_FS_UUID].set) @@ -210,7 +215,7 @@ GRUB_MOD_INIT(search) cmd = grub_register_extcmd ("search", grub_cmd_search, GRUB_COMMAND_FLAG_EXTRACTOR | GRUB_COMMAND_ACCEPT_DASH, - N_("[-f|-l|-u|-s|-n] [--hint HINT [--hint HINT] ...]" + N_("[-f|-l|-u|-s|-n] [--cryptodisk-only] [--hint HINT [--hint HINT] ...]" " NAME"), N_("Search devices by file, filesystem label" " or filesystem UUID." diff --git a/grub-core/normal/main.c b/grub-core/normal/main.c index d1cbaa1806..320adbe337 100644 --- a/grub-core/normal/main.c +++ b/grub-core/normal/main.c @@ -647,7 +647,8 @@ static const char *features[] = { "feature_chainloader_bpb", "feature_ntldr", "feature_platform_search_hint", "feature_default_font_path", "feature_all_video_module", "feature_menuentry_id", "feature_menuentry_options", "feature_200_final", - "feature_nativedisk_cmd", "feature_timeout_style" + "feature_nativedisk_cmd", "feature_timeout_style", + "feature_search_cryptodisk_only" }; GRUB_MOD_INIT(normal) diff --git a/include/grub/search.h b/include/grub/search.h index ffd2411ca1..3eabaf0ccd 100644 --- a/include/grub/search.h +++ b/include/grub/search.h @@ -21,9 +21,10 @@ enum search_flags { - SEARCH_FLAGS_NONE = 0, - SEARCH_FLAGS_NO_FLOPPY = 1, - SEARCH_FLAGS_EFIDISK_ONLY = 2 + SEARCH_FLAGS_NONE = 0, + SEARCH_FLAGS_NO_FLOPPY = 1, + SEARCH_FLAGS_EFIDISK_ONLY = 2, + SEARCH_FLAGS_CRYPTODISK_ONLY = 4 }; void grub_search_fs_file (const char *key, const char *var, -- 2.49.0 ++++++ 0003-disk-diskfilter-Introduce-the-cryptocheck-command.patch ++++++ >From 781d736bd5d0004c705d73b0348b154d8ab838cf Mon Sep 17 00:00:00 2001 From: Maxim Suhanov <dfirb...@gmail.com> Date: Thu, 8 May 2025 19:02:09 +0200 Subject: [PATCH 3/8] disk/diskfilter: Introduce the "cryptocheck" command This command examines a given diskfilter device, e.g., an LVM disk, and checks if underlying disks, physical volumes, are cryptodisks, e.g., LUKS disks, this layout is called "LVM-on-LUKS". The return value is 0 when all underlying disks (of a given device) are cryptodisks (1 if at least one disk is unencrypted or in an unknown state). Users are encouraged to include the relevant check before loading anything from an LVM disk that is supposed to be encrypted. This further supports the CLI authentication, blocking bypass attempts when booting from an encrypted LVM disk. Signed-off-by: Maxim Suhanov <dfirb...@gmail.com> Reviewed-by: Daniel Kiper <daniel.ki...@oracle.com> --- grub-core/disk/diskfilter.c | 75 +++++++++++++++++++++++++++++++++++++ 1 file changed, 75 insertions(+) diff --git a/grub-core/disk/diskfilter.c b/grub-core/disk/diskfilter.c index c45bef1caf..3f7c05e14e 100644 --- a/grub-core/disk/diskfilter.c +++ b/grub-core/disk/diskfilter.c @@ -20,6 +20,7 @@ #include <grub/dl.h> #include <grub/disk.h> #include <grub/mm.h> +#include <grub/command.h> #include <grub/err.h> #include <grub/misc.h> #include <grub/diskfilter.h> @@ -1487,6 +1488,73 @@ grub_diskfilter_get_pv_from_disk (grub_disk_t disk, } #endif +static int +grub_diskfilter_check_pvs_encrypted (grub_disk_t disk, int *pvs_cnt) +{ + struct grub_diskfilter_lv *lv = disk->data; + struct grub_diskfilter_pv *pv; + + *pvs_cnt = 0; + + if (lv->vg->pvs) + for (pv = lv->vg->pvs; pv; pv = pv->next) + { + (*pvs_cnt)++; + + if (pv->disk == NULL) + { + /* Can be a partially activated VG, bail out. */ + return GRUB_ERR_TEST_FAILURE; + } + + if (pv->disk->dev->id != GRUB_DISK_DEVICE_CRYPTODISK_ID) + { + /* All backing devices must be cryptodisks, stop. */ + return GRUB_ERR_TEST_FAILURE; + } + } + return GRUB_ERR_NONE; +} + +static grub_err_t +grub_cmd_cryptocheck (grub_command_t cmd __attribute__ ((unused)), + int argc, char **args) +{ + grub_disk_t disk; + int check_pvs_res; + int namelen; + int pvs_cnt; + + if (argc != 1) + return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("disk name expected")); + + namelen = grub_strlen (args[0]); + if (namelen > 2 && (args[0][0] == '(') && (args[0][namelen - 1] == ')')) + args[0][namelen - 1] = 0; + else + return grub_error (GRUB_ERR_UNKNOWN_DEVICE, N_("invalid disk: %s"), + args[0]); + + if (!is_valid_diskfilter_name (&args[0][1])) + return grub_error (GRUB_ERR_UNKNOWN_DEVICE, N_("unrecognized disk: %s"), + &args[0][1]); + + disk = grub_disk_open (&args[0][1]); + if (disk == NULL) + return grub_error (GRUB_ERR_UNKNOWN_DEVICE, N_("no such disk: %s"), + &args[0][1]); + + check_pvs_res = grub_diskfilter_check_pvs_encrypted (disk, &pvs_cnt); + grub_disk_close (disk); + + grub_printf("%s is %sencrypted (%d pv%s examined)\n", &args[0][1], + (check_pvs_res == GRUB_ERR_NONE) ? "" : "un", + pvs_cnt, + (pvs_cnt > 1) ? "s" : ""); + + return check_pvs_res; +} + static struct grub_disk_dev grub_diskfilter_dev = { .name = "diskfilter", @@ -1503,14 +1571,21 @@ static struct grub_disk_dev grub_diskfilter_dev = .next = 0 }; +static grub_command_t cmd; + GRUB_MOD_INIT(diskfilter) { grub_disk_dev_register (&grub_diskfilter_dev); + cmd = grub_register_command ("cryptocheck", grub_cmd_cryptocheck, + N_("DEVICE"), + N_("Check if a logical volume resides on encrypted disks.")); } GRUB_MOD_FINI(diskfilter) { grub_disk_dev_unregister (&grub_diskfilter_dev); + if (cmd != NULL) + grub_unregister_command (cmd); free_array (); } -- 2.49.0 ++++++ 0004-Key-revocation-on-out-of-bound-file-access.patch ++++++ --- /var/tmp/diff_new_pack.izAuMX/_old 2025-05-13 20:12:24.344303930 +0200 +++ /var/tmp/diff_new_pack.izAuMX/_new 2025-05-13 20:12:24.348304098 +0200 @@ -1,7 +1,7 @@ -From 6547d22fc9e20720d1a896be82b2d50d842f86b0 Mon Sep 17 00:00:00 2001 +From 977f8c63d9d85fd101e989310ac0ba011f252df1 Mon Sep 17 00:00:00 2001 From: Michael Chang <mch...@suse.com> Date: Mon, 20 Nov 2023 09:25:53 +0800 -Subject: [PATCH 4/4] Key revocation on out of bound file access +Subject: [PATCH 2/2] Key revocation on out of bound file access After successful disk unlocking, grub now takes on the responsibility of safeguarding passwords or TPM keys exclusively within authenticated @@ -14,15 +14,23 @@ and procfs, ensuring key protection against potential breaches due to inadvertent customizations in grub.cfg. -Signed-Off-by Michael Chang <mch...@suse.com> +v2: use cryptocheck command +The grub_disk_is_crypto() function duplicates the purpose of the +cryptocheck command and is therefore removed. A new check function now +calls cryptocheck directly to improve code reuse. + +Signed-Off-by: Michael Chang <mch...@suse.com> --- - grub-core/commands/crypttab.c | 36 +++++++++++++++++++++++++++++++++++ + grub-core/commands/crypttab.c | 76 +++++++++++++++++++++++++++++++++++ + grub-core/disk/diskfilter.c | 1 + include/grub/file.h | 1 + - 2 files changed, 37 insertions(+) + 3 files changed, 78 insertions(+) +diff --git a/grub-core/commands/crypttab.c b/grub-core/commands/crypttab.c +index 9397bede9e..f104154e23 100644 --- a/grub-core/commands/crypttab.c +++ b/grub-core/commands/crypttab.c -@@ -6,6 +6,7 @@ +@@ -6,11 +6,47 @@ #include <grub/mm.h> #include <grub/list.h> #include <grub/crypttab.h> @@ -30,7 +38,47 @@ GRUB_MOD_LICENSE ("GPLv3+"); -@@ -89,6 +90,41 @@ + grub_crypto_key_list_t *cryptokey_lst; + ++static int ++is_unencrypted_disk (grub_disk_t disk) ++{ ++ grub_command_t cmd; ++ char *disk_str; ++ int disk_str_len; ++ int res; ++ ++ if (disk->dev->id == GRUB_DISK_DEVICE_CRYPTODISK_ID) ++ return 0; /* This is (crypto*) disk */ ++ ++ if (disk->dev->id == GRUB_DISK_DEVICE_DISKFILTER_ID) ++ { ++ char opt[] = "--quiet"; ++ char *args[2]; ++ ++ cmd = grub_command_find ("cryptocheck"); ++ if (!cmd) /* No diskfilter module loaded for some reason */ ++ return 1; ++ ++ disk_str_len = grub_strlen (disk->name) + 2 + 1; ++ disk_str = grub_malloc (disk_str_len); ++ if (!disk_str) /* Something is wrong, better report as unencrypted */ ++ return 1; ++ ++ grub_snprintf (disk_str, disk_str_len, "(%s)", disk->name); ++ args[0] = opt; ++ args[1] = disk_str; ++ res = cmd->func (cmd, 2, args); ++ grub_free (disk_str); ++ return (res != GRUB_ERR_NONE); /* GRUB_ERR_NONE for encrypted */ ++ } ++ return 1; ++} ++ + grub_err_t + grub_cryptokey_add_or_update (const char *uuid, const char *key, grub_size_t key_len, const char *path, int is_tpmkey) + { +@@ -89,6 +125,44 @@ grub_cryptokey_tpmkey_discard (void) grub_cryptokey_discard(); } @@ -59,8 +107,11 @@ + case GRUB_FILE_TYPE_LINUX_INITRD: + case GRUB_FILE_TYPE_LOADENV: + case GRUB_FILE_TYPE_THEME: -+ if (!disk || !grub_disk_is_crypto (disk)) -+ grub_cryptokey_discard (); ++ if (!disk || is_unencrypted_disk (disk)) ++ { ++ grub_cryptokey_discard (); ++ grub_errno = GRUB_ERR_NONE; ++ } + break; + default: + break; @@ -72,7 +123,7 @@ static grub_err_t grub_cmd_crypttab_entry (grub_command_t cmd __attribute__ ((unused)), int argc, char **argv) -@@ -121,6 +157,8 @@ +@@ -121,6 +195,8 @@ GRUB_MOD_INIT(crypttab) { cmd = grub_register_command ("crypttab_entry", grub_cmd_crypttab_entry, N_("VOLUME-NAME ENCRYPTED-DEVICE KEY-FILE") , N_("No description")); @@ -81,89 +132,31 @@ } GRUB_MOD_FINI(crypttab) ---- a/include/grub/file.h -+++ b/include/grub/file.h -@@ -185,6 +185,7 @@ - /* Filters with lower ID are executed first. */ - typedef enum grub_file_filter_id - { -+ GRUB_FILE_FILTER_DISTRUST, - GRUB_FILE_FILTER_VERIFY, - GRUB_FILE_FILTER_GZIO, - GRUB_FILE_FILTER_XZIO, +diff --git a/grub-core/disk/diskfilter.c b/grub-core/disk/diskfilter.c +index b1d5d464f5..e23215486d 100644 --- a/grub-core/disk/diskfilter.c +++ b/grub-core/disk/diskfilter.c -@@ -558,6 +558,39 @@ - return NULL; - } - -+static int -+grub_diskfilter_has_cryptodisk (const struct grub_diskfilter_lv *lv) -+{ -+ struct grub_diskfilter_pv *pv; -+ -+ if (!lv) -+ return 0; -+ -+ if (lv->vg->pvs) -+ for (pv = lv->vg->pvs; pv; pv = pv->next) -+ { -+ if (!pv->disk) -+ { -+ grub_dprintf ("diskfilter", _("Couldn't find physical volume `%s'." -+ " Some modules may be missing from core image."), -+ pv->name); -+ continue; -+ } -+ -+ switch (pv->disk->dev->id) -+ { -+ case GRUB_DISK_DEVICE_CRYPTODISK_ID: -+ return 1; -+ case GRUB_DISK_DEVICE_DISKFILTER_ID: -+ return grub_diskfilter_has_cryptodisk (pv->disk->data); -+ default: -+ break; -+ } -+ } -+ -+ return 0; -+} -+ - static grub_err_t - grub_diskfilter_open (const char *name, grub_disk_t disk) - { -@@ -589,6 +622,8 @@ +@@ -590,6 +590,7 @@ grub_diskfilter_open (const char *name, grub_disk_t disk) disk->total_sectors = lv->size; disk->max_agglomerate = GRUB_DISK_MAX_MAX_AGGLOMERATE; -+ disk->is_crypto_diskfilter = grub_diskfilter_has_cryptodisk (lv); + return 0; } ---- a/include/grub/disk.h -+++ b/include/grub/disk.h -@@ -147,6 +147,8 @@ - - /* Device-specific data. */ - void *data; -+ -+ int is_crypto_diskfilter; - }; - typedef struct grub_disk *grub_disk_t; - -@@ -317,4 +319,12 @@ - void grub_diskfilter_fini (void); - #endif - -+static inline int -+grub_disk_is_crypto (grub_disk_t disk) -+{ -+ return ((disk->is_crypto_diskfilter || -+ disk->dev->id == GRUB_DISK_DEVICE_CRYPTODISK_ID) ? -+ 1 : 0); -+} -+ - #endif /* ! GRUB_DISK_HEADER */ +diff --git a/include/grub/file.h b/include/grub/file.h +index c463e4f992..804d512231 100644 +--- a/include/grub/file.h ++++ b/include/grub/file.h +@@ -185,6 +185,7 @@ extern grub_disk_read_hook_t EXPORT_VAR(grub_file_progress_hook); + /* Filters with lower ID are executed first. */ + typedef enum grub_file_filter_id + { ++ GRUB_FILE_FILTER_DISTRUST, + GRUB_FILE_FILTER_VERIFY, + GRUB_FILE_FILTER_GZIO, + GRUB_FILE_FILTER_XZIO, +-- +2.49.0 + ++++++ 0004-commands-search-Add-the-diskfilter-support.patch ++++++ >From 13ae8a054a4a0b871ce3fd8ddaaff7a4f2ba2478 Mon Sep 17 00:00:00 2001 From: Maxim Suhanov <dfirb...@gmail.com> Date: Thu, 8 May 2025 19:02:10 +0200 Subject: [PATCH 4/8] commands/search: Add the diskfilter support When the --cryptodisk-only argument is given, also check the target device using the "cryptocheck" command, if available. This extends the checks to common layouts like LVM-on-LUKS, so the --cryptodisk-only argument transparently handles such setups. Signed-off-by: Maxim Suhanov <dfirb...@gmail.com> Reviewed-by: Daniel Kiper <daniel.ki...@oracle.com> --- grub-core/commands/search.c | 32 +++++++++++++++++++++++++++++++- 1 file changed, 31 insertions(+), 1 deletion(-) diff --git a/grub-core/commands/search.c b/grub-core/commands/search.c index f6bfef9585..185c1e70f7 100644 --- a/grub-core/commands/search.c +++ b/grub-core/commands/search.c @@ -54,6 +54,36 @@ struct search_ctx int is_cache; }; +static bool +is_unencrypted_disk (grub_disk_t disk) +{ + grub_command_t cmd; + char *disk_str; + int disk_str_len; + int res; + + if (disk->dev->id == GRUB_DISK_DEVICE_CRYPTODISK_ID) + return false; /* This is (crypto) disk. */ + + if (disk->dev->id == GRUB_DISK_DEVICE_DISKFILTER_ID) + { + cmd = grub_command_find ("cryptocheck"); + if (cmd == NULL) /* No diskfilter module loaded for some reason. */ + return true; + + disk_str_len = grub_strlen (disk->name) + 2 + 1; + disk_str = grub_malloc (disk_str_len); + if (disk_str == NULL) /* Something is wrong, better report as unencrypted. */ + return true; + + grub_snprintf (disk_str, disk_str_len, "(%s)", disk->name); + res = cmd->func (cmd, 1, &disk_str); + grub_free (disk_str); + return (res != GRUB_ERR_NONE) ? true : false; /* GRUB_ERR_NONE for encrypted. */ + } + return true; +} + /* Helper for FUNC_NAME. */ static int iterate_device (const char *name, void *data) @@ -97,7 +127,7 @@ iterate_device (const char *name, void *data) grub_errno = GRUB_ERR_NONE; return 0; } - if (dev->disk == NULL || dev->disk->dev->id != GRUB_DISK_DEVICE_CRYPTODISK_ID) + if (dev->disk == NULL || is_unencrypted_disk (dev->disk) == true) { grub_device_close (dev); grub_errno = GRUB_ERR_NONE; -- 2.49.0 ++++++ 0005-docs-Document-available-crypto-disks-checks.patch ++++++ >From 45fffe05e9c33582258a88b4a722a5a561dbfa6e Mon Sep 17 00:00:00 2001 From: Maxim Suhanov <dfirb...@gmail.com> Date: Thu, 8 May 2025 19:02:11 +0200 Subject: [PATCH 5/8] docs: Document available crypto disks checks Document the --cryptodisk-only argument. Also, document the "cryptocheck" command invoked when that argument is processed. Signed-off-by: Maxim Suhanov <dfirb...@gmail.com> Reviewed-by: Daniel Kiper <daniel.ki...@oracle.com> --- docs/grub.texi | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/docs/grub.texi b/docs/grub.texi index 9aaea72826..1c078c5c5b 100644 --- a/docs/grub.texi +++ b/docs/grub.texi @@ -4368,6 +4368,7 @@ you forget a command, you can run the command @command{help} * configfile:: Load a configuration file * cpuid:: Check for CPU features * crc:: Compute or check CRC32 checksums +* cryptocheck:: Check if a device is encrypted * cryptomount:: Mount a crypto device * cutmem:: Remove memory regions * date:: Display or set current date and time @@ -4680,6 +4681,16 @@ Alias for @code{hashsum --hash crc32 arg @dots{}}. See command @command{hashsum} (@pxref{hashsum}) for full description. @end deffn +@node cryptocheck +@subsection cryptocheck + +@deffn Command cryptocheck device +Check if a given diskfilter device is backed by encrypted devices +(@pxref{cryptomount} for additional information). + +The command examines all backing devices, physical volumes, of a specified +logical volume, like LVM2, and fails when at least one of them is unencrypted. +@end deffn @node cryptomount @subsection cryptomount @@ -5531,7 +5542,8 @@ unbootable. @xref{Using GPG-style digital signatures}, for more information. @deffn Command search @ [@option{--file}|@option{--label}|@option{--fs-uuid}] @ - [@option{--set} [var]] [@option{--no-floppy}|@option{--efidisk-only}] name + [@option{--set} [var]] [@option{--no-floppy}|@option{--efidisk-only}|@option{--cryptodisk-only}] @ + name Search devices by file (@option{-f}, @option{--file}), filesystem label (@option{-l}, @option{--label}), or filesystem UUID (@option{-u}, @option{--fs-uuid}). @@ -5546,6 +5558,14 @@ devices, which can be slow. The (@option{--efidisk-only}) option prevents searching any other devices then EFI disks. This is typically used when chainloading to local EFI partition. +The (@option{--cryptodisk-only}) option prevents searching any devices other +than encrypted disks. This is typically used when booting from an encrypted +file system to ensure that no code gets executed from an unencrypted device +having the same filesystem UUID or label. + +This option implicitly invokes the command @command{cryptocheck}, if it is +available (@pxref{cryptocheck} for additional information). + The @samp{search.file}, @samp{search.fs_label}, and @samp{search.fs_uuid} commands are aliases for @samp{search --file}, @samp{search --label}, and @samp{search --fs-uuid} respectively. -- 2.49.0 ++++++ 0006-disk-cryptodisk-Add-the-erase-secrets-function.patch ++++++ >From 0a11bc48ea60f7611df2c5b640cecc325c7c4fd9 Mon Sep 17 00:00:00 2001 From: Maxim Suhanov <dfirb...@gmail.com> Date: Thu, 8 May 2025 19:02:12 +0200 Subject: [PATCH 6/8] disk/cryptodisk: Add the "erase secrets" function 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 1c078c5c5b..c4936db8c1 100644 --- a/docs/grub.texi +++ b/docs/grub.texi @@ -4727,6 +4727,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 @@ -6981,6 +6986,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 903af33131..bd9cb681ec 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 33eb6568ca..f9ae750f85 100644 --- a/grub-core/disk/cryptodisk.c +++ b/grub-core/disk/cryptodisk.c @@ -1784,6 +1784,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 = @@ -1808,6 +1833,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 b3291519b1..08abfb7b6c 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.49.0 ++++++ 0007-disk-cryptodisk-Wipe-the-passphrase-from-memory.patch ++++++ >From d5a155864230964878280a52dc82392382af1c5d Mon Sep 17 00:00:00 2001 From: Maxim Suhanov <dfirb...@gmail.com> Date: Thu, 8 May 2025 19:02:13 +0200 Subject: [PATCH 7/8] disk/cryptodisk: Wipe the passphrase from memory Switching to another EFI boot application while there are secrets in RAM is dangerous, because not all firmware is wiping memory on free. To reduce the attack surface, wipe the passphrase acquired when unlocking an encrypted volume. Signed-off-by: Maxim Suhanov <dfirb...@gmail.com> Reviewed-by: Daniel Kiper <daniel.ki...@oracle.com> --- grub-core/disk/cryptodisk.c | 1 + 1 file changed, 1 insertion(+) diff --git a/grub-core/disk/cryptodisk.c b/grub-core/disk/cryptodisk.c index f9ae750f85..cb87d337ac 100644 --- a/grub-core/disk/cryptodisk.c +++ b/grub-core/disk/cryptodisk.c @@ -1251,6 +1251,7 @@ grub_cryptodisk_scan_device_real (const char *name, #endif if (askpass) { + grub_memset (cargs->key_data, 0, cargs->key_len); cargs->key_len = 0; grub_free (cargs->key_data); } -- 2.49.0 ++++++ 0008-cryptocheck-Add-quiet-option.patch ++++++ >From ba5a201546cfb69d3079f18c89a79bda98e7bcd1 Mon Sep 17 00:00:00 2001 From: Michael Chang <mch...@suse.com> Date: Thu, 8 May 2025 19:02:14 +0200 Subject: [PATCH 8/8] cryptocheck: Add --quiet option The option can be used to suppress output if we only want to test the return value of the command. Also, mention this option in the documentation. Signed-off-by: Maxim Suhanov <dfirb...@gmail.com> Reviewed-by: Daniel Kiper <daniel.ki...@oracle.com> Signed-off-by: Michael Chang <mch...@suse.com> --- docs/grub.texi | 4 +++- grub-core/commands/search.c | 7 ++++++- grub-core/disk/diskfilter.c | 25 +++++++++++++++++++------ 3 files changed, 28 insertions(+), 8 deletions(-) diff --git a/docs/grub.texi b/docs/grub.texi index c4936db8c1..9646cf9282 100644 --- a/docs/grub.texi +++ b/docs/grub.texi @@ -4684,12 +4684,14 @@ Alias for @code{hashsum --hash crc32 arg @dots{}}. See command @command{hashsum} @node cryptocheck @subsection cryptocheck -@deffn Command cryptocheck device +@deffn Command cryptocheck [ @option{--quiet} ] device Check if a given diskfilter device is backed by encrypted devices (@pxref{cryptomount} for additional information). The command examines all backing devices, physical volumes, of a specified logical volume, like LVM2, and fails when at least one of them is unencrypted. + +The option @option{--quiet} can be given to suppress the output. @end deffn @node cryptomount diff --git a/grub-core/commands/search.c b/grub-core/commands/search.c index 185c1e70f7..49b679e805 100644 --- a/grub-core/commands/search.c +++ b/grub-core/commands/search.c @@ -67,6 +67,9 @@ is_unencrypted_disk (grub_disk_t disk) if (disk->dev->id == GRUB_DISK_DEVICE_DISKFILTER_ID) { + char opt[] = "--quiet"; + char *args[2]; + cmd = grub_command_find ("cryptocheck"); if (cmd == NULL) /* No diskfilter module loaded for some reason. */ return true; @@ -77,7 +80,9 @@ is_unencrypted_disk (grub_disk_t disk) return true; grub_snprintf (disk_str, disk_str_len, "(%s)", disk->name); - res = cmd->func (cmd, 1, &disk_str); + args[0] = opt; + args[1] = disk_str; + res = cmd->func (cmd, 2, args); grub_free (disk_str); return (res != GRUB_ERR_NONE) ? true : false; /* GRUB_ERR_NONE for encrypted. */ } diff --git a/grub-core/disk/diskfilter.c b/grub-core/disk/diskfilter.c index 3f7c05e14e..b1d5d464f5 100644 --- a/grub-core/disk/diskfilter.c +++ b/grub-core/disk/diskfilter.c @@ -1524,6 +1524,19 @@ grub_cmd_cryptocheck (grub_command_t cmd __attribute__ ((unused)), int check_pvs_res; int namelen; int pvs_cnt; + int opt_quiet = 0; + + if (argc == 2) + { + if (grub_strcmp (args[0], "--quiet") == 0) + { + opt_quiet = 1; + argc--; + args++; + } + else + return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("unrecognized option: %s"), args[0]); + } if (argc != 1) return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("disk name expected")); @@ -1546,11 +1559,11 @@ grub_cmd_cryptocheck (grub_command_t cmd __attribute__ ((unused)), check_pvs_res = grub_diskfilter_check_pvs_encrypted (disk, &pvs_cnt); grub_disk_close (disk); - - grub_printf("%s is %sencrypted (%d pv%s examined)\n", &args[0][1], - (check_pvs_res == GRUB_ERR_NONE) ? "" : "un", - pvs_cnt, - (pvs_cnt > 1) ? "s" : ""); + if (!opt_quiet) + grub_printf ("%s is %sencrypted (%d pv%s examined)\n", &args[0][1], + (check_pvs_res == GRUB_ERR_NONE) ? "" : "un", + pvs_cnt, + (pvs_cnt > 1) ? "s" : ""); return check_pvs_res; } @@ -1578,7 +1591,7 @@ GRUB_MOD_INIT(diskfilter) { grub_disk_dev_register (&grub_diskfilter_dev); cmd = grub_register_command ("cryptocheck", grub_cmd_cryptocheck, - N_("DEVICE"), + N_("[--quiet] DEVICE"), N_("Check if a logical volume resides on encrypted disks.")); } -- 2.49.0