9 Commits

Author SHA256 Message Date
8664a1b42d Optimize PBKDF2 to reduce the decryption time (bsc#1248516)
- 0001-lib-crypto-Introduce-new-HMAC-functions-to-reuse-buf.patch
- 0002-lib-pbkdf2-Optimize-PBKDF2-by-reusing-HMAC-handle.patch
- 0001-kern-misc-Implement-faster-grub_memcpy-for-aligned-b.patch
2026-01-20 15:29:01 +08:00
8e0047f3d6 Add upstream CVE fixes for 2025-11-18
- Fix CVE-2025-54771 (bsc#1252931)
  * 0001-kern-file-Call-grub_dl_unref-after-fs-fs_close.patch
- Fix CVE-2025-54770 (bsc#1252930)
  * 0002-net-net-Unregister-net_set_vlan-command-on-unload.patch
- Fix CVE-2025-61662 (bsc#1252933)
  * 0003-gettext-gettext-Unregister-gettext-command-on-module.patch
- Fix CVE-2025-61663 (bsc#1252934)
- Fix CVE-2025-61664 (bsc#1252935)
  * 0004-normal-main-Unregister-commands-on-module-unload.patch
  * 0005-tests-lib-functional_test-Unregister-commands-on-mod.patch
- Fix CVE-2025-61661 (bsc#1252932)
  * 0006-commands-usbtest-Use-correct-string-length-field.patch
  * 0007-commands-usbtest-Ensure-string-length-is-sufficient-.patch
- Bump upstream SBAT generation to 6
2025-11-19 11:42:00 +08:00
662ffc3467 Accepting request 1312316 from home:michael-chang:branches:Base:System
- Fix "sparse file not allowed" error after grub2-reboot (bsc#1245738)
  * grub2-grubenv-in-btrfs-header.patch

- Fix PowerPC network boot prefix to correctly locate grub.cfg (bsc#1249385)
  * 0001-ieee1275-Use-net-config-for-boot-location-instead-of.patch

OBS-URL: https://build.opensuse.org/request/show/1312316
OBS-URL: https://build.opensuse.org/package/show/Base:System/grub2?expand=0&rev=568
2025-11-06 15:17:36 +08:00
faa532f0d4 - turn off page flipping for i386-pc using VBE video backend (bsc#1245636)
* grub2-i386-pc-no-pageflipping.patch

OBS-URL: https://build.opensuse.org/package/show/Base:System/grub2?expand=0&rev=566
2025-10-21 15:07:39 +08:00
db6cd9e010 - Fix boot hangs in setting up serial console when ACPI SPCR table is present
and redirection is disabled (bsc#1249088)
  * 0001-term-ns8250-spcr-Return-if-redirection-is-disabled.patch

OBS-URL: https://build.opensuse.org/package/show/Base:System/grub2?expand=0&rev=565
2025-10-21 15:05:27 +08:00
01d2deb451 - Fix timeout when loading initrd via http after PPC CAS reboot (bsc#1245953)
* 0001-tcp-Fix-TCP-port-number-reused-on-reboot.patch

OBS-URL: https://build.opensuse.org/package/show/Base:System/grub2?expand=0&rev=559
2025-10-21 14:50:14 +08:00
e8de5b5d4b - Skip mount point in grub_find_device function (bsc#1246231)
* 0001-getroot-Skip-mount-points-in-grub_find_device.patch

OBS-URL: https://build.opensuse.org/package/show/Base:System/grub2?expand=0&rev=558
2025-10-21 14:48:34 +08:00
64d637cf0c Update the bug tag for 0001-tpm2-Add-extra-RSA-SRK-types.patch
OBS-URL: https://build.opensuse.org/package/show/Base:System/grub2?expand=0&rev=557
2025-10-21 14:46:36 +08:00
58b2f1d02d - Fix CVE-2024-56738: side-channel attack due to not constant-time
algorithm in grub_crypto_memcmp (bsc#1234959)
  * grub2-constant-time-grub_crypto_memcmp.patch

OBS-URL: https://build.opensuse.org/package/show/Base:System/grub2?expand=0&rev=556
2025-10-21 14:44:46 +08:00
196 changed files with 42819 additions and 1976 deletions

View File

@@ -1,42 +0,0 @@
From d7158116601881ec676de4c16d82653344ea617f Mon Sep 17 00:00:00 2001
From: Michael Chang <mchang@suse.com>
Date: Thu, 22 Jan 2026 18:19:23 +0800
Subject: [PATCH] 00_header: Omit loading efi_uga on non-x86 EFI platforms
When booting the arm64-efi target, GRUB prints the error message that
may disrupt the boot process:
error: ../../grub-core/fs/btrfs.c:find_path:2163:file
`/boot/grub2/arm64-efi/efi_uga.mod' not found.
This is introduced by the commit:
ea0b76dc4 util/grub.d/00_header.in: Disable loading all_video for EFI
However the efi_uga module is only enabled for x86_64-efi and i386-efi.
The script should therefore check the CPU target before attempting to
load it.
Signed-off-by: Michael Chang <mchang@suse.com>
---
util/grub.d/00_header.in | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/util/grub.d/00_header.in b/util/grub.d/00_header.in
index ffb50847f..63d8a1f38 100644
--- a/util/grub.d/00_header.in
+++ b/util/grub.d/00_header.in
@@ -179,7 +179,9 @@ else # GRUB_FORCE_EFI_ALL_VIDEO is not set true
cat <<EOF
if [ x\$grub_platform = xefi ]; then
insmod efi_gop
- insmod efi_uga
+ if [ x\$grub_cpu = xx86_64 -o x\$grub_cpu = xi386 ]; then
+ insmod efi_uga
+ fi
elif [ x\$feature_all_video_module = xy ]; then
EOF
fi # end GRUB_FORCE_EFI_ALL_VIDEO
--
2.52.0

View File

@@ -13,6 +13,8 @@ Signed-off-by: Michael Chang <mchang@suse.com>
util/grub-editenv.c | 4 +---
3 files changed, 14 insertions(+), 3 deletions(-)
diff --git a/grub-core/lib/envblk.c b/grub-core/lib/envblk.c
index 2e4e78b132..24efbe7ffa 100644
--- a/grub-core/lib/envblk.c
+++ b/grub-core/lib/envblk.c
@@ -23,6 +23,18 @@
@@ -34,9 +36,11 @@ Signed-off-by: Michael Chang <mchang@suse.com>
grub_envblk_t
grub_envblk_open (char *buf, grub_size_t size)
{
diff --git a/include/grub/lib/envblk.h b/include/grub/lib/envblk.h
index c3e6559217..83f3fcf841 100644
--- a/include/grub/lib/envblk.h
+++ b/include/grub/lib/envblk.h
@@ -31,6 +31,7 @@
@@ -31,6 +31,7 @@ struct grub_envblk
};
typedef struct grub_envblk *grub_envblk_t;
@@ -44,10 +48,12 @@ Signed-off-by: Michael Chang <mchang@suse.com>
grub_envblk_t grub_envblk_open (char *buf, grub_size_t size);
int grub_envblk_set (grub_envblk_t envblk, const char *name, const char *value);
void grub_envblk_delete (grub_envblk_t envblk, const char *name);
diff --git a/util/grub-editenv.c b/util/grub-editenv.c
index b8219335f7..a02d3f2a63 100644
--- a/util/grub-editenv.c
+++ b/util/grub-editenv.c
@@ -255,9 +255,7 @@
if (fp == NULL)
@@ -210,9 +210,7 @@ create_envblk_fs (void)
if (! fp)
grub_util_error (_("cannot open `%s': %s"), device, strerror (errno));
- buf = xmalloc (size);
@@ -57,3 +63,6 @@ Signed-off-by: Michael Chang <mchang@suse.com>
if (fseek (fp, offset, SEEK_SET) < 0)
grub_util_error (_("cannot seek `%s': %s"), device, strerror (errno));
--
2.34.1

View File

@@ -120,17 +120,17 @@ Signed-off-by: Michael Chang <mchang@suse.com>
if (nested)
--- 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/safemath.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 @@
@@ -317,8 +320,31 @@
grub_env_set ("default", ptr + 1);
else
grub_env_unset ("default");
@@ -162,7 +162,7 @@ Signed-off-by: Michael Chang <mchang@suse.com>
if (errs_before != grub_err_printed_errors)
grub_wait_after_message ();
@@ -327,8 +353,23 @@
@@ -326,8 +352,23 @@
errs_before = grub_err_printed_errors;
if (grub_errno == GRUB_ERR_NONE && grub_loader_is_loaded ())
@@ -312,7 +312,7 @@ Signed-off-by: Michael Chang <mchang@suse.com>
/* 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. */
@@ -903,10 +900,6 @@
@@ -886,10 +883,6 @@
grub_err_t ret = 0;
struct grub_script *parsed_script;

View File

@@ -38,6 +38,8 @@ Signed-Off-by Michael Chang <mchang@suse.com>
include/grub/crypttab.h | 18 ++++++++++-------
7 files changed, 61 insertions(+), 22 deletions(-)
diff --git a/grub-core/commands/crypttab.c b/grub-core/commands/crypttab.c
index c2217ca980..9397bede9e 100644
--- a/grub-core/commands/crypttab.c
+++ b/grub-core/commands/crypttab.c
@@ -9,17 +9,20 @@
@@ -65,7 +67,7 @@ Signed-Off-by Michael Chang <mchang@suse.com>
if (!cur)
cur = grub_zalloc (sizeof (*cur));
if (!cur)
@@ -44,21 +47,24 @@
@@ -44,21 +47,24 @@ grub_initrd_publish_key (const char *uuid, const char *key, grub_size_t key_len,
cur->path = grub_strdup (path);
}
@@ -94,7 +96,7 @@ Signed-Off-by Michael Chang <mchang@suse.com>
{
grub_list_remove (GRUB_AS_LIST (cur));
grub_memset (cur->key, 0, cur->key_len);
@@ -69,6 +75,20 @@
@@ -69,6 +75,20 @@ grub_initrd_discard_key (void)
}
}
@@ -115,7 +117,7 @@ Signed-Off-by Michael Chang <mchang@suse.com>
static grub_err_t
grub_cmd_crypttab_entry (grub_command_t cmd __attribute__ ((unused)),
int argc, char **argv)
@@ -92,7 +112,7 @@
@@ -92,7 +112,7 @@ grub_cmd_crypttab_entry (grub_command_t cmd __attribute__ ((unused)),
}
/*FIXME: Validate UUID string*/
@@ -124,9 +126,11 @@ Signed-Off-by Michael Chang <mchang@suse.com>
}
static grub_command_t cmd;
diff --git a/grub-core/disk/cryptodisk.c b/grub-core/disk/cryptodisk.c
index cb87d337ac..5fd68f4549 100644
--- a/grub-core/disk/cryptodisk.c
+++ b/grub-core/disk/cryptodisk.c
@@ -1076,6 +1076,9 @@
@@ -1071,6 +1071,9 @@ grub_cryptodisk_scan_device_real (const char *name,
struct cryptodisk_read_hook_ctx read_hook_data = {0};
int askpass = 0;
char *part = NULL;
@@ -136,15 +140,15 @@ Signed-Off-by Michael Chang <mchang@suse.com>
dev = grub_cryptodisk_get_by_source_disk (source);
@@ -1194,6 +1197,7 @@
goto error;
@@ -1185,6 +1188,7 @@ grub_cryptodisk_scan_device_real (const char *name,
goto error;
#ifndef GRUB_UTIL
grub_cli_set_auth_needed ();
+ is_tpmkey = 1;
#endif
goto cleanup;
}
@@ -1307,7 +1311,7 @@
@@ -1247,7 +1251,7 @@ grub_cryptodisk_scan_device_real (const char *name,
#ifndef GRUB_UTIL
if (cargs->key_data && dev)
@@ -153,7 +157,7 @@ Signed-Off-by Michael Chang <mchang@suse.com>
#endif
if (askpass)
{
@@ -1890,6 +1894,10 @@
@@ -1792,6 +1796,10 @@ grub_cryptodisk_erasesecrets (void)
grub_cryptodisk_t i;
grub_uint8_t *buf;
@@ -164,9 +168,11 @@ Signed-Off-by Michael Chang <mchang@suse.com>
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 9ee8f37907..e5e7929581 100644
--- a/grub-core/loader/linux.c
+++ b/grub-core/loader/linux.c
@@ -226,13 +226,13 @@
@@ -226,13 +226,13 @@ grub_initrd_init (int argc, char *argv[],
int i;
int newc = 0;
struct dir *root = 0;
@@ -182,7 +188,7 @@ Signed-Off-by Michael Chang <mchang@suse.com>
if (pk->key && pk->path)
numkey++;
@@ -305,7 +305,7 @@
@@ -305,7 +305,7 @@ grub_initrd_init (int argc, char *argv[],
goto overflow;
}
@@ -191,9 +197,11 @@ Signed-Off-by Michael Chang <mchang@suse.com>
if (pk->key && pk->path)
{
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 320adbe337..343cdbae2c 100644
--- a/grub-core/normal/main.c
+++ b/grub-core/normal/main.c
@@ -599,7 +599,7 @@
@@ -599,7 +599,7 @@ grub_cmdline_run (int nested, int force_auth)
return;
}
@@ -202,17 +210,19 @@ Signed-Off-by Michael Chang <mchang@suse.com>
grub_normal_reader_init (nested);
while (1)
diff --git a/grub-core/normal/menu.c b/grub-core/normal/menu.c
index f243c5e0bd..897da6abac 100644
--- a/grub-core/normal/menu.c
+++ b/grub-core/normal/menu.c
@@ -33,6 +33,7 @@
@@ -32,6 +32,7 @@
#include <grub/script_sh.h>
#include <grub/gfxterm.h>
#include <grub/dl.h>
#include <grub/safemath.h>
+#include <grub/crypttab.h>
#ifdef GRUB_MACHINE_IEEE1275
#include <grub/ieee1275/ieee1275.h>
#endif
@@ -770,6 +771,7 @@
@@ -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;
@@ -220,7 +230,7 @@ Signed-Off-by Michael Chang <mchang@suse.com>
break;
}
@@ -852,6 +854,11 @@
@@ -851,6 +853,11 @@ run_menu (grub_menu_t menu, int nested, int *auto_boot, int *notify_boot)
clear_timeout ();
}
@@ -232,9 +242,11 @@ Signed-Off-by Michael Chang <mchang@suse.com>
switch (c)
{
case GRUB_TERM_KEY_HOME:
diff --git a/grub-core/normal/menu_entry.c b/grub-core/normal/menu_entry.c
index 38c958e657..bbd05e5638 100644
--- a/grub-core/normal/menu_entry.c
+++ b/grub-core/normal/menu_entry.c
@@ -1331,7 +1331,7 @@
@@ -1331,7 +1331,7 @@ grub_menu_entry_run (grub_menu_entry_t entry)
return;
}
@@ -243,6 +255,8 @@ Signed-Off-by Michael Chang <mchang@suse.com>
screen = make_screen (entry);
if (! screen)
diff --git a/include/grub/crypttab.h b/include/grub/crypttab.h
index 113c53cfce..f86404686f 100644
--- a/include/grub/crypttab.h
+++ b/include/grub/crypttab.h
@@ -4,21 +4,25 @@
@@ -278,3 +292,6 @@ Signed-Off-by Michael Chang <mchang@suse.com>
+void
+grub_cryptokey_tpmkey_discard (void);
#endif /* ! GRUB_CRYPTTAB_HEADER */
--
2.49.0

View File

@@ -1,30 +0,0 @@
From b50719d46a75da79b23d2eda4bb117bb1c9207fc Mon Sep 17 00:00:00 2001
From: Michael Chang <mchang@suse.com>
Date: Mon, 19 Jan 2026 14:27:49 +0800
Subject: [PATCH 1/2] Revert "configure: Print a more helpful error if
autoconf-archive is not installed"
This reverts commit ac042f3f58d33ce9cd5ff61750f06da1a1d7b0eb.
---
configure.ac | 5 -----
1 file changed, 5 deletions(-)
diff --git a/configure.ac b/configure.ac
index 900e0626a..b4d4db944 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1792,11 +1792,6 @@ LIBS=""
# Defined in acinclude.m4.
grub_ASM_USCORE
grub_PROG_TARGET_CC
-
-# The error message produced by autoconf if autoconf-archive is not installed is
-# quite misleading and not very helpful. So, try point people in the right direction.
-m4_ifndef([AX_CHECK_LINK_FLAG], [m4_fatal([autoconf-archive is missing. You must install it to generate the configure script.])])
-
if test "x$TARGET_APPLE_LINKER" != x1 ; then
AX_CHECK_LINK_FLAG([-Wl,--image-base,0x400000],
[TARGET_IMG_BASE_LDOPT="-Wl,--image-base"],
--
2.52.0

View File

@@ -41,9 +41,30 @@ Signed-Off-by: Michael Chang <mchang@suse.com>
include/grub/parser.h | 4 ++
3 files changed, 90 insertions(+)
diff --git a/grub-core/commands/blscfg.c b/grub-core/commands/blscfg.c
index cbe2a289e..e08f35817 100644
--- a/grub-core/commands/blscfg.c
+++ b/grub-core/commands/blscfg.c
@@ -953,10 +953,14 @@ static void create_entry (struct bls_entry *entry)
const char *sdval = grub_env_get("save_default");
bool savedefault = ((NULL != sdval) && (grub_strcmp(sdval, "true") == 0));
+#ifdef GRUB_MACHINE_EFI
+ src = grub_xasprintf ("%slinux %s%s%s%s\n"
+#else
src = grub_xasprintf ("%sload_video\n"
"set gfxpayload=keep\n"
"insmod gzio\n"
"linux %s%s%s%s\n"
+#endif
"%s%s",
savedefault ? "savedefault\n" : "",
#ifdef GRUB_MACHINE_EMU
diff --git a/grub-core/normal/main.c b/grub-core/normal/main.c
index 03631f07a..8e58ced67 100644
--- a/grub-core/normal/main.c
+++ b/grub-core/normal/main.c
@@ -113,6 +113,65 @@
@@ -113,6 +113,65 @@ read_config_file_getline (char **line, int cont __attribute__ ((unused)),
return GRUB_ERR_NONE;
}
@@ -109,7 +130,7 @@ Signed-Off-by: Michael Chang <mchang@suse.com>
static grub_menu_t
read_config_file (const char *config)
{
@@ -282,6 +341,26 @@
@@ -282,6 +341,26 @@ grub_normal_execute (const char *config, int nested, int batch)
grub_boot_time ("Executing config file");
@@ -136,7 +157,7 @@ Signed-Off-by: Michael Chang <mchang@suse.com>
if (config)
{
menu = read_config_file (config);
@@ -307,6 +386,9 @@
@@ -307,6 +386,9 @@ grub_normal_execute (const char *config, int nested, int batch)
grub_boot_time ("Executed config file");
@@ -146,9 +167,11 @@ Signed-Off-by: Michael Chang <mchang@suse.com>
if (! batch)
{
if (menu && menu->size)
diff --git a/include/grub/parser.h b/include/grub/parser.h
index 64f9f5cc2..9d702571a 100644
--- a/include/grub/parser.h
+++ b/include/grub/parser.h
@@ -86,7 +86,11 @@
@@ -86,7 +86,11 @@ struct grub_parser
};
typedef struct grub_parser *grub_parser_t;
@@ -160,3 +183,6 @@ Signed-Off-by: Michael Chang <mchang@suse.com>
grub_err_t
grub_rescue_parse_line (char *line,
--
2.46.0

View File

@@ -70,7 +70,7 @@ V6:
--- a/grub-core/Makefile.core.def
+++ b/grub-core/Makefile.core.def
@@ -2456,6 +2456,12 @@
@@ -2362,6 +2362,12 @@
common = net/ethernet.c;
common = net/arp.c;
common = net/netbuff.c;
@@ -233,7 +233,7 @@ V6:
GRUB_MOD_LICENSE ("GPLv3+");
@@ -346,7 +347,7 @@
@@ -345,7 +346,7 @@
}
static grub_efi_handle_t
@@ -242,7 +242,7 @@ V6:
grub_efi_device_path_t **r_device_path)
{
grub_efi_handle_t handle;
@@ -499,6 +500,17 @@
@@ -498,6 +499,17 @@
ldp = grub_efi_find_last_device_path (ddp);
@@ -260,7 +260,7 @@ V6:
if (GRUB_EFI_DEVICE_PATH_TYPE (ldp) != GRUB_EFI_MESSAGING_DEVICE_PATH_TYPE
|| (GRUB_EFI_DEVICE_PATH_SUBTYPE (ldp) != GRUB_EFI_IPV4_DEVICE_PATH_SUBTYPE
&& GRUB_EFI_DEVICE_PATH_SUBTYPE (ldp) != GRUB_EFI_IPV6_DEVICE_PATH_SUBTYPE))
@@ -766,6 +778,7 @@
@@ -765,6 +777,7 @@
if (GRUB_EFI_DEVICE_PATH_TYPE (ldp) != GRUB_EFI_MESSAGING_DEVICE_PATH_TYPE
|| (GRUB_EFI_DEVICE_PATH_SUBTYPE (ldp) != GRUB_EFI_IPV4_DEVICE_PATH_SUBTYPE
&& GRUB_EFI_DEVICE_PATH_SUBTYPE (ldp) != GRUB_EFI_IPV6_DEVICE_PATH_SUBTYPE
@@ -268,7 +268,7 @@ V6:
&& GRUB_EFI_DEVICE_PATH_SUBTYPE (ldp) != GRUB_EFI_URI_DEVICE_PATH_SUBTYPE))
continue;
dup_dp = grub_efi_duplicate_device_path (dp);
@@ -781,6 +794,15 @@
@@ -780,6 +793,15 @@
}
dup_ldp = grub_efi_find_last_device_path (dup_dp);
@@ -284,7 +284,7 @@ V6:
dup_ldp->type = GRUB_EFI_END_DEVICE_PATH_TYPE;
dup_ldp->subtype = GRUB_EFI_END_ENTIRE_DEVICE_PATH_SUBTYPE;
dup_ldp->length = sizeof (*dup_ldp);
@@ -870,6 +892,9 @@
@@ -860,6 +882,9 @@
GRUB_MOD_INIT(efinet)
{
@@ -294,7 +294,7 @@ V6:
grub_efinet_findcards ();
grub_efi_net_config = grub_efi_net_config_real;
}
@@ -881,5 +906,7 @@
@@ -871,5 +896,7 @@
FOR_NET_CARDS_SAFE (card, next)
if (card->driver == &efidriver)
grub_net_card_unregister (card);
@@ -3848,17 +3848,17 @@ V6:
+
--- a/grub-core/net/net.c
+++ b/grub-core/net/net.c
@@ -33,6 +33,9 @@
@@ -32,6 +32,9 @@
#include <grub/loader.h>
#include <grub/bufio.h>
#include <grub/kernel.h>
#include <grub/safemath.h>
+#ifdef GRUB_MACHINE_EFI
+#include <grub/net/efi.h>
+#endif
GRUB_MOD_LICENSE ("GPLv3+");
@@ -2079,8 +2082,49 @@
@@ -2014,8 +2017,49 @@
static grub_command_t cmd_setvlan, cmd_lsroutes, cmd_lscards;
static grub_command_t cmd_lsaddr, cmd_slaac;
@@ -3908,7 +3908,7 @@ V6:
grub_register_variable_hook ("net_default_server", defserver_get_env,
defserver_set_env);
grub_env_export ("net_default_server");
@@ -2131,10 +2175,37 @@
@@ -2066,10 +2110,37 @@
grub_net_restore_hw,
GRUB_LOADER_PREBOOT_HOOK_PRIO_DISK);
grub_net_poll_cards_idle = grub_net_poll_cards_idle_real;
@@ -3945,8 +3945,8 @@ V6:
+
grub_register_variable_hook ("net_default_server", 0, 0);
grub_register_variable_hook ("pxe_default_server", 0, 0);
grub_register_variable_hook ("net_default_ip", 0, 0);
@@ -2155,4 +2226,7 @@
@@ -2088,4 +2159,7 @@
grub_net_fini_hw (0);
grub_loader_unregister_preboot_hook (fini_hnd);
grub_net_poll_cards_idle = NULL;
@@ -3956,7 +3956,7 @@ V6:
}
--- a/include/grub/efi/api.h
+++ b/include/grub/efi/api.h
@@ -663,6 +663,23 @@
@@ -653,6 +653,23 @@
typedef grub_uint8_t grub_efi_ip_address_t[8] __attribute__ ((aligned(4)));
typedef grub_efi_uint64_t grub_efi_physical_address_t;
typedef grub_efi_uint64_t grub_efi_virtual_address_t;
@@ -3980,7 +3980,7 @@ V6:
/* XXX although the spec does not specify the padding, this actually
must have the padding! */
@@ -912,6 +929,8 @@
@@ -902,6 +919,8 @@
grub_efi_uint16_t remote_port;
grub_efi_uint16_t protocol;
grub_efi_uint8_t static_ip_address;
@@ -3989,7 +3989,7 @@ V6:
} GRUB_PACKED;
typedef struct grub_efi_ipv6_device_path grub_efi_ipv6_device_path_t;
@@ -970,6 +989,15 @@
@@ -960,6 +979,15 @@
} GRUB_PACKED;
typedef struct grub_efi_uri_device_path grub_efi_uri_device_path_t;
@@ -4005,7 +4005,7 @@ V6:
#define GRUB_EFI_VENDOR_MESSAGING_DEVICE_PATH_SUBTYPE 10
/* Media Device Path. */
@@ -1052,6 +1080,23 @@
@@ -1042,6 +1070,23 @@
} GRUB_PACKED;
typedef struct grub_efi_bios_device_path grub_efi_bios_device_path_t;
@@ -4029,7 +4029,7 @@ V6:
struct grub_efi_open_protocol_information_entry
{
grub_efi_handle_t agent_handle;
@@ -1554,23 +1599,28 @@
@@ -1544,23 +1589,28 @@
typedef grub_uint8_t grub_efi_pxe_packet_t[1472];
@@ -4072,7 +4072,7 @@ V6:
#define GRUB_EFI_PXE_BASE_CODE_MAX_IPCNT 8
typedef struct {
@@ -1620,18 +1670,32 @@
@@ -1610,18 +1660,32 @@
typedef struct grub_efi_pxe
{
grub_uint64_t rev;
@@ -4117,7 +4117,7 @@ V6:
struct grub_efi_pxe_mode *mode;
} grub_efi_pxe_t;
@@ -1951,6 +2015,44 @@
@@ -1921,6 +1985,44 @@
};
typedef struct grub_efi_ip4_config2_protocol grub_efi_ip4_config2_protocol_t;
@@ -4162,7 +4162,7 @@ V6:
enum grub_efi_ip6_config_data_type {
GRUB_EFI_IP6_CONFIG_DATA_TYPE_INTERFACEINFO,
GRUB_EFI_IP6_CONFIG_DATA_TYPE_ALT_INTERFACEID,
@@ -1985,4 +2087,47 @@
@@ -1955,4 +2057,47 @@
};
typedef struct grub_efi_ip6_config_protocol grub_efi_ip6_config_protocol_t;

View File

@@ -0,0 +1,82 @@
From 552a2de0642bb95dd38fcdb7894ea7e07171975e Mon Sep 17 00:00:00 2001
From: Michael Chang <mchang@suse.com>
Date: Mon, 15 Jul 2024 11:43:07 +0800
Subject: [PATCH] bli: Fix crash in get_part_uuid
The get_part_uuid() function made an assumption that the target grub
device is a partition device and accessed device->disk->partition
without checking for NULL. There are four situations where this
assumption is problematic:
1. The device is a net device instead of a disk.
2. The device is an abstraction device, like LVM, RAID, or CRYPTO, which
is mostly logical "disk" ((lvmid/<UUID>) and so on).
3. Firmware RAID may present the ESP to grub as an EFI disk (hd0) device
if it is contained within a Linux software RAID.
4. When booting from a cdrom, the ESP is a vfat image indexed by the El
Torito boot catalog. The boot device is set to (cd0), corresponding
to the cdrom image mounted as an iso9660 filesystem.
As a result, get_part_uuid() could lead to a NULL pointer dereference
and trigger a synchronous exception during boot if the ESP falls into
one of these categories. This patch fixes the problem by adding the
necessary checks to handle cases where the ESP is not a partition
device.
Additionally, to avoid disrupting the boot process, this patch relaxes
the severity of the errors in this context to non-critical. Errors will
be logged, but they will not prevent the boot process from continuing.
Fixes: e0fa7dc84 (bli: Add a module for the Boot Loader Interface)
Signed-off-by: Michael Chang <mchang@suse.com>
Reviewed-By: Oliver Steffen <osteffen@redhat.com>
---
grub-core/commands/bli.c | 20 +++++++++++++++++++-
1 file changed, 19 insertions(+), 1 deletion(-)
diff --git a/grub-core/commands/bli.c b/grub-core/commands/bli.c
index e0d8a54f7..298c5f70a 100644
--- a/grub-core/commands/bli.c
+++ b/grub-core/commands/bli.c
@@ -48,6 +48,22 @@ get_part_uuid (const char *device_name, char **part_uuid)
if (device == NULL)
return grub_error (grub_errno, N_("cannot open device: %s"), device_name);
+ if (device->disk == NULL)
+ {
+ grub_dprintf ("bli", "%s is not a disk device, partuuid skipped\n", device_name);
+ *part_uuid = NULL;
+ grub_device_close (device);
+ return GRUB_ERR_NONE;
+ }
+
+ if (device->disk->partition == NULL)
+ {
+ grub_dprintf ("bli", "%s has no partition, partuuid skipped\n", device_name);
+ *part_uuid = NULL;
+ grub_device_close (device);
+ return GRUB_ERR_NONE;
+ }
+
disk = grub_disk_open (device->disk->name);
if (disk == NULL)
{
@@ -99,7 +115,7 @@ set_loader_device_part_uuid (void)
status = get_part_uuid (device_name, &part_uuid);
- if (status == GRUB_ERR_NONE)
+ if (status == GRUB_ERR_NONE && part_uuid)
status = grub_efi_set_variable_to_string ("LoaderDevicePartUUID", &bli_vendor_guid, part_uuid,
GRUB_EFI_VARIABLE_BOOTSERVICE_ACCESS |
GRUB_EFI_VARIABLE_RUNTIME_ACCESS);
@@ -117,4 +133,6 @@ GRUB_MOD_INIT (bli)
GRUB_EFI_VARIABLE_BOOTSERVICE_ACCESS |
GRUB_EFI_VARIABLE_RUNTIME_ACCESS);
set_loader_device_part_uuid ();
+ /* No error here is critical, other than being logged */
+ grub_print_error ();
}
--
2.46.0

File diff suppressed because it is too large Load Diff

View File

@@ -14,11 +14,13 @@ Signed-off-by: Michael Chang <mchang@suse.com>
grub-core/commands/blscfg.c | 164 ++++++++++++++++++++++--------------
1 file changed, 103 insertions(+), 61 deletions(-)
--- a/grub-core/commands/blsuki.c
+++ b/grub-core/commands/blsuki.c
@@ -117,6 +117,16 @@
diff --git a/grub-core/commands/blscfg.c b/grub-core/commands/blscfg.c
index 343c7ae989..10996722cf 100644
--- a/grub-core/commands/blscfg.c
+++ b/grub-core/commands/blscfg.c
@@ -55,6 +55,15 @@ struct keyval
static grub_blsuki_entry_t *entries = NULL;
static struct bls_entry *entries = NULL;
+struct bls_fragment
+{
@@ -27,39 +29,141 @@ Signed-off-by: Michael Chang <mchang@suse.com>
+ char *filename;
+};
+typedef struct bls_fragment *bls_fragment_t;
+static bls_fragment_t fragments;
+
+static bls_fragment_t fragments = NULL;
+
#define FOR_BLSUKI_ENTRIES(var) FOR_LIST_ELEMENTS (var, entries)
#define FOR_BLS_ENTRIES(var) FOR_LIST_ELEMENTS (var, entries)
/*
@@ -645,6 +655,69 @@
/* BLS appears to make paths relative to the filesystem that snippets are
@@ -466,69 +475,41 @@ struct read_entry_info {
grub_file_t file;
};
-static int read_entry (
- const char *filename,
- const struct grub_dirhook_info *dirhook_info UNUSED,
- void *data)
+static int
+read_entry (const char *filename)
{
grub_size_t m = 0, n, clip = 0;
int rc = 0;
char *p = NULL;
grub_file_t f = NULL;
struct bls_entry *entry;
- struct read_entry_info *info = (struct read_entry_info *)data;
-
- grub_dprintf ("blscfg", "filename: \"%s\"\n", filename);
+ char *slash;
- n = grub_strlen (filename);
+ grub_dprintf ("blscfg", "read_entry: \"%s\"\n", filename);
- if (info->file)
- {
- f = info->file;
- }
- else
- {
- if (filename[0] == '.')
- return 0;
+ f = grub_file_open (filename, GRUB_FILE_TYPE_CONFIG);
- if (n <= 5)
- return 0;
-
- if (grub_strcmp (filename + n - 5, ".conf") != 0)
- return 0;
-
- p = grub_xasprintf ("(%s)%s/%s", info->devid, info->dirname, filename);
-
- f = grub_file_open (p, GRUB_FILE_TYPE_CONFIG);
- if (!f)
- goto finish;
- }
+ if (!f)
+ goto finish;
entry = grub_zalloc (sizeof (*entry));
if (!entry)
goto finish;
- if (info->file)
- {
- char *slash;
+ /* Strip .conf */
+ n = grub_strlen (filename);
- if (n > 5 && !grub_strcmp (filename + n - 5, ".conf") == 0)
- clip = 5;
+ if (n > 5 && !grub_strcmp (filename + n - 5, ".conf") == 0)
+ clip = 5;
- slash = grub_strrchr (filename, '/');
- if (!slash)
- slash = grub_strrchr (filename, '\\');
+ slash = grub_strrchr (filename, '/');
+ if (!slash)
+ slash = grub_strrchr (filename, '\\');
- while (*slash == '/' || *slash == '\\')
- slash++;
+ while (*slash == '/' || *slash == '\\')
+ slash++;
- m = slash ? slash - filename : 0;
- }
- else
- {
- m = 0;
- clip = 5;
- }
+ m = slash ? slash - filename : 0;
n -= m;
entry->filename = grub_strndup(filename + m, n - clip);
@@ -573,10 +554,7 @@ static int read_entry (
if (rc < 0)
break;
}
-
- if (info->devid)
- entry->devid = grub_strdup(info->devid);
-
+ entry->devid = grub_file_get_device_name (filename);
if (!rc)
bls_add_entry(entry);
@@ -590,6 +568,73 @@ finish:
return 0;
}
+static int
+collect_fragments (
+ const char *filename,
+ const struct grub_dirhook_info *dirhook_info __attribute__ ((__unused__)),
+ void *data __attribute__ ((__unused__)))
+ const struct grub_dirhook_info *dirhook_info UNUSED,
+ void *data)
+{
+ grub_size_t n;
+ char *p = NULL;
+ struct read_entry_info *info = (struct read_entry_info *)data;
+ bls_fragment_t fragment, f, last;
+
+ if (filename[0] == '.')
+ return 0;
+
+ fragment = grub_zalloc (sizeof (*fragment));
+ if (fragment == NULL)
+ n = grub_strlen (filename);
+ if (n <= 5)
+ return 0;
+
+ fragment->filename = grub_strdup (filename);
+ if (fragment->filename == NULL)
+ {
+ grub_free (fragment);
+ return 0;
+ }
+ if (grub_strcmp (filename + n - 5, ".conf") != 0)
+ return 0;
+
+ if (fragments == NULL)
+ p = grub_xasprintf ("(%s)%s/%s", info->devid, info->dirname, filename);
+
+ fragment = grub_zalloc (sizeof (*fragment));
+ fragment->filename = grub_strdup (p);
+
+ if (!fragments)
+ {
+ fragments = fragment;
+ return 0;
@@ -68,8 +172,8 @@ Signed-off-by: Michael Chang <mchang@suse.com>
+ FOR_LIST_ELEMENTS (f, fragments)
+ {
+ int rc;
+ rc = grub_strcmp (fragment->filename, f->filename);
+ if (rc == 0)
+ rc = grub_strcmp(fragment->filename, f->filename);
+ if (!rc)
+ {
+ grub_free (fragment);
+ return 0;
@@ -100,33 +204,56 @@ Signed-off-by: Michael Chang <mchang@suse.com>
+ return 0;
+}
+
/*
* This function returns a list of values that had the same key in the BLS
* config file or UKI. The number of entries in this list is returned by the len
@@ -1200,7 +1273,7 @@
read_entry_info.devid = info->devid;
read_entry_info.cmd_type = cmd_type;
static grub_envblk_t saved_env = NULL;
- r = dir_fs->fs_dir (dir_dev, read_entry_info.dirname, blsuki_read_entry,
+ r = dir_fs->fs_dir (dir_dev, read_entry_info.dirname, collect_fragments,
&read_entry_info);
if (r != 0)
{
@@ -1208,6 +1281,17 @@
grub_errno = GRUB_ERR_NONE;
}
static int UNUSED
@@ -1007,6 +1052,7 @@ static int find_entry (struct find_entry_info *info)
const char *blsdir = info->dirname;
int fallback = 0;
int r = 0;
+ bls_fragment_t fragment;
+ while (fragments != NULL)
+ {
+ bls_fragment_t fragment = fragments;
if (!blsdir) {
blsdir = grub_env_get ("blsdir");
@@ -1024,8 +1070,14 @@ static int find_entry (struct find_entry_info *info)
read_entry_info.devid = info->devid;
read_fallback:
- r = blsdir_fs->fs_dir (blsdir_dev, read_entry_info.dirname, read_entry,
+ r = blsdir_fs->fs_dir (blsdir_dev, read_entry_info.dirname, collect_fragments,
&read_entry_info);
+ FOR_LIST_ELEMENTS (fragment, fragments)
+ {
+ grub_dprintf ("blscfg", "read_entry: %s\n", fragment->filename);
+ read_entry (fragment->filename);
+ }
+
+ fragments = fragments->next;
+ grub_dprintf ("blsuki", "read_entry: %s\n", fragment->filename);
+ blsuki_read_entry (fragment->filename, NULL, &read_entry_info);
+ grub_free (fragment->filename);
+ grub_free (fragment);
+ }
+
/*
* If we aren't able to find BLS entries in the directory given by info->dirname,
* we can fallback to the default location of "/loader/entries/" and see if we
if (r != 0) {
grub_dprintf ("blscfg", "read_entry returned error\n");
grub_err_t e;
@@ -1060,21 +1112,11 @@ bls_load_entries (const char *path)
.fs = NULL,
.dirname = NULL,
};
- struct read_entry_info rei = {
- .devid = NULL,
- .dirname = NULL,
- };
if (path) {
len = grub_strlen (path);
if (grub_strcmp (path + len - 5, ".conf") == 0) {
- rei.file = grub_file_open (path, GRUB_FILE_TYPE_CONFIG);
- if (!rei.file)
- return grub_errno;
- /*
- * read_entry() closes the file
- */
- return read_entry(path, NULL, &rei);
+ return read_entry (path);
} else if (path[0] == '(') {
devid = path + 1;
--
2.49.0

View File

@@ -1,30 +0,0 @@
From cc6749ca2fbe48c8624dbbea02b4bed89f046ef5 Mon Sep 17 00:00:00 2001
From: Michael Chang <mchang@suse.com>
Date: Mon, 2 Feb 2026 18:40:01 +0800
Subject: [PATCH] blsuki: Fix linux_cmd size calcution in bls_get_linux()
---
grub-core/commands/blsuki.c | 7 +++++++
1 file changed, 7 insertions(+)
diff --git a/grub-core/commands/blsuki.c b/grub-core/commands/blsuki.c
index 4da0464cf..531aac889 100644
--- a/grub-core/commands/blsuki.c
+++ b/grub-core/commands/blsuki.c
@@ -958,6 +958,13 @@ bls_get_linux (grub_blsuki_entry_t *entry)
}
}
+ /* Need one extra byte for '\n' */
+ if (grub_add (size, 1, &size))
+ {
+ grub_error (GRUB_ERR_OUT_OF_RANGE, "overflow detected while calculating linux buffer size");
+ goto finish;
+ }
+
linux_cmd = grub_malloc (size);
if (linux_cmd == NULL)
goto finish;
--
2.52.0

View File

@@ -0,0 +1,374 @@
From c7dd3dd296592fef6166170121b54aafe634369f Mon Sep 17 00:00:00 2001
From: Alec Brown <alec.r.brown@oracle.com>
Date: Wed, 24 Jan 2024 06:26:37 +0000
Subject: [PATCH 1/2] cli_lock: Add build option to block command line
interface
Add functionality to disable command line interface access and editing of GRUB
menu entries if GRUB image is built with --disable-cli.
Signed-off-by: Alec Brown <alec.r.brown@oracle.com>
Reviewed-by: Vladimir Serbinenko <phcoder@gmail.com>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
---
docs/grub.texi | 6 ++++--
grub-core/kern/main.c | 28 ++++++++++++++++++++++++++++
grub-core/kern/rescue_reader.c | 13 +++++++++++++
grub-core/normal/auth.c | 3 +++
grub-core/normal/menu_text.c | 31 +++++++++++++++++--------------
include/grub/kernel.h | 3 ++-
include/grub/misc.h | 2 ++
include/grub/util/install.h | 8 ++++++--
util/grub-install-common.c | 11 ++++++++---
util/grub-mkimage.c | 9 ++++++++-
util/mkimage.c | 16 +++++++++++++++-
11 files changed, 106 insertions(+), 24 deletions(-)
diff --git a/docs/grub.texi b/docs/grub.texi
index 00c5fdc44..e89007920 100644
--- a/docs/grub.texi
+++ b/docs/grub.texi
@@ -6523,8 +6523,10 @@ the GRUB command line, edit menu entries, and execute any menu entry. If
@samp{superusers} is set, then use of the command line and editing of menu
entries are automatically restricted to superusers. Setting @samp{superusers}
to empty string effectively disables both access to CLI and editing of menu
-entries. Note: The environment variable needs to be exported to also affect
-the section defined by the @samp{submenu} command (@pxref{submenu}).
+entries. Building a grub image with @samp{--disable-cli} option will also
+disable access to CLI and editing of menu entries, as well as disabling rescue
+mode. Note: The environment variable needs to be exported to also affect the
+section defined by the @samp{submenu} command (@pxref{submenu}).
Other users may be allowed to execute specific menu entries by giving a list of
usernames (as above) using the @option{--users} option to the
diff --git a/grub-core/kern/main.c b/grub-core/kern/main.c
index 02df49206..07b6940d2 100644
--- a/grub-core/kern/main.c
+++ b/grub-core/kern/main.c
@@ -30,11 +30,14 @@
#include <grub/reader.h>
#include <grub/parser.h>
#include <grub/verify.h>
+#include <grub/types.h>
#ifdef GRUB_MACHINE_PCBIOS
#include <grub/machine/memory.h>
#endif
+static bool cli_disabled = false;
+
grub_addr_t
grub_modules_get_end (void)
{
@@ -237,6 +240,28 @@ grub_load_normal_mode (void)
grub_command_execute ("normal", 0, 0);
}
+bool
+grub_is_cli_disabled (void)
+{
+ return cli_disabled;
+}
+
+static void
+check_is_cli_disabled (void)
+{
+ struct grub_module_header *header;
+ header = 0;
+
+ FOR_MODULES (header)
+ {
+ if (header->type == OBJ_TYPE_DISABLE_CLI)
+ {
+ cli_disabled = true;
+ return;
+ }
+ }
+}
+
static void
reclaim_module_space (void)
{
@@ -294,6 +319,9 @@ grub_main (void)
grub_boot_time ("After loading embedded modules.");
+ /* Check if the CLI should be disabled */
+ check_is_cli_disabled ();
+
/* It is better to set the root device as soon as possible,
for convenience. */
grub_set_prefix_and_root ();
diff --git a/grub-core/kern/rescue_reader.c b/grub-core/kern/rescue_reader.c
index dcd7d4439..4259857ba 100644
--- a/grub-core/kern/rescue_reader.c
+++ b/grub-core/kern/rescue_reader.c
@@ -78,6 +78,19 @@ grub_rescue_read_line (char **line, int cont,
void __attribute__ ((noreturn))
grub_rescue_run (void)
{
+ /* Stall if the CLI has been disabled */
+ if (grub_is_cli_disabled ())
+ {
+ grub_printf ("Rescue mode has been disabled...\n");
+
+ do
+ {
+ /* Do not optimize out the loop. */
+ asm volatile ("");
+ }
+ while (1);
+ }
+
grub_printf ("Entering rescue mode...\n");
while (1)
diff --git a/grub-core/normal/auth.c b/grub-core/normal/auth.c
index 517fc623f..d94020186 100644
--- a/grub-core/normal/auth.c
+++ b/grub-core/normal/auth.c
@@ -209,6 +209,9 @@ grub_auth_check_authentication (const char *userlist)
char entered[GRUB_AUTH_MAX_PASSLEN];
struct grub_auth_user *user;
+ if (grub_is_cli_disabled ())
+ return GRUB_ACCESS_DENIED;
+
grub_memset (login, 0, sizeof (login));
if (is_authenticated (userlist))
diff --git a/grub-core/normal/menu_text.c b/grub-core/normal/menu_text.c
index ae92050d7..56c6f7797 100644
--- a/grub-core/normal/menu_text.c
+++ b/grub-core/normal/menu_text.c
@@ -194,21 +194,24 @@ command-line or ESC to discard edits and return to the GRUB menu."),
grub_free (msg_translated);
#endif
- if (nested)
+ if (!grub_is_cli_disabled ())
{
- ret += grub_print_message_indented_real
- (_("Press enter to boot the selected OS, "
- "`e' to edit the commands before booting "
- "or `c' for a command-line. ESC to return previous menu."),
- STANDARD_MARGIN, STANDARD_MARGIN, term, dry_run);
- }
- else
- {
- ret += grub_print_message_indented_real
- (_("Press enter to boot the selected OS, "
- "`e' to edit the commands before booting "
- "or `c' for a command-line."),
- STANDARD_MARGIN, STANDARD_MARGIN, term, dry_run);
+ if (nested)
+ {
+ ret += grub_print_message_indented_real
+ (_("Press enter to boot the selected OS, "
+ "`e' to edit the commands before booting "
+ "or `c' for a command-line. ESC to return previous menu."),
+ STANDARD_MARGIN, STANDARD_MARGIN, term, dry_run);
+ }
+ else
+ {
+ ret += grub_print_message_indented_real
+ (_("Press enter to boot the selected OS, "
+ "`e' to edit the commands before booting "
+ "or `c' for a command-line."),
+ STANDARD_MARGIN, STANDARD_MARGIN, term, dry_run);
+ }
}
}
return ret;
diff --git a/include/grub/kernel.h b/include/grub/kernel.h
index d3aafc884..9f3e2031f 100644
--- a/include/grub/kernel.h
+++ b/include/grub/kernel.h
@@ -31,7 +31,8 @@ enum
OBJ_TYPE_GPG_PUBKEY,
OBJ_TYPE_X509_PUBKEY,
OBJ_TYPE_DTB,
- OBJ_TYPE_DISABLE_SHIM_LOCK
+ OBJ_TYPE_DISABLE_SHIM_LOCK,
+ OBJ_TYPE_DISABLE_CLI
};
/* The module header. */
diff --git a/include/grub/misc.h b/include/grub/misc.h
index 1b35a167f..1578f36c3 100644
--- a/include/grub/misc.h
+++ b/include/grub/misc.h
@@ -391,6 +391,8 @@ grub_uint64_t EXPORT_FUNC(grub_divmod64) (grub_uint64_t n,
grub_uint64_t d,
grub_uint64_t *r);
+extern bool EXPORT_FUNC(grub_is_cli_disabled) (void);
+
/* Must match softdiv group in gentpl.py. */
#if !defined(GRUB_MACHINE_EMU) && (defined(__arm__) || defined(__ia64__) || \
(defined(__riscv) && (__riscv_xlen == 32)))
diff --git a/include/grub/util/install.h b/include/grub/util/install.h
index 38c6da73b..a4aac7b85 100644
--- a/include/grub/util/install.h
+++ b/include/grub/util/install.h
@@ -72,6 +72,8 @@
{ "appended-signature-size", GRUB_INSTALL_OPTIONS_APPENDED_SIGNATURE_SIZE,\
"SIZE", 0, N_("Add a note segment reserving SIZE bytes for an appended signature"), \
1}, \
+ { "disable-cli", GRUB_INSTALL_OPTIONS_DISABLE_CLI, 0, 0, \
+ N_("disabled command line interface access"), 0 }, \
{ "verbose", 'v', 0, 0, \
N_("print verbose messages."), 1 }
@@ -136,7 +138,8 @@ enum grub_install_options {
GRUB_INSTALL_OPTIONS_DTB,
GRUB_INSTALL_OPTIONS_SBAT,
GRUB_INSTALL_OPTIONS_DISABLE_SHIM_LOCK,
- GRUB_INSTALL_OPTIONS_APPENDED_SIGNATURE_SIZE
+ GRUB_INSTALL_OPTIONS_APPENDED_SIGNATURE_SIZE,
+ GRUB_INSTALL_OPTIONS_DISABLE_CLI
};
extern char *grub_install_source_directory;
@@ -199,7 +202,8 @@ grub_install_generate_image (const char *dir, const char *prefix,
const struct grub_install_image_target_desc *image_target,
int note, size_t appsig_size,
grub_compression_t comp, const char *dtb_file,
- const char *sbat_path, const int disable_shim_lock);
+ const char *sbat_path, const int disable_shim_lock,
+ const int disable_cli);
const struct grub_install_image_target_desc *
grub_install_get_image_target (const char *arg);
diff --git a/util/grub-install-common.c b/util/grub-install-common.c
index 75fa03995..344dca664 100644
--- a/util/grub-install-common.c
+++ b/util/grub-install-common.c
@@ -469,6 +469,7 @@ static char **x509keys;
static size_t nx509keys;
static grub_compression_t compression;
static size_t appsig_size;
+static int disable_cli;
int
grub_install_parse (int key, char *arg)
@@ -514,6 +515,9 @@ grub_install_parse (int key, char *arg)
* (nx509keys + 1));
x509keys[nx509keys++] = xstrdup (arg);
return 1;
+ case GRUB_INSTALL_OPTIONS_DISABLE_CLI:
+ disable_cli = 1;
+ return 1;
case GRUB_INSTALL_OPTIONS_VERBOSITY:
verbosity++;
@@ -707,12 +711,13 @@ grub_install_make_image_wrap_file (const char *dir, const char *prefix,
grub_util_info ("grub-mkimage --directory '%s' --prefix '%s' --output '%s'"
" --format '%s' --compression '%s'"
- " --appended-signature-size %zu%s%s%s\n",
+ " --appended-signature-size %zu%s%s%s%s\n",
dir, prefix, outname,
mkimage_target, compnames[compression],
appsig_size,
note ? " --note" : "",
- disable_shim_lock ? " --disable-shim-lock" : "", s);
+ disable_shim_lock ? " --disable-shim-lock" : "",
+ disable_cli ? " --disable-cli" : "", s);
free (s);
tgt = grub_install_get_image_target (mkimage_target);
@@ -724,7 +729,7 @@ grub_install_make_image_wrap_file (const char *dir, const char *prefix,
pubkeys, npubkeys, x509keys, nx509keys,
config_path, tgt,
note, appsig_size, compression, dtb, sbat,
- disable_shim_lock);
+ disable_shim_lock, disable_cli);
while (dc--)
grub_install_pop_module ();
}
diff --git a/util/grub-mkimage.c b/util/grub-mkimage.c
index 7d61ef3ea..351a5e430 100644
--- a/util/grub-mkimage.c
+++ b/util/grub-mkimage.c
@@ -84,6 +84,7 @@ static struct argp_option options[] = {
{"compression", 'C', "(xz|none|auto)", 0, N_("choose the compression to use for core image"), 0},
{"sbat", 's', N_("FILE"), 0, N_("SBAT metadata"), 0},
{"disable-shim-lock", GRUB_INSTALL_OPTIONS_DISABLE_SHIM_LOCK, 0, 0, N_("disable shim_lock verifier"), 0},
+ {"disable-cli", GRUB_INSTALL_OPTIONS_DISABLE_CLI, 0, 0, N_("disable command line interface access"), 0},
{"verbose", 'v', 0, 0, N_("print verbose messages."), 0},
{"appended-signature-size", 'S', N_("SIZE"), 0, N_("Add a note segment reserving SIZE bytes for an appended signature"), 0},
{ 0, 0, 0, 0, 0, 0 }
@@ -133,6 +134,7 @@ struct arguments
int note;
int disable_shim_lock;
size_t appsig_size;
+ int disable_cli;
const struct grub_install_image_target_desc *image_target;
grub_compression_t comp;
};
@@ -259,6 +261,10 @@ argp_parser (int key, char *arg, struct argp_state *state)
arguments->disable_shim_lock = 1;
break;
+ case GRUB_INSTALL_OPTIONS_DISABLE_CLI:
+ arguments->disable_cli = 1;
+ break;
+
case 'v':
verbosity++;
break;
@@ -347,7 +353,8 @@ main (int argc, char *argv[])
arguments.image_target, arguments.note,
arguments.appsig_size,
arguments.comp, arguments.dtb,
- arguments.sbat, arguments.disable_shim_lock);
+ arguments.sbat, arguments.disable_shim_lock,
+ arguments.disable_cli);
if (grub_util_file_sync (fp) < 0)
grub_util_error (_("cannot sync `%s': %s"), arguments.output ? : "stdout",
diff --git a/util/mkimage.c b/util/mkimage.c
index 0737935fd..d6cc13475 100644
--- a/util/mkimage.c
+++ b/util/mkimage.c
@@ -889,7 +889,8 @@ grub_install_generate_image (const char *dir, const char *prefix,
const struct grub_install_image_target_desc *image_target,
int note, size_t appsig_size, grub_compression_t comp,
const char *dtb_path, const char *sbat_path,
- int disable_shim_lock)
+ int disable_shim_lock,
+ int disable_cli)
{
char *kernel_img, *core_img;
size_t total_module_size, core_size;
@@ -964,6 +965,9 @@ grub_install_generate_image (const char *dir, const char *prefix,
if (disable_shim_lock)
total_module_size += sizeof (struct grub_module_header);
+ if (disable_cli)
+ total_module_size += sizeof (struct grub_module_header);
+
if (config_path)
{
config_size = ALIGN_ADDR (grub_util_get_image_size (config_path) + 1);
@@ -1130,6 +1134,16 @@ grub_install_generate_image (const char *dir, const char *prefix,
offset += sizeof (*header);
}
+ if (disable_cli)
+ {
+ struct grub_module_header *header;
+
+ header = (struct grub_module_header *) (kernel_img + offset);
+ header->type = grub_host_to_target32 (OBJ_TYPE_DISABLE_CLI);
+ header->size = grub_host_to_target32 (sizeof (*header));
+ offset += sizeof (*header);
+ }
+
if (config_path)
{
struct grub_module_header *header;
--
2.46.0

View File

@@ -0,0 +1,153 @@
From 386b59ddb42fa3f86ddfe557113b25c8fa16f88c Mon Sep 17 00:00:00 2001
From: Forest <forestix@nom.one>
Date: Mon, 6 May 2024 17:07:30 -0700
Subject: [PATCH] disk/cryptodisk: Allow user to retry failed passphrase
Give the user a chance to re-enter their cryptodisk passphrase after a typo,
rather than immediately failing (and likely dumping them into a GRUB shell).
By default, we allow 3 tries before giving up. A value in the
cryptodisk_passphrase_tries environment variable will override this default.
The user can give up early by entering an empty passphrase, just as they
could before this patch.
Signed-off-by: Forest <forestix@nom.one>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
---
docs/grub.texi | 9 +++++
grub-core/disk/cryptodisk.c | 71 ++++++++++++++++++++++++++++---------
2 files changed, 64 insertions(+), 16 deletions(-)
Index: grub-2.12/docs/grub.texi
===================================================================
--- grub-2.12.orig/docs/grub.texi
+++ grub-2.12/docs/grub.texi
@@ -3278,6 +3278,7 @@ These variables have special meaning to
* color_normal::
* config_directory::
* config_file::
+* cryptodisk_passphrase_tries::
* debug::
* default::
* fallback::
@@ -3450,6 +3451,14 @@ processed by commands @command{configfil
(@pxref{normal}). It is restored to the previous value when command completes.
+@node cryptodisk_passphrase_tries
+@subsection cryptodisk_passphrase_tries
+
+When prompting the user for a cryptodisk passphrase, allow this many attempts
+before giving up. Defaults to @samp{3} if unset or set to an invalid value.
+(The user can give up early by entering an empty passphrase.)
+
+
@node debug
@subsection debug
Index: grub-2.12/grub-core/disk/cryptodisk.c
===================================================================
--- grub-2.12.orig/grub-core/disk/cryptodisk.c
+++ grub-2.12/grub-core/disk/cryptodisk.c
@@ -17,6 +17,7 @@
*/
#include <grub/cryptodisk.h>
+#include <grub/env.h>
#include <grub/mm.h>
#include <grub/misc.h>
#include <grub/dl.h>
@@ -1202,37 +1203,76 @@ grub_cryptodisk_scan_device_real (const
grub_free (part);
}
- if (!cargs->key_len)
+ if (cargs->key_len)
{
+ ret = cr->recover_key (source, dev, cargs);
+ if (ret != GRUB_ERR_NONE)
+ goto error;
+ }
+ else
+ {
+ /* Get the passphrase from the user, if no key data. */
+ unsigned long tries = 3;
+ const char *tries_env;
+
if (grub_errno)
{
grub_print_error ();
grub_errno = GRUB_ERR_NONE;
}
- /* Get the passphrase from the user, if no key data. */
askpass = 1;
- part = grub_partition_get_name (source->partition);
- grub_printf_ (N_("Enter passphrase for %s%s%s (%s): "), source->name,
- source->partition != NULL ? "," : "",
- part != NULL ? part : N_("UNKNOWN"), dev->uuid);
- grub_free (part);
-
cargs->key_data = grub_malloc (GRUB_CRYPTODISK_MAX_PASSPHRASE);
if (cargs->key_data == NULL)
goto error;
- if (!grub_password_get ((char *) cargs->key_data, GRUB_CRYPTODISK_MAX_PASSPHRASE))
+ tries_env = grub_env_get ("cryptodisk_passphrase_tries");
+ if (tries_env != NULL && tries_env[0] != '\0')
{
- grub_error (GRUB_ERR_BAD_ARGUMENT, "passphrase not supplied");
- goto error;
+ unsigned long tries_env_val;
+ const char *p;
+
+ tries_env_val = grub_strtoul (tries_env, &p, 0);
+ if (*p == '\0' && tries_env_val != ~0UL)
+ tries = tries_env_val;
+ else
+ grub_printf_ (N_("Invalid cryptodisk_passphrase_tries value `%s'. Defaulting to %lu.\n"),
+ tries_env,
+ tries);
}
- cargs->key_len = grub_strlen ((char *) cargs->key_data);
- }
- ret = cr->recover_key (source, dev, cargs);
- if (ret != GRUB_ERR_NONE)
- goto error;
+ for (; tries > 0; tries--)
+ {
+ part = grub_partition_get_name (source->partition);
+ grub_printf_ (N_("Enter passphrase for %s%s%s (%s): "), source->name,
+ source->partition != NULL ? "," : "",
+ part != NULL ? part : N_("UNKNOWN"),
+ dev->uuid);
+ grub_free (part);
+
+ if (!grub_password_get ((char *) cargs->key_data, GRUB_CRYPTODISK_MAX_PASSPHRASE))
+ {
+ grub_error (GRUB_ERR_BAD_ARGUMENT, "passphrase not supplied");
+ goto error;
+ }
+ cargs->key_len = grub_strlen ((char *) cargs->key_data);
+
+ ret = cr->recover_key (source, dev, cargs);
+ if (ret == GRUB_ERR_NONE)
+ break;
+ if (ret != GRUB_ERR_ACCESS_DENIED || tries == 1)
+ goto error;
+ grub_puts_ (N_("Invalid passphrase."));
+
+ /*
+ * Since recover_key() calls a function that returns grub_errno,
+ * a leftover error value from a previously rejected passphrase
+ * will trigger a phantom failure. We therefore clear it before
+ * trying a new passphrase.
+ */
+ grub_errno = GRUB_ERR_NONE;
+ }
+ }
ret = grub_cryptodisk_insert (dev, name, source);
if (ret != GRUB_ERR_NONE)

View File

@@ -1,27 +0,0 @@
From ad40cc47948a351a77bd0aa35286e1f1e66cc39f Mon Sep 17 00:00:00 2001
From: Michael Chang <mchang@suse.com>
Date: Mon, 24 Nov 2025 15:27:28 +0800
Subject: [PATCH] editenv: create health_check_flag env var on RW raw block
Signed-off-by: Michael Chang <mchang@suse.com>
---
util/grub-editenv.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/util/grub-editenv.c b/util/grub-editenv.c
index ddecfab48..16ab32798 100644
--- a/util/grub-editenv.c
+++ b/util/grub-editenv.c
@@ -468,7 +468,8 @@ set_variables (const char *name, int argc, char *argv[])
*(p++) = 0;
- if ((strcmp (argv[0], "next_entry") == 0) && envblk_on_block != NULL)
+ if ((strcmp (argv[0], "next_entry") == 0 ||
+ strcmp (argv[0], "health_checker_flag") == 0) && envblk_on_block != NULL)
{
if (grub_envblk_set (envblk_on_block, argv[0], p) == 0)
grub_util_error ("%s", _("environment block too small"));
--
2.51.1

View File

@@ -0,0 +1,55 @@
From 8b9234c7e482edd49a9b3377da8e48fbd54aab28 Mon Sep 17 00:00:00 2001
From: Michael Chang <mchang@suse.com>
Date: Tue, 24 Sep 2024 18:59:34 +0800
Subject: [PATCH] efinet: Skip virtual VLAN devices during card enumeration
Similar to the fix in commit "c52ae4057 efinet: skip virtual IPv4 and
IPv6 devices during card enumeration", the UEFI PXE driver creates
additional VLAN child devices when a VLAN ID is configured on a network
interface associated with a physical NIC. These virtual VLAN devices
must be skipped during card enumeration to ensure that the subsequent
SNP exclusive open operation targets the correct physical card
instances, otherwise packet transfer would fail.
Example device path with VLAN nodes:
/MAC(123456789ABC,0x1)/Vlan(20)/IPv4(0.0.0.0,0x0,DHCP,0.0.0.0,0.0.0.0,0.0.0.0)
Signed-Off-by: Michael Chang <mchang@suse.com>
---
grub-core/net/drivers/efi/efinet.c | 12 +++++++++++-
1 file changed, 11 insertions(+), 1 deletion(-)
diff --git a/grub-core/net/drivers/efi/efinet.c b/grub-core/net/drivers/efi/efinet.c
index 720b5d0e1..3d0bf34fa 100644
--- a/grub-core/net/drivers/efi/efinet.c
+++ b/grub-core/net/drivers/efi/efinet.c
@@ -280,7 +280,8 @@ grub_efinet_findcards (void)
|| GRUB_EFI_DEVICE_PATH_SUBTYPE (child) == GRUB_EFI_IPV6_DEVICE_PATH_SUBTYPE)
&& parent
&& GRUB_EFI_DEVICE_PATH_TYPE (parent) == GRUB_EFI_MESSAGING_DEVICE_PATH_TYPE
- && GRUB_EFI_DEVICE_PATH_SUBTYPE (parent) == GRUB_EFI_MAC_ADDRESS_DEVICE_PATH_SUBTYPE)
+ && (GRUB_EFI_DEVICE_PATH_SUBTYPE (parent) == GRUB_EFI_MAC_ADDRESS_DEVICE_PATH_SUBTYPE
+ || GRUB_EFI_DEVICE_PATH_SUBTYPE (parent) == GRUB_EFI_VLAN_DEVICE_PATH_SUBTYPE))
continue;
net = grub_efi_open_protocol (*handle, &net_io_guid,
@@ -810,6 +811,15 @@ grub_efi_net_config_real (grub_efi_handle_t hnd, char **device,
dup_ldp->type = GRUB_EFI_END_DEVICE_PATH_TYPE;
dup_ldp->subtype = GRUB_EFI_END_ENTIRE_DEVICE_PATH_SUBTYPE;
dup_ldp->length = sizeof (*dup_ldp);
+
+ dup_ldp = grub_efi_find_last_device_path (dup_dp);
+ if (GRUB_EFI_DEVICE_PATH_SUBTYPE (dup_ldp) == GRUB_EFI_VLAN_DEVICE_PATH_SUBTYPE)
+ {
+ dup_ldp->type = GRUB_EFI_END_DEVICE_PATH_TYPE;
+ dup_ldp->subtype = GRUB_EFI_END_ENTIRE_DEVICE_PATH_SUBTYPE;
+ dup_ldp->length = sizeof (*dup_ldp);
+ }
+
match = grub_efi_compare_device_paths (dup_dp, cdp) == 0;
grub_free (dup_dp);
if (!match)
--
2.46.1

View File

@@ -0,0 +1,48 @@
From 44f3c7978a8ac5cc94a5c885ac9e983ba2980f5e Mon Sep 17 00:00:00 2001
From: Michael Chang <mchang@suse.com>
Date: Wed, 29 May 2024 12:32:32 +0800
Subject: [PATCH] fix grub screen filled with post screen artifects
---
grub-core/normal/menu.c | 7 ++++---
grub-core/term/efi/console.c | 2 +-
2 files changed, 5 insertions(+), 4 deletions(-)
diff --git a/grub-core/normal/menu.c b/grub-core/normal/menu.c
index 1df2638d7..b11b28e0d 100644
--- a/grub-core/normal/menu.c
+++ b/grub-core/normal/menu.c
@@ -975,13 +975,14 @@ show_menu (grub_menu_t menu, int nested, int autobooted)
if (! e)
continue; /* Menu is empty. */
- grub_cls ();
-
if (auto_boot)
grub_menu_execute_with_fallback (menu, e, autobooted,
&execution_callback, &notify_boot);
else
- grub_menu_execute_entry (e, 0);
+ {
+ grub_cls ();
+ grub_menu_execute_entry (e, 0);
+ }
if (autobooted)
break;
}
diff --git a/grub-core/term/efi/console.c b/grub-core/term/efi/console.c
index bb587f39d..258b52737 100644
--- a/grub-core/term/efi/console.c
+++ b/grub-core/term/efi/console.c
@@ -432,7 +432,7 @@ grub_console_cls (struct grub_term_output *term __attribute__ ((unused)))
grub_efi_simple_text_output_interface_t *o;
grub_efi_int32_t orig_attr;
- if (grub_efi_is_finished || text_mode != GRUB_TEXT_MODE_AVAILABLE)
+ if (grub_prepare_for_text_output (term) != GRUB_ERR_NONE)
return;
o = grub_efi_system_table->con_out;
--
2.45.1

View File

@@ -0,0 +1,65 @@
From 7a8d9a29358fbe9eb5dcc70e63c417c4f3cd5068 Mon Sep 17 00:00:00 2001
From: "Darrick J. Wong" <djwong@kernel.org>
Date: Mon, 3 Feb 2025 15:41:22 -0800
Subject: [PATCH 1/3] fs/xfs: Add new superblock features added in Linux
6.12/6.13
The Linux port of XFS added a few new features in 2024. The existing
GRUB driver doesn't attempt to read or write any of the new metadata,
so, all three can be added to the incompat allowlist.
On the occasion align XFS_SB_FEAT_INCOMPAT_NREXT64 value.
Signed-off-by: Darrick J. Wong <djwong@kernel.org>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
---
grub-core/fs/xfs.c | 19 +++++++++++++++++--
1 file changed, 17 insertions(+), 2 deletions(-)
diff --git a/grub-core/fs/xfs.c b/grub-core/fs/xfs.c
index c17e54e447..e3a69fe498 100644
--- a/grub-core/fs/xfs.c
+++ b/grub-core/fs/xfs.c
@@ -88,7 +88,10 @@ GRUB_MOD_LICENSE ("GPLv3+");
#define XFS_SB_FEAT_INCOMPAT_META_UUID (1 << 2) /* metadata UUID */
#define XFS_SB_FEAT_INCOMPAT_BIGTIME (1 << 3) /* large timestamps */
#define XFS_SB_FEAT_INCOMPAT_NEEDSREPAIR (1 << 4) /* needs xfs_repair */
-#define XFS_SB_FEAT_INCOMPAT_NREXT64 (1 << 5) /* large extent counters */
+#define XFS_SB_FEAT_INCOMPAT_NREXT64 (1 << 5) /* large extent counters */
+#define XFS_SB_FEAT_INCOMPAT_EXCHRANGE (1 << 6) /* exchangerange supported */
+#define XFS_SB_FEAT_INCOMPAT_PARENT (1 << 7) /* parent pointers */
+#define XFS_SB_FEAT_INCOMPAT_METADIR (1 << 8) /* metadata dir tree */
/*
* Directory entries with ftype are explicitly handled by GRUB code.
@@ -98,6 +101,15 @@ GRUB_MOD_LICENSE ("GPLv3+");
*
* We do not currently verify metadata UUID, so it is safe to read filesystems
* with the XFS_SB_FEAT_INCOMPAT_META_UUID feature.
+ *
+ * We do not currently replay the log, so it is safe to read filesystems
+ * with the XFS_SB_FEAT_INCOMPAT_EXCHRANGE feature.
+ *
+ * We do not currently read directory parent pointers, so it is safe to read
+ * filesystems with the XFS_SB_FEAT_INCOMPAT_PARENT feature.
+ *
+ * We do not currently look at realtime or quota metadata, so it is safe to
+ * read filesystems with the XFS_SB_FEAT_INCOMPAT_METADIR feature.
*/
#define XFS_SB_FEAT_INCOMPAT_SUPPORTED \
(XFS_SB_FEAT_INCOMPAT_FTYPE | \
@@ -105,7 +117,10 @@ GRUB_MOD_LICENSE ("GPLv3+");
XFS_SB_FEAT_INCOMPAT_META_UUID | \
XFS_SB_FEAT_INCOMPAT_BIGTIME | \
XFS_SB_FEAT_INCOMPAT_NEEDSREPAIR | \
- XFS_SB_FEAT_INCOMPAT_NREXT64)
+ XFS_SB_FEAT_INCOMPAT_NREXT64 | \
+ XFS_SB_FEAT_INCOMPAT_EXCHRANGE | \
+ XFS_SB_FEAT_INCOMPAT_PARENT | \
+ XFS_SB_FEAT_INCOMPAT_METADIR)
struct grub_xfs_sblock
{
--
2.48.1

View File

@@ -0,0 +1,48 @@
From 045aae8fe7238aabc217700df4d17d83b7d891f3 Mon Sep 17 00:00:00 2001
From: Michael Chang <mchang@suse.com>
Date: Tue, 23 Jan 2024 12:46:16 +0800
Subject: [PATCH] fs/xfs: always verify the total number of entries is not zero
---
grub-core/fs/xfs.c | 12 ++++++------
1 file changed, 6 insertions(+), 6 deletions(-)
diff --git a/grub-core/fs/xfs.c b/grub-core/fs/xfs.c
index bc2224dbb..1ce5fa4fc 100644
--- a/grub-core/fs/xfs.c
+++ b/grub-core/fs/xfs.c
@@ -900,6 +900,8 @@ grub_xfs_iterate_dir (grub_fshelp_node_t dir,
{
struct grub_xfs_dir2_entry *direntry =
grub_xfs_first_de(dir->data, dirblock);
+ struct grub_xfs_dirblock_tail *tail = grub_xfs_dir_tail (dir->data, dirblock);
+
int entries = -1;
char *end = dirblock + dirblk_size;
@@ -918,18 +920,16 @@ grub_xfs_iterate_dir (grub_fshelp_node_t dir,
*/
if (dir->inode.nextents == grub_cpu_to_be32_compile_time (1))
{
- struct grub_xfs_dirblock_tail *tail = grub_xfs_dir_tail (dir->data, dirblock);
-
end = (char *) tail;
/* Subtract the space used by leaf nodes. */
end -= grub_be_to_cpu32 (tail->leaf_count) * sizeof (struct grub_xfs_dir_leaf_entry);
+ }
- entries = grub_be_to_cpu32 (tail->leaf_count) - grub_be_to_cpu32 (tail->leaf_stale);
+ entries = grub_be_to_cpu32 (tail->leaf_count) - grub_be_to_cpu32 (tail->leaf_stale);
- if (!entries)
- continue;
- }
+ if (!entries)
+ continue;
/* Iterate over all entries within this block. */
while ((char *) direntry < (char *) end)
--
2.43.0

View File

@@ -0,0 +1,113 @@
From eae4fc64a16cb58733afca09e70a09e51d405a9d Mon Sep 17 00:00:00 2001
From: Michael Chang <mchang@suse.com>
Date: Tue, 30 Sep 2025 14:44:02 +0800
Subject: [PATCH] ieee1275: Use net config for boot location instead of
firmware bootpath
On network boots, grub_ieee1275_net_config() is used to determine the
boot device, but the path continues to be taken from the Open Firmware
/chosen/bootpath property. This assumes the device node follows the
generic IEEE-1275 syntax, which is not always the case. Different
drivers may extend or redefine the format, and GRUB may then
misinterpret the argument as a filename and set $prefix incorrectly.
The generic Open Firmware device path format is:
device-name[:device-argument]
device-argument := [partition][,[filename]]
For example, a bootpath such as:
/vdevice/l-lan@30000002:speed=auto,duplex=auto,1.2.243.345,,9.8.76.543,1.2.34.5,5,5,255.255.255.0,512
does not follow this form. The section after the colon (the
device-argument) contains driver-specific options and network
parameters, not a valid filename. GRUB interprets this string as a
filename, which results in $prefix being set to "/", effectively losing
the intended boot directory.
The firmware is not at fault here, since interpretation of device nodes
is driver-specific. Instead, GRUB should use the filename provided in
the cached DHCP packet, which is consistent and reliable. This is also
the same mechanism already used on UEFI and legacy BIOS platforms.
This patch updates grub_machine_get_bootlocation() to prefer the result
from grub_ieee1275_net_config() when complete, and only fall back to the
firmware bootpath otherwise.
Signed-off-by: Michael Chang <mchang@suse.com>
---
grub-core/kern/ieee1275/init.c | 28 +++++++++++++++++++++-------
1 file changed, 21 insertions(+), 7 deletions(-)
diff --git a/grub-core/kern/ieee1275/init.c b/grub-core/kern/ieee1275/init.c
index 45f787eff..802a34f07 100644
--- a/grub-core/kern/ieee1275/init.c
+++ b/grub-core/kern/ieee1275/init.c
@@ -153,9 +153,11 @@ void (*grub_ieee1275_net_config) (const char *dev, char **device, char **path,
void
grub_machine_get_bootlocation (char **device, char **path)
{
- char *bootpath;
+ char *bootpath = NULL;
char *filename;
- char *type;
+ char *type = NULL;
+ char *ret_device = NULL;
+ char *ret_path = NULL;
bootpath = grub_ieee1275_get_boot_dev ();
if (! bootpath)
@@ -171,7 +173,7 @@ grub_machine_get_bootlocation (char **device, char **path)
dev = grub_ieee1275_get_aliasdevname (bootpath);
canon = grub_ieee1275_canonicalise_devname (dev);
if (! canon)
- return;
+ goto done;
ptr = canon + grub_strlen (canon) - 1;
while (ptr > canon && (*ptr == ',' || *ptr == ':'))
ptr--;
@@ -179,13 +181,17 @@ grub_machine_get_bootlocation (char **device, char **path)
*ptr = 0;
if (grub_ieee1275_net_config)
- grub_ieee1275_net_config (canon, device, path, bootpath);
+ grub_ieee1275_net_config (canon, &ret_device, &ret_path, bootpath);
grub_free (dev);
grub_free (canon);
+
+ /* Use path from net config if it is provided by cached DHCP info */
+ if (ret_path != NULL)
+ goto done;
+ /* Fall through to use firmware bootpath */
}
else
- *device = grub_ieee1275_encode_devname (bootpath);
- grub_free (type);
+ ret_device = grub_ieee1275_encode_devname (bootpath);
filename = grub_ieee1275_get_filename (bootpath);
if (filename)
@@ -198,10 +204,18 @@ grub_machine_get_bootlocation (char **device, char **path)
*lastslash = '\0';
grub_translate_ieee1275_path (filename);
- *path = filename;
+ ret_path = filename;
}
}
+
+ done:
+ grub_free (type);
grub_free (bootpath);
+
+ if (device != NULL)
+ *device = ret_device;
+ if (path != NULL)
+ *path = ret_path;
}
/* Claim some available memory in the first /memory node. */
--
2.51.0

View File

@@ -0,0 +1,56 @@
From 5025c64afc876d91d3947ce07bb59ffe9af7209d Mon Sep 17 00:00:00 2001
From: Sudhakar Kuppusamy <sudhakar@linux.ibm.com>
Date: Tue, 25 Feb 2025 19:14:24 +0530
Subject: [PATCH 1/9] ieee1275: adding failure check condition on
/ibm,secure-boot
failure check condition is missing while finding device "/" and
get property "ibm,secure-boot". So, adding the failure check condition.
Signed-off-by: Sudhakar Kuppusamy <sudhakar@linux.ibm.com>
---
grub-core/kern/ieee1275/init.c | 20 ++++++++++++++------
1 file changed, 14 insertions(+), 6 deletions(-)
diff --git a/grub-core/kern/ieee1275/init.c b/grub-core/kern/ieee1275/init.c
index f86543da0d..0e1cbf24c3 100644
--- a/grub-core/kern/ieee1275/init.c
+++ b/grub-core/kern/ieee1275/init.c
@@ -987,12 +987,20 @@ grub_get_ieee1275_secure_boot (void)
int rc;
grub_uint32_t is_sb;
- grub_ieee1275_finddevice ("/", &root);
-
- rc = grub_ieee1275_get_integer_property (root, "ibm,secure-boot", &is_sb,
- sizeof (is_sb), 0);
+ if (grub_ieee1275_finddevice ("/", &root))
+ {
+ grub_error (GRUB_ERR_UNKNOWN_DEVICE, "couldn't find / node");
+ return;
+ }
- /* ibm,secure-boot:
+ rc = grub_ieee1275_get_integer_property (root, "ibm,secure-boot", &is_sb, sizeof (is_sb), 0);
+ if (rc < 0)
+ {
+ grub_error (GRUB_ERR_UNKNOWN_DEVICE, "couldn't examine /ibm,secure-boot property");
+ return;
+ }
+ /*
+ * ibm,secure-boot:
* 0 - disabled
* 1 - audit
* 2 - enforce
@@ -1000,7 +1008,7 @@ grub_get_ieee1275_secure_boot (void)
*
* We only support enforce.
*/
- if (rc >= 0 && is_sb >= 2)
+ if (is_sb >= 2)
grub_lockdown ();
}
--
2.48.1

View File

@@ -22,17 +22,19 @@ Signed-off-by: Mukesh Kumar Chaurasiya <mchauras@linux.ibm.com>
grub-core/disk/ieee1275/ofdisk.c | 80 +++++++++++++++++++++++++++++++-
2 files changed, 86 insertions(+), 2 deletions(-)
diff --git a/docs/grub.texi b/docs/grub.texi
index d3f0f6577..c8ebc083d 100644
--- a/docs/grub.texi
+++ b/docs/grub.texi
@@ -3323,6 +3323,7 @@
@@ -3315,6 +3315,7 @@ These variables have special meaning to GRUB.
* net_default_ip::
* net_default_mac::
* net_default_server::
+* ofdisk_retry_timeout::
* pager::
* prefix::
* pxe_default_server::
@@ -3783,6 +3784,13 @@
* pxe_blksize::
@@ -3744,6 +3745,13 @@ The default is the value of @samp{color_normal} (@pxref{color_normal}).
@xref{Network}.
@@ -46,19 +48,21 @@ Signed-off-by: Mukesh Kumar Chaurasiya <mchauras@linux.ibm.com>
@node pager
@subsection pager
diff --git a/grub-core/disk/ieee1275/ofdisk.c b/grub-core/disk/ieee1275/ofdisk.c
index 7197d5401..f96bbb58c 100644
--- a/grub-core/disk/ieee1275/ofdisk.c
+++ b/grub-core/disk/ieee1275/ofdisk.c
@@ -25,6 +25,9 @@
@@ -24,6 +24,9 @@
#include <grub/ieee1275/ofdisk.h>
#include <grub/i18n.h>
#include <grub/time.h>
#include <grub/safemath.h>
+#include <grub/env.h>
+
+#define RETRY_DEFAULT_TIMEOUT 15
static char *last_devpath;
static grub_ieee1275_ihandle_t last_ihandle;
@@ -822,7 +825,7 @@
@@ -783,7 +786,7 @@ compute_dev_path (const char *name)
}
static grub_err_t
@@ -67,7 +71,7 @@ Signed-off-by: Mukesh Kumar Chaurasiya <mchauras@linux.ibm.com>
{
grub_ieee1275_phandle_t dev;
char *devpath;
@@ -918,6 +921,56 @@
@@ -879,6 +882,56 @@ grub_ofdisk_open (const char *name, grub_disk_t disk)
return 0;
}
@@ -124,7 +128,7 @@ Signed-off-by: Mukesh Kumar Chaurasiya <mchauras@linux.ibm.com>
static void
grub_ofdisk_close (grub_disk_t disk)
{
@@ -954,7 +1007,7 @@
@@ -915,7 +968,7 @@ grub_ofdisk_prepare (grub_disk_t disk, grub_disk_addr_t sector)
}
static grub_err_t
@@ -133,10 +137,11 @@ Signed-off-by: Mukesh Kumar Chaurasiya <mchauras@linux.ibm.com>
grub_size_t size, char *buf)
{
grub_err_t err;
@@ -974,6 +1027,29 @@
@@ -934,6 +987,29 @@ grub_ofdisk_read (grub_disk_t disk, grub_disk_addr_t sector,
return 0;
}
static grub_err_t
+static grub_err_t
+grub_ofdisk_read (grub_disk_t disk, grub_disk_addr_t sector,
+ grub_size_t size, char *buf)
+{
@@ -159,7 +164,9 @@ Signed-off-by: Mukesh Kumar Chaurasiya <mchauras@linux.ibm.com>
+ return err;
+}
+
+static grub_err_t
static grub_err_t
grub_ofdisk_write (grub_disk_t disk, grub_disk_addr_t sector,
grub_size_t size, const char *buf)
{
--
2.41.0

View File

@@ -0,0 +1,45 @@
From 12d518fd50ed4787d3cc4bafcc11e14139dc5d76 Mon Sep 17 00:00:00 2001
From: Thomas Frauendorfer | Miray Software <tf@miray.de>
Date: Wed, 7 May 2025 16:15:22 +0200
Subject: [PATCH 1/7] kern/file: Call grub_dl_unref() after fs->fs_close()
With commit 16f196874 (kern/file: Implement filesystem reference
counting) files hold a reference to their file systems.
When closing a file in grub_file_close() we should not expect
file->fs to stay valid after calling grub_dl_unref() on file->fs->mod.
So, grub_dl_unref() should be called after file->fs->fs_close().
Fixes: CVE-2025-54771
Fixes: 16f196874 (kern/file: Implement filesystem reference counting)
Reported-by: Thomas Frauendorfer | Miray Software <tf@miray.de>
Signed-off-by: Thomas Frauendorfer | Miray Software <tf@miray.de>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
---
grub-core/kern/file.c | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/grub-core/kern/file.c b/grub-core/kern/file.c
index 7217a6ea7..dce29bedd 100644
--- a/grub-core/kern/file.c
+++ b/grub-core/kern/file.c
@@ -201,12 +201,12 @@ grub_file_read (grub_file_t file, void *buf, grub_size_t len)
grub_err_t
grub_file_close (grub_file_t file)
{
- if (file->fs->mod)
- grub_dl_unref (file->fs->mod);
-
if (file->fs->fs_close)
(file->fs->fs_close) (file);
+ if (file->fs->mod)
+ grub_dl_unref (file->fs->mod);
+
if (file->device)
grub_device_close (file->device);
grub_free (file->name);
--
2.51.1

View File

@@ -0,0 +1,122 @@
From ba65f46ffd2952a3f69d85a4534b1e55291f080c Mon Sep 17 00:00:00 2001
From: Avnish Chouhan <avnish@linux.ibm.com>
Date: Thu, 23 May 2024 18:43:14 +0530
Subject: [PATCH] kern/ieee1275/init: Add IEEE 1275 Radix support for KVM on
Power
This patch adds support for Radix, Xive and Radix_gtse in Options
vector5 which is required for KVM LPARs. KVM LPARs ONLY support
Radix and not the Hash. Not enabling Radix on any PowerVM KVM LPARs
will result in boot failure.
Signed-off-by: Avnish Chouhan <avnish@linux.ibm.com>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
---
grub-core/kern/ieee1275/init.c | 63 +++++++++++++++++++++++++++++++++-
1 file changed, 62 insertions(+), 1 deletion(-)
diff --git a/grub-core/kern/ieee1275/init.c b/grub-core/kern/ieee1275/init.c
index bb800b275..8e08e5dd5 100644
--- a/grub-core/kern/ieee1275/init.c
+++ b/grub-core/kern/ieee1275/init.c
@@ -115,6 +115,16 @@ grub_addr_t grub_ieee1275_original_stack;
#define DRC_INFO 0x40
#define BYTE22 (DY_MEM_V2 | DRC_INFO)
+/* For ibm,arch-vec-5-platform-support. */
+#define XIVE_INDEX 0x17
+#define MMU_INDEX 0x18
+#define RADIX_GTSE_INDEX 0x1a
+#define RADIX_ENABLED 0x40
+#define XIVE_ENABLED 0x40
+#define HASH_ENABLED 0x00
+#define MAX_SUPPORTED 0xC0
+#define RADIX_GTSE_ENABLED 0x40
+
void
grub_exit (void)
{
@@ -740,6 +750,10 @@ struct option_vector5
grub_uint32_t platform_facilities;
grub_uint8_t sub_processors;
grub_uint8_t byte22;
+ grub_uint8_t xive;
+ grub_uint8_t mmu;
+ grub_uint8_t hpt_ext;
+ grub_uint8_t radix_gtse;
} GRUB_PACKED;
struct pvr_entry
@@ -778,6 +792,13 @@ grub_ieee1275_ibm_cas (void)
{
int rc;
grub_ieee1275_ihandle_t root;
+ grub_uint8_t ibm_arch_platform_support[8];
+ grub_ssize_t actual;
+ grub_uint8_t xive_support = 0;
+ grub_uint8_t mmu_support = 0;
+ grub_uint8_t radix_gtse_support = 0;
+ int i = 0;
+ int prop_len = 8;
struct cas_args
{
struct grub_ieee1275_common_hdr common;
@@ -786,6 +807,46 @@ grub_ieee1275_ibm_cas (void)
grub_ieee1275_cell_t cas_addr;
grub_ieee1275_cell_t result;
} args;
+
+ grub_ieee1275_get_integer_property (grub_ieee1275_chosen,
+ "ibm,arch-vec-5-platform-support",
+ (grub_uint32_t *) ibm_arch_platform_support,
+ sizeof (ibm_arch_platform_support),
+ &actual);
+
+ for (i = 0; i < prop_len; i++)
+ {
+ switch (ibm_arch_platform_support[i])
+ {
+ case XIVE_INDEX:
+ if (ibm_arch_platform_support[i + 1] & MAX_SUPPORTED)
+ xive_support = XIVE_ENABLED;
+ else
+ xive_support = 0;
+ break;
+
+ case MMU_INDEX:
+ if (ibm_arch_platform_support[i + 1] & MAX_SUPPORTED)
+ mmu_support = RADIX_ENABLED;
+ else
+ mmu_support = HASH_ENABLED;
+ break;
+
+ case RADIX_GTSE_INDEX:
+ if (mmu_support == RADIX_ENABLED)
+ radix_gtse_support = ibm_arch_platform_support[i + 1] & RADIX_GTSE_ENABLED;
+ else
+ radix_gtse_support = 0;
+ break;
+
+ default:
+ /* Ignoring the other indexes of ibm,arch-vec-5-platform-support. */
+ break;
+ }
+ /* Skipping the property value. */
+ i++;
+ }
+
struct cas_vector vector =
{
.pvr_list = { { 0x00000000, 0xffffffff } }, /* any processor */
@@ -802,7 +863,7 @@ grub_ieee1275_ibm_cas (void)
.vec4 = 0x0001, /* set required minimum capacity % to the lowest value */
.vec5_size = 1 + sizeof (struct option_vector5) - 2,
.vec5 = {
- 0, BYTE2, 0, CMO, ASSOCIATIVITY, BIN_OPTS, 0, 0, MAX_CPU, 0, 0, PLATFORM_FACILITIES, SUB_PROCESSORS, BYTE22
+ 0, BYTE2, 0, CMO, ASSOCIATIVITY, BIN_OPTS, 0, 0, MAX_CPU, 0, 0, PLATFORM_FACILITIES, SUB_PROCESSORS, BYTE22, xive_support, mmu_support, 0, radix_gtse_support
}
};
--
2.47.0

View File

@@ -0,0 +1,116 @@
From 1fbd2a278cfc645adc45c0e1357e58bcd1909f8d Mon Sep 17 00:00:00 2001
From: Gary Lin <glin@suse.com>
Date: Thu, 28 Aug 2025 15:03:35 +0800
Subject: [PATCH] kern/misc: Implement faster grub_memcpy() for aligned buffers
When both "dest" and "src" are aligned, copying the data in chunks
(unsigned long) is more efficient than a byte-by-byte copy.
Also tweak '__aeabi_memcpy()', '__aeabi_memcpy4()', and
'__aeabi_memcpy8()', since 'grub_memcpy()' is not inline anymore.
Signed-off-by: Gary Lin <glin@suse.com>
---
grub-core/kern/compiler-rt.c | 8 ++++----
grub-core/kern/misc.c | 30 ++++++++++++++++++++++++++++++
include/grub/misc.h | 8 +-------
3 files changed, 35 insertions(+), 11 deletions(-)
diff --git a/grub-core/kern/compiler-rt.c b/grub-core/kern/compiler-rt.c
index eda689a0c..8f3865e95 100644
--- a/grub-core/kern/compiler-rt.c
+++ b/grub-core/kern/compiler-rt.c
@@ -24,7 +24,7 @@
void * GRUB_BUILTIN_ATTR
memcpy (void *dest, const void *src, grub_size_t n)
{
- return grub_memmove (dest, src, n);
+ return grub_memcpy (dest, src, n);
}
void * GRUB_BUILTIN_ATTR
memmove (void *dest, const void *src, grub_size_t n)
@@ -372,11 +372,11 @@ grub_int32_t
__aeabi_idiv (grub_int32_t a, grub_int32_t b)
__attribute__ ((alias ("__divsi3")));
void *__aeabi_memcpy (void *dest, const void *src, grub_size_t n)
- __attribute__ ((alias ("grub_memcpy")));
+ __attribute__ ((alias ("memcpy")));
void *__aeabi_memcpy4 (void *dest, const void *src, grub_size_t n)
- __attribute__ ((alias ("grub_memcpy")));
+ __attribute__ ((alias ("memcpy")));
void *__aeabi_memcpy8 (void *dest, const void *src, grub_size_t n)
- __attribute__ ((alias ("grub_memcpy")));
+ __attribute__ ((alias ("memcpy")));
void *__aeabi_memset (void *s, int c, grub_size_t n)
__attribute__ ((alias ("memset")));
diff --git a/grub-core/kern/misc.c b/grub-core/kern/misc.c
index 2b7922393..016932583 100644
--- a/grub-core/kern/misc.c
+++ b/grub-core/kern/misc.c
@@ -99,6 +99,36 @@ grub_memmove (void *dest, const void *src, grub_size_t n)
return dest;
}
+static void *
+__memcpy_aligned (void *dest, const void *src, grub_size_t n)
+{
+ unsigned long *dw = (unsigned long *) dest;
+ const unsigned long *sw = (const unsigned long *) src;
+ grub_uint8_t *d;
+ const grub_uint8_t *s;
+
+ for (; n >= sizeof (unsigned long); n -= sizeof (unsigned long))
+ *dw++ = *sw++;
+
+ d = (grub_uint8_t *) dw;
+ s = (const grub_uint8_t *) sw;
+ for (; n > 0; n--)
+ *d++ = *s++;
+
+ return dest;
+}
+
+void *
+grub_memcpy (void *dest, const void *src, grub_size_t n)
+{
+ /* Check if 'dest' and 'src' are aligned */
+ if (((grub_addr_t) dest & (sizeof (unsigned long) - 1)) == 0 &&
+ ((grub_addr_t) src & (sizeof (unsigned long) - 1)) == 0)
+ return __memcpy_aligned (dest, src, n);
+
+ return grub_memmove (dest, src, n);
+}
+
char *
grub_strcpy (char *dest, const char *src)
{
diff --git a/include/grub/misc.h b/include/grub/misc.h
index e087e7b3e..b6b14ca55 100644
--- a/include/grub/misc.h
+++ b/include/grub/misc.h
@@ -38,6 +38,7 @@
#define grub_dprintf(condition, ...) grub_real_dprintf(GRUB_FILE, __LINE__, condition, __VA_ARGS__)
void *EXPORT_FUNC(grub_memmove) (void *dest, const void *src, grub_size_t n);
+void *EXPORT_FUNC(grub_memcpy) (void *dest, const void *src, grub_size_t n);
char *EXPORT_FUNC(grub_strcpy) (char *dest, const char *src);
static inline char *
@@ -103,13 +104,6 @@ grub_strlcpy (char *dest, const char *src, grub_size_t size)
return res;
}
-/* XXX: If grub_memmove is too slow, we must implement grub_memcpy. */
-static inline void *
-grub_memcpy (void *dest, const void *src, grub_size_t n)
-{
- return grub_memmove (dest, src, n);
-}
-
#if defined(__x86_64__) && !defined (GRUB_UTIL)
#if defined (__MINGW32__) || defined (__CYGWIN__) || defined (__MINGW64__)
#define GRUB_ASM_ATTR __attribute__ ((sysv_abi))
--
2.51.0

View File

@@ -105,5 +105,5 @@ as stage1 that can be too old to load updated modules.
+void *EXPORT_FUNC(grub_calloc) (grub_size_t nmemb, grub_size_t size);
+#endif
typedef grub_uint64_t grub_mem_attr_t;
void grub_mm_check_real (const char *file, int line);
#define grub_mm_check() grub_mm_check_real (GRUB_FILE, __LINE__);

View File

@@ -0,0 +1,33 @@
From 4f45e963ea913000fd8e3fe20f9afb3722073cea Mon Sep 17 00:00:00 2001
From: Maxim Suhanov <dfirblog@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 <dfirblog@gmail.com>
Reviewed-by: Daniel Kiper <daniel.kiper@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

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,194 @@
From 1bc53f8fc980914132040670b85a010e094559ec Mon Sep 17 00:00:00 2001
From: Hernan Gatta <hegatta@linux.microsoft.com>
Date: Tue, 1 Feb 2022 05:02:53 -0800
Subject: [PATCH] key_protector: Add key protectors framework
A key protector encapsulates functionality to retrieve an unlocking key
for a fully-encrypted disk from a specific source. A key protector
module registers itself with the key protectors framework when it is
loaded and unregisters when unloaded. Additionally, a key protector may
accept parameters that describe how it should operate.
The key protectors framework, besides offering registration and
unregistration functions, also offers a one-stop routine for finding and
invoking a key protector by name. If a key protector with the specified
name exists and if an unlocking key is successfully retrieved by it, the
function returns to the caller the retrieved key and its length.
Cc: Vladimir Serbinenko <phcoder@gmail.com>
Signed-off-by: Hernan Gatta <hegatta@linux.microsoft.com>
Signed-off-by: Gary Lin <glin@suse.com>
Reviewed-by: Stefan Berger <stefanb@linux.ibm.com>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
---
grub-core/Makefile.am | 1 +
grub-core/Makefile.core.def | 5 +++
grub-core/disk/key_protector.c | 73 ++++++++++++++++++++++++++++++++++
include/grub/key_protector.h | 47 ++++++++++++++++++++++
4 files changed, 126 insertions(+)
create mode 100644 grub-core/disk/key_protector.c
create mode 100644 include/grub/key_protector.h
diff --git a/grub-core/Makefile.am b/grub-core/Makefile.am
index 1eda467e0..e50db8106 100644
--- a/grub-core/Makefile.am
+++ b/grub-core/Makefile.am
@@ -90,6 +90,7 @@ endif
KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/mm.h
KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/parser.h
KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/partition.h
+KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/key_protector.h
KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/stack_protector.h
KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/term.h
KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/time.h
diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def
index a38955e18..37f131ae2 100644
--- a/grub-core/Makefile.core.def
+++ b/grub-core/Makefile.core.def
@@ -1282,6 +1282,11 @@ module = {
common = disk/raid6_recover.c;
};
+module = {
+ name = key_protector;
+ common = disk/key_protector.c;
+};
+
module = {
name = scsi;
common = disk/scsi.c;
diff --git a/grub-core/disk/key_protector.c b/grub-core/disk/key_protector.c
new file mode 100644
index 000000000..0d146c1c0
--- /dev/null
+++ b/grub-core/disk/key_protector.c
@@ -0,0 +1,73 @@
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2022 Microsoft Corporation
+ * Copyright (C) 2024 Free Software Foundation, Inc.
+ *
+ * GRUB is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GRUB is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GRUB. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <grub/dl.h>
+#include <grub/list.h>
+#include <grub/misc.h>
+#include <grub/mm.h>
+#include <grub/key_protector.h>
+
+GRUB_MOD_LICENSE ("GPLv3+");
+
+struct grub_key_protector *grub_key_protectors = NULL;
+
+grub_err_t
+grub_key_protector_register (struct grub_key_protector *protector)
+{
+ if (protector == NULL || protector->name == NULL || protector->name[0] == '\0')
+ return grub_error (GRUB_ERR_BAD_ARGUMENT, "Invalid key protector for registration");
+
+ if (grub_key_protectors != NULL &&
+ grub_named_list_find (GRUB_AS_NAMED_LIST (grub_key_protectors), protector->name) != NULL)
+ return grub_error (GRUB_ERR_BAD_ARGUMENT, "Key protector '%s' already registered", protector->name);
+
+ grub_list_push (GRUB_AS_LIST_P (&grub_key_protectors), GRUB_AS_LIST (protector));
+
+ return GRUB_ERR_NONE;
+}
+
+grub_err_t
+grub_key_protector_unregister (struct grub_key_protector *protector)
+{
+ if (protector == NULL)
+ return grub_error (GRUB_ERR_BAD_ARGUMENT, "Invalid key protector for unregistration");
+
+ grub_list_remove (GRUB_AS_LIST (protector));
+
+ return GRUB_ERR_NONE;
+}
+
+grub_err_t
+grub_key_protector_recover_key (const char *protector, grub_uint8_t **key,
+ grub_size_t *key_size)
+{
+ struct grub_key_protector *kp = NULL;
+
+ if (grub_key_protectors == NULL)
+ return grub_error (GRUB_ERR_OUT_OF_RANGE, "No key protector registered");
+
+ if (protector == NULL || protector[0] == '\0')
+ return grub_error (GRUB_ERR_BAD_ARGUMENT, "Invalid key protector");
+
+ kp = grub_named_list_find (GRUB_AS_NAMED_LIST (grub_key_protectors), protector);
+ if (kp == NULL)
+ return grub_error (GRUB_ERR_OUT_OF_RANGE, "Key protector '%s' not found", protector);
+
+ return kp->recover_key (key, key_size);
+}
diff --git a/include/grub/key_protector.h b/include/grub/key_protector.h
new file mode 100644
index 000000000..00b15c13d
--- /dev/null
+++ b/include/grub/key_protector.h
@@ -0,0 +1,47 @@
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2022 Microsoft Corporation
+ * Copyright (C) 2024 Free Software Foundation, Inc.
+ *
+ * GRUB is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GRUB is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GRUB. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef GRUB_PROTECTOR_HEADER
+#define GRUB_PROTECTOR_HEADER 1
+
+#include <grub/err.h>
+#include <grub/types.h>
+
+struct grub_key_protector
+{
+ struct grub_key_protector *next;
+ struct grub_key_protector **prev;
+
+ const char *name;
+
+ grub_err_t (*recover_key) (grub_uint8_t **key, grub_size_t *key_size);
+};
+
+grub_err_t
+grub_key_protector_register (struct grub_key_protector *protector);
+
+grub_err_t
+grub_key_protector_unregister (struct grub_key_protector *protector);
+
+grub_err_t
+grub_key_protector_recover_key (const char *protector,
+ grub_uint8_t **key,
+ grub_size_t *key_size);
+
+#endif /* ! GRUB_PROTECTOR_HEADER */
--
2.43.0

View File

@@ -0,0 +1,234 @@
From e98e880b67be178f3a5951fb345ded8c002eb6e5 Mon Sep 17 00:00:00 2001
From: Gary Lin <glin@suse.com>
Date: Wed, 13 Aug 2025 11:43:40 +0800
Subject: [PATCH 1/2] lib/crypto: Introduce new HMAC functions to reuse buffers
To enable more efficient buffer reuse for HMAC operations, three new
functions have been introduced. This change prevents the need to
reallocate memory for each HMAC operation.
* grub_crypto_hmac_reset(): Reinitializes the hash contexts in the HMAC
handle.
* grub_crypto_hmac_final(): Provides the final HMAC result without
freeing the handle, allowing it to be reused immediately.
* grub_crypto_hmac_free(): Deallocates the HMAC handle and its
associated memory.
To further facilitate buffer reuse, 'ctx2' is now included within the HMAC
handle struct, and the initialization of 'ctx2' is moved to
grub_crypto_hmac_init().
The intermediate hash states ('ctx' and 'ctx2') for the inner and outer
padded keys are now cached. grub_crypto_hmac_reset() restores these cached
states for new operations, which avoids redundant hashing of the keys.
Signed-off-by: Gary Lin <glin@suse.com>
---
grub-core/disk/geli.c | 4 +-
grub-core/lib/crypto.c | 91 ++++++++++++++++++++++++++++++------------
include/grub/crypto.h | 8 +++-
3 files changed, 74 insertions(+), 29 deletions(-)
Index: grub-2.12/grub-core/disk/geli.c
===================================================================
--- grub-2.12.orig/grub-core/disk/geli.c
+++ grub-2.12/grub-core/disk/geli.c
@@ -464,9 +464,7 @@ geli_recover_key (grub_disk_t source, gr
grub_crypto_hmac_write (hnd, header.salt, sizeof (header.salt));
grub_crypto_hmac_write (hnd, cargs->key_data, cargs->key_len);
- gcry_err = grub_crypto_hmac_fini (hnd, geomkey);
- if (gcry_err)
- return grub_crypto_gcry_error (gcry_err);
+ grub_crypto_hmac_fini (hnd, geomkey);
}
gcry_err = grub_crypto_hmac_buffer (dev->hash, geomkey,
Index: grub-2.12/grub-core/lib/crypto.c
===================================================================
--- grub-2.12.orig/grub-core/lib/crypto.c
+++ grub-2.12/grub-core/lib/crypto.c
@@ -31,7 +31,9 @@ struct grub_crypto_hmac_handle
{
const struct gcry_md_spec *md;
void *ctx;
- void *opad;
+ void *ctx2;
+ void *ctx_cache;
+ void *ctx2_cache;
};
static gcry_cipher_spec_t *grub_ciphers = NULL;
@@ -307,7 +309,8 @@ grub_crypto_hmac_init (const struct gcry
{
grub_uint8_t *helpkey = NULL;
grub_uint8_t *ipad = NULL, *opad = NULL;
- void *ctx = NULL;
+ void *ctx = NULL, *ctx2 = NULL;
+ void *ctx_cache = NULL, *ctx2_cache = NULL;
struct grub_crypto_hmac_handle *ret = NULL;
unsigned i;
@@ -318,6 +321,18 @@ grub_crypto_hmac_init (const struct gcry
if (!ctx)
goto err;
+ ctx2 = grub_malloc (md->contextsize);
+ if (!ctx2)
+ goto err;
+
+ ctx_cache = grub_malloc (md->contextsize);
+ if (!ctx_cache)
+ goto err;
+
+ ctx2_cache = grub_malloc (md->contextsize);
+ if (!ctx2_cache)
+ goto err;
+
if ( keylen > md->blocksize )
{
helpkey = grub_malloc (md->mdlen);
@@ -347,26 +362,40 @@ grub_crypto_hmac_init (const struct gcry
grub_free (helpkey);
helpkey = NULL;
+ /* inner pad */
md->init (ctx);
-
- md->write (ctx, ipad, md->blocksize); /* inner pad */
+ md->write (ctx, ipad, md->blocksize);
+ grub_memcpy (ctx_cache, ctx, md->contextsize);
grub_memset (ipad, 0, md->blocksize);
grub_free (ipad);
ipad = NULL;
+ /* outer pad */
+ md->init (ctx2);
+ md->write (ctx2, opad, md->blocksize);
+ grub_memcpy (ctx2_cache, ctx2, md->contextsize);
+ grub_memset (opad, 0, md->blocksize);
+ grub_free (opad);
+ opad = NULL;
+
ret = grub_malloc (sizeof (*ret));
if (!ret)
goto err;
ret->md = md;
ret->ctx = ctx;
- ret->opad = opad;
+ ret->ctx2 = ctx2;
+ ret->ctx_cache = ctx_cache;
+ ret->ctx2_cache = ctx2_cache;
return ret;
err:
grub_free (helpkey);
grub_free (ctx);
+ grub_free (ctx2);
+ grub_free (ctx_cache);
+ grub_free (ctx2_cache);
grub_free (ipad);
grub_free (opad);
return NULL;
@@ -380,37 +409,48 @@ grub_crypto_hmac_write (struct grub_cryp
hnd->md->write (hnd->ctx, data, datalen);
}
-gcry_err_code_t
+void
grub_crypto_hmac_fini (struct grub_crypto_hmac_handle *hnd, void *out)
{
- grub_uint8_t *p;
- grub_uint8_t *ctx2;
+ grub_crypto_hmac_final (hnd, out);
+ grub_crypto_hmac_free (hnd);
+}
- ctx2 = grub_malloc (hnd->md->contextsize);
- if (!ctx2)
- return GPG_ERR_OUT_OF_MEMORY;
+void
+grub_crypto_hmac_reset (struct grub_crypto_hmac_handle *hnd)
+{
+ grub_memcpy (hnd->ctx, hnd->ctx_cache, hnd->md->contextsize);
+ grub_memcpy (hnd->ctx2, hnd->ctx2_cache, hnd->md->contextsize);
+}
+
+void
+grub_crypto_hmac_final (struct grub_crypto_hmac_handle *hnd, void *out)
+{
+ grub_uint8_t *p;
hnd->md->final (hnd->ctx);
hnd->md->read (hnd->ctx);
p = hnd->md->read (hnd->ctx);
- hnd->md->init (ctx2);
- hnd->md->write (ctx2, hnd->opad, hnd->md->blocksize);
- hnd->md->write (ctx2, p, hnd->md->mdlen);
- hnd->md->final (ctx2);
- grub_memset (hnd->opad, 0, hnd->md->blocksize);
- grub_free (hnd->opad);
- grub_memset (hnd->ctx, 0, hnd->md->contextsize);
- grub_free (hnd->ctx);
+ hnd->md->write (hnd->ctx2, p, hnd->md->mdlen);
+ hnd->md->final (hnd->ctx2);
- grub_memcpy (out, hnd->md->read (ctx2), hnd->md->mdlen);
- grub_memset (ctx2, 0, hnd->md->contextsize);
- grub_free (ctx2);
+ grub_memcpy (out, hnd->md->read (hnd->ctx2), hnd->md->mdlen);
+}
+void
+grub_crypto_hmac_free (struct grub_crypto_hmac_handle *hnd)
+{
+ grub_memset (hnd->ctx, 0, hnd->md->contextsize);
+ grub_free (hnd->ctx);
+ grub_memset (hnd->ctx2, 0, hnd->md->contextsize);
+ grub_free (hnd->ctx2);
+ grub_memset (hnd->ctx_cache, 0, hnd->md->contextsize);
+ grub_free (hnd->ctx_cache);
+ grub_memset (hnd->ctx2_cache, 0, hnd->md->contextsize);
+ grub_free (hnd->ctx2_cache);
grub_memset (hnd, 0, sizeof (*hnd));
grub_free (hnd);
-
- return GPG_ERR_NO_ERROR;
}
gcry_err_code_t
@@ -425,7 +465,8 @@ grub_crypto_hmac_buffer (const struct gc
return GPG_ERR_OUT_OF_MEMORY;
grub_crypto_hmac_write (hnd, data, datalen);
- return grub_crypto_hmac_fini (hnd, out);
+ grub_crypto_hmac_fini (hnd, out);
+ return GPG_ERR_NO_ERROR;
}
Index: grub-2.12/include/grub/crypto.h
===================================================================
--- grub-2.12.orig/include/grub/crypto.h
+++ grub-2.12/include/grub/crypto.h
@@ -358,8 +358,14 @@ void
grub_crypto_hmac_write (struct grub_crypto_hmac_handle *hnd,
const void *data,
grub_size_t datalen);
-gcry_err_code_t
+void
grub_crypto_hmac_fini (struct grub_crypto_hmac_handle *hnd, void *out);
+void
+grub_crypto_hmac_reset (struct grub_crypto_hmac_handle *hnd);
+void
+grub_crypto_hmac_final (struct grub_crypto_hmac_handle *hnd, void *out);
+void
+grub_crypto_hmac_free (struct grub_crypto_hmac_handle *hnd);
gcry_err_code_t
grub_crypto_hmac_buffer (const struct gcry_md_spec *md,

View File

@@ -1,119 +0,0 @@
From f770cc82c3d65c65d812e96e006c17861d357d99 Mon Sep 17 00:00:00 2001
From: Michael Chang <mchang@suse.com>
Date: Sat, 26 Apr 2025 15:07:36 +0800
Subject: [PATCH 1/4] linux: fallback to EFI handover on x86_64
On the x86_64 platform, when the shim loader protocol is unavailable and
UEFI Secure Boot is enabled, fall back to the Linux EFI handover boot
protocol. This legacy method supports the in-kernel EFI stub and is used
instead of the 32-bit boot entry.
Signed-off-by: Michael Chang <mchang@suse.com>
---
grub-core/Makefile.core.def | 2 ++
grub-core/loader/efi/linux.c | 13 +++++++------
grub-core/loader/i386/efi/linux.c | 30 ++++--------------------------
3 files changed, 13 insertions(+), 32 deletions(-)
diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def
index 80ea6656a..1811661c3 100644
--- a/grub-core/Makefile.core.def
+++ b/grub-core/Makefile.core.def
@@ -1902,6 +1902,8 @@ module = {
loongarch64 = loader/efi/linux.c;
riscv32 = loader/efi/linux.c;
riscv64 = loader/efi/linux.c;
+ i386_efi = loader/efi/linux.c;
+ x86_64_efi = loader/efi/linux.c;
emu = loader/emu/linux.c;
common = loader/linux.c;
i386_efi = loader/efi/linux_boot.c;
diff --git a/grub-core/loader/efi/linux.c b/grub-core/loader/efi/linux.c
index 394df6039..b20dec404 100644
--- a/grub-core/loader/efi/linux.c
+++ b/grub-core/loader/efi/linux.c
@@ -71,10 +71,10 @@ static initrd_media_device_path_t initrd_lf2_device_path = {
};
extern grub_err_t
-grub_cmd_linux_x86_legacy (grub_command_t cmd, int argc, char *argv[]);
+grub_cmd_linux_efi_fallback (grub_command_t cmd, int argc, char *argv[]);
extern grub_err_t
-grub_cmd_initrd_x86_legacy (grub_command_t cmd, int argc, char *argv[]);
+grub_cmd_initrd_efi_fallback (grub_command_t cmd, int argc, char *argv[]);
static grub_efi_status_t __grub_efi_api
grub_efi_initrd_load_file2 (grub_efi_load_file2_t *this,
@@ -389,8 +389,9 @@ grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)),
}
#if defined(__i386__) || defined(__x86_64__)
- if (!initrd_use_loadfile2)
- return grub_cmd_initrd_x86_legacy (cmd, argc, argv);
+ if (grub_is_using_legacy_shim_lock_protocol () == true ||
+ !initrd_use_loadfile2)
+ return grub_cmd_initrd_efi_fallback (cmd, argc, argv);
#endif
if (!loaded)
@@ -474,7 +475,7 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
#if defined(__i386__) || defined(__x86_64__)
grub_dprintf ("linux", "using legacy shim_lock protocol, falling back to legacy Linux kernel loader\n");
- err = grub_cmd_linux_x86_legacy (cmd, argc, argv);
+ err = grub_cmd_linux_efi_fallback (cmd, argc, argv);
if (err == GRUB_ERR_NONE)
return GRUB_ERR_NONE;
@@ -513,7 +514,7 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
*/
fallback:
grub_file_close (file);
- return grub_cmd_linux_x86_legacy (cmd, argc, argv);
+ return grub_cmd_linux_efi_fallback (cmd, argc, argv);
}
#endif
diff --git a/grub-core/loader/i386/efi/linux.c b/grub-core/loader/i386/efi/linux.c
index ca3435a88..49e4a3f19 100644
--- a/grub-core/loader/i386/efi/linux.c
+++ b/grub-core/loader/i386/efi/linux.c
@@ -421,30 +421,8 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
return grub_errno;
}
-static grub_command_t cmd_linux, cmd_initrd;
-static grub_command_t cmd_linuxefi, cmd_initrdefi;
+extern grub_err_t __attribute__((alias("grub_cmd_linux")))
+grub_cmd_linux_efi_fallback (grub_command_t cmd, int argc, char *argv[]);
-GRUB_MOD_INIT(linux)
-{
- cmd_linuxefi =
- grub_register_command ("linuxefi", grub_cmd_linux,
- 0, N_("Load Linux."));
- cmd_initrdefi =
- grub_register_command ("initrdefi", grub_cmd_initrd,
- 0, N_("Load initrd."));
- cmd_linux =
- grub_register_command ("linux", grub_cmd_linux,
- 0, N_("Load Linux."));
- cmd_initrd =
- grub_register_command ("initrd", grub_cmd_initrd,
- 0, N_("Load initrd."));
- my_mod = mod;
-}
-
-GRUB_MOD_FINI(linux)
-{
- grub_unregister_command (cmd_linuxefi);
- grub_unregister_command (cmd_initrdefi);
- grub_unregister_command (cmd_linux);
- grub_unregister_command (cmd_initrd);
-}
+extern grub_err_t __attribute__((alias("grub_cmd_initrd")))
+grub_cmd_initrd_efi_fallback (grub_command_t cmd, int argc, char *argv[]);
--
2.50.1

View File

@@ -12,9 +12,11 @@ Signed-Off-by Michael Chang <mchang@suse.com>
grub-core/disk/luks2.c | 81 ++++++++++++++++++++++++++++++++++++++++--
1 file changed, 79 insertions(+), 2 deletions(-)
diff --git a/grub-core/disk/luks2.c b/grub-core/disk/luks2.c
index d5106402f..fe5ba777a 100644
--- a/grub-core/disk/luks2.c
+++ b/grub-core/disk/luks2.c
@@ -126,6 +126,14 @@
@@ -124,6 +124,14 @@ struct grub_luks2_digest
};
typedef struct grub_luks2_digest grub_luks2_digest_t;
@@ -29,7 +31,7 @@ Signed-Off-by Michael Chang <mchang@suse.com>
gcry_err_code_t AF_merge (const gcry_md_spec_t * hash, grub_uint8_t * src,
grub_uint8_t * dst, grub_size_t blocksize,
grub_size_t blocknumbers);
@@ -267,6 +275,39 @@
@@ -257,6 +265,39 @@ luks2_parse_digest (grub_luks2_digest_t *out, const grub_json_t *digest)
return GRUB_ERR_NONE;
}
@@ -69,7 +71,7 @@ Signed-Off-by Michael Chang <mchang@suse.com>
static grub_err_t
luks2_get_keyslot (grub_luks2_keyslot_t *k, grub_luks2_digest_t *d, grub_luks2_segment_t *s,
const grub_json_t *root, grub_size_t keyslot_json_idx)
@@ -594,13 +635,14 @@
@@ -561,13 +602,14 @@ luks2_recover_key (grub_disk_t source,
{
grub_uint8_t candidate_key[GRUB_CRYPTODISK_MAX_KEYLEN];
char cipher[32], *json_header = NULL, *ptr;
@@ -84,9 +86,9 @@ Signed-Off-by Michael Chang <mchang@suse.com>
- grub_json_t *json = NULL, keyslots;
+ grub_json_t *json = NULL, keyslots, tokens;
grub_err_t ret;
grub_size_t sz;
@@ -644,6 +686,37 @@
if (cargs->key_data == NULL || cargs->key_len == 0)
@@ -605,6 +647,37 @@ luks2_recover_key (grub_disk_t source,
goto err;
}
@@ -124,7 +126,7 @@ Signed-Off-by Michael Chang <mchang@suse.com>
if (grub_disk_native_sectors (source) == GRUB_DISK_SIZE_UNKNOWN)
{
/* FIXME: Allow use of source disk, and maybe cause errors in read. */
@@ -680,6 +753,10 @@
@@ -641,6 +714,10 @@ luks2_recover_key (grub_disk_t source,
continue;
}
@@ -135,3 +137,6 @@ Signed-Off-by Michael Chang <mchang@suse.com>
grub_dprintf ("luks2", "Trying keyslot \"%" PRIuGRUB_UINT64_T "\"\n", keyslot.idx);
/* Sector size should be one of 512, 1024, 2048, or 4096. */
--
2.42.0

View File

@@ -0,0 +1,68 @@
From f0a61161f74f9855af84778261338224d926a61f Mon Sep 17 00:00:00 2001
From: B Horn <b@horn.uk>
Date: Sat, 15 Jun 2024 02:33:08 +0100
Subject: [PATCH 01/20] misc: Implement grub_strlcpy()
grub_strlcpy() acts the same way as strlcpy() does on most *NIX,
returning the length of src and ensuring dest is always NUL
terminated except when size is 0.
Signed-off-by: B Horn <b@horn.uk>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
---
include/grub/misc.h | 39 +++++++++++++++++++++++++++++++++++++++
1 file changed, 39 insertions(+)
diff --git a/include/grub/misc.h b/include/grub/misc.h
index 6e94d18f5a..e087e7b3e8 100644
--- a/include/grub/misc.h
+++ b/include/grub/misc.h
@@ -64,6 +64,45 @@ grub_stpcpy (char *dest, const char *src)
return d - 1;
}
+static inline grub_size_t
+grub_strlcpy (char *dest, const char *src, grub_size_t size)
+{
+ char *d = dest;
+ grub_size_t res = 0;
+ /*
+ * We do not subtract one from size here to avoid dealing with underflowing
+ * the value, which is why to_copy is always checked to be greater than one
+ * throughout this function.
+ */
+ grub_size_t to_copy = size;
+
+ /* Copy size - 1 bytes to dest. */
+ if (to_copy > 1)
+ while ((*d++ = *src++) != '\0' && ++res && --to_copy > 1)
+ ;
+
+ /*
+ * NUL terminate if size != 0. The previous step may have copied a NUL byte
+ * if it reached the end of the string, but we know dest[size - 1] must always
+ * be a NUL byte.
+ */
+ if (size != 0)
+ dest[size - 1] = '\0';
+
+ /* If there is still space in dest, but are here, we reached the end of src. */
+ if (to_copy > 1)
+ return res;
+
+ /*
+ * If we haven't reached the end of the string, iterate through to determine
+ * the strings total length.
+ */
+ while (*src++ != '\0' && ++res)
+ ;
+
+ return res;
+}
+
/* XXX: If grub_memmove is too slow, we must implement grub_memcpy. */
static inline void *
grub_memcpy (void *dest, const void *src, grub_size_t n)
--
2.48.1

View File

@@ -0,0 +1,60 @@
From d35ff22516b161f6d472f7f5371a89597b072d04 Mon Sep 17 00:00:00 2001
From: Michael Chang <mchang@suse.com>
Date: Mon, 6 May 2024 10:34:22 +0800
Subject: [PATCH] net/drivers/ieee1275/ofnet: Remove 200 ms timeout in
get_card_packet() to reduce input latency
When GRUB image is netbooted on ppc64le, the keyboard input exhibits
significant latency, reports even say that characters are processed
about once per second. This issue makes interactively trying to debug
a ppc64le config very difficult.
It seems that the latency is largely caused by a 200 ms timeout in the
idle event loop, during which the network card interface is consistently
polled for incoming packets. Often, no packets arrive during this
period, so the timeout nearly always expires, which blocks the response
to key inputs.
Furthermore, this 200 ms timeout might not need to be enforced at this
basic layer, considering that GRUB performs synchronous reads and its
timeout management is actually handled by higher layers, not directly in
the card instance. Additionally, the idle polling, which reacts to
unsolicited packets like ICMP and SLAAC, would be fine at a less frequent
polling interval, rather than needing a timeout for receiving a response.
For these reasons, we believe the timeout in get_card_packet() should be
effectively removed. According to test results, the delay has disappeared,
and it is now much easier to use interactively.
Signed-Off-by: Michael Chang <mchang@suse.com>
Tested-by: Tony Jones <tonyj@suse.com>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
---
grub-core/net/drivers/ieee1275/ofnet.c | 8 ++------
1 file changed, 2 insertions(+), 6 deletions(-)
diff --git a/grub-core/net/drivers/ieee1275/ofnet.c b/grub-core/net/drivers/ieee1275/ofnet.c
index 78f03df8e..3bf48b3f0 100644
--- a/grub-core/net/drivers/ieee1275/ofnet.c
+++ b/grub-core/net/drivers/ieee1275/ofnet.c
@@ -82,15 +82,11 @@ get_card_packet (struct grub_net_card *dev)
grub_ssize_t actual;
int rc;
struct grub_ofnetcard_data *data = dev->data;
- grub_uint64_t start_time;
struct grub_net_buff *nb;
- start_time = grub_get_time_ms ();
- do
- rc = grub_ieee1275_read (data->handle, dev->rcvbuf, dev->rcvbufsize, &actual);
- while ((actual <= 0 || rc < 0) && (grub_get_time_ms () - start_time < 200));
+ rc = grub_ieee1275_read (data->handle, dev->rcvbuf, dev->rcvbufsize, &actual);
- if (actual <= 0)
+ if (actual <= 0 || rc < 0)
return NULL;
nb = grub_netbuff_alloc (actual + 2);
--
2.45.2

View File

@@ -23,9 +23,11 @@ Signed-off-by: Michael Chang <mchang@suse.com>
grub-core/disk/ieee1275/ofdisk.c | 75 +++++++++++++++++++++++---------
1 file changed, 55 insertions(+), 20 deletions(-)
diff --git a/grub-core/disk/ieee1275/ofdisk.c b/grub-core/disk/ieee1275/ofdisk.c
index c5c20a5ec..36ee5314d 100644
--- a/grub-core/disk/ieee1275/ofdisk.c
+++ b/grub-core/disk/ieee1275/ofdisk.c
@@ -36,8 +36,13 @@
@@ -35,8 +35,13 @@ static grub_ieee1275_ihandle_t last_ihandle;
#define IEEE1275_DISK_ALIAS "/disk@"
#define IEEE1275_NVMEOF_DISK_ALIAS "/nvme-of/controller@"
@@ -39,7 +41,7 @@ Signed-off-by: Michael Chang <mchang@suse.com>
static int is_boot_nvmeof;
struct ofdisk_hash_ent
@@ -554,20 +559,30 @@
@@ -540,20 +545,30 @@ dev_iterate (const struct grub_ieee1275_devalias *alias)
{
if (grub_strcmp (alias->type, "fcp") == 0)
{
@@ -79,7 +81,7 @@ Signed-off-by: Michael Chang <mchang@suse.com>
}
}
else if (grub_strcmp (alias->type, "vscsi") == 0)
@@ -590,9 +605,8 @@
@@ -575,9 +590,8 @@ dev_iterate (const struct grub_ieee1275_devalias *alias)
if (boot_type &&
grub_strcmp (boot_type, alias->type) != 0)
{
@@ -90,7 +92,7 @@ Signed-off-by: Michael Chang <mchang@suse.com>
}
if (grub_ieee1275_open (alias->path, &ihandle))
@@ -672,9 +686,8 @@
@@ -646,9 +660,8 @@ dev_iterate (const struct grub_ieee1275_devalias *alias)
if (boot_type &&
grub_strcmp (boot_type, alias->type) != 0)
{
@@ -100,8 +102,8 @@ Signed-off-by: Michael Chang <mchang@suse.com>
- goto iter_children;
}
if (grub_add (grub_strlen (alias->path), sizeof ("/disk@7766554433221100"), &sz))
@@ -1155,13 +1168,37 @@
buf = grub_malloc (grub_strlen (alias->path) +
@@ -1116,13 +1129,37 @@ get_parent_devname (const char *devname, int *is_nvmeof)
return parent;
}
@@ -142,7 +144,7 @@ Signed-off-by: Michael Chang <mchang@suse.com>
if (!canon)
{
@@ -1170,8 +1207,6 @@
@@ -1131,8 +1168,6 @@ get_boot_device_parent (const char *bootpath, int *is_nvmeof)
grub_print_error ();
return NULL;
}
@@ -151,7 +153,7 @@ Signed-off-by: Michael Chang <mchang@suse.com>
parent = get_parent_devname (canon, is_nvmeof);
early_log ("%s is parent of %s\n", parent, canon);
@@ -1225,9 +1260,9 @@
@@ -1179,9 +1214,9 @@ insert_bootpath (void)
boot_parent = get_boot_device_parent (bootpath, &is_boot_nvmeof);
boot_type = grub_ieee1275_get_device_type (boot_parent);
if (boot_type)
@@ -163,3 +165,6 @@ Signed-off-by: Michael Chang <mchang@suse.com>
}
grub_free (type);
grub_free (bootpath);
--
2.44.0

View File

@@ -37,7 +37,7 @@ Signed-off-by: Michael Chang <mchang@suse.com>
--- a/grub-core/disk/ieee1275/ofdisk.c
+++ b/grub-core/disk/ieee1275/ofdisk.c
@@ -32,6 +32,13 @@
@@ -31,6 +31,13 @@
static char *last_devpath;
static grub_ieee1275_ihandle_t last_ihandle;
@@ -51,7 +51,7 @@ Signed-off-by: Michael Chang <mchang@suse.com>
struct ofdisk_hash_ent
{
char *devpath;
@@ -543,12 +550,21 @@
@@ -529,12 +536,21 @@
{
if (grub_strcmp (alias->type, "fcp") == 0)
{
@@ -78,9 +78,9 @@ Signed-off-by: Michael Chang <mchang@suse.com>
}
else if (grub_strcmp (alias->type, "vscsi") == 0)
{
@@ -567,6 +583,14 @@
@@ -552,6 +568,14 @@
char *buf, *bufptr;
unsigned i;
grub_size_t sz;
+ if (boot_type &&
+ grub_strcmp (boot_type, alias->type) != 0)
@@ -93,9 +93,9 @@ Signed-off-by: Michael Chang <mchang@suse.com>
if (grub_ieee1275_open (alias->path, &ihandle))
return;
@@ -641,6 +665,14 @@
@@ -615,6 +639,14 @@
grub_uint16_t table_size;
grub_ieee1275_ihandle_t ihandle;
grub_size_t sz;
+ if (boot_type &&
+ grub_strcmp (boot_type, alias->type) != 0)
@@ -105,10 +105,10 @@ Signed-off-by: Michael Chang <mchang@suse.com>
+ goto iter_children;
+ }
+
if (grub_add (grub_strlen (alias->path), sizeof ("/disk@7766554433221100"), &sz))
{
grub_error (GRUB_ERR_OUT_OF_RANGE, "overflow detected while creating buffer for sas_ioa");
@@ -705,6 +737,7 @@
buf = grub_malloc (grub_strlen (alias->path) +
sizeof ("/disk@7766554433221100"));
if (!buf)
@@ -674,6 +706,7 @@
return;
}
@@ -116,7 +116,7 @@ Signed-off-by: Michael Chang <mchang@suse.com>
{
struct grub_ieee1275_devalias child;
@@ -1081,6 +1114,68 @@
@@ -1046,6 +1079,68 @@
.next = 0
};
@@ -185,7 +185,7 @@ Signed-off-by: Michael Chang <mchang@suse.com>
static void
insert_bootpath (void)
{
@@ -1123,6 +1218,12 @@
@@ -1081,6 +1176,12 @@
char *device = grub_ieee1275_get_devname (bootpath);
op = ofdisk_hash_add (device, NULL);
op->is_boot = 1;
@@ -198,7 +198,7 @@ Signed-off-by: Michael Chang <mchang@suse.com>
}
grub_free (type);
grub_free (bootpath);
@@ -1139,12 +1240,37 @@
@@ -1097,12 +1198,37 @@
grub_disk_dev_unregister (&grub_ofdisk_dev);
}

View File

@@ -0,0 +1,102 @@
From 68a2663cc316d55c2670a639c8a4a2a43ffdb141 Mon Sep 17 00:00:00 2001
From: Avnish Chouhan <avnish@linux.ibm.com>
Date: Wed, 15 Jan 2025 17:46:05 +0530
Subject: [PATCH] powerpc: increase MIN RMA size for CAS negotiation
Change RMA size from 512 MB to 768 MB which will result
in more memory at boot time for PowerPC. When PowerPC LPAR use/uses vTPM,
Secure Boot or FADump, the 512 MB RMA memory is not sufficient for
booting. With this 512 MB RMA, GRUB2 run out of memory and unable to
load the necessary. Sometimes even usage of CDROM which requires more
memory for installation along with the options mentioned above troubles
the boot memory and result in boot failures. Increasing the RMA size
will resolves multiple out of memory issues observed in PowerPC.
Failure details (GRUB2 debugs):
kern/ieee1275/init.c:550: mm requested region of size 8513000, flags 1
kern/ieee1275/init.c:563: Cannot satisfy allocation and retain minimum runtime
space
kern/ieee1275/init.c:550: mm requested region of size 8513000, flags 0
kern/ieee1275/init.c:563: Cannot satisfy allocation and retain minimum runtime
space
kern/file.c:215: Closing `/ppc/ppc64/initrd.img' ...
kern/disk.c:297: Closing
`ieee1275//vdevice/v-scsi
@30000067/disk@8300000000000000'...
kern/disk.c:311: Closing
`ieee1275//vdevice/v-scsi
@30000067/disk@8300000000000000' succeeded.
kern/file.c:225: Closing `/ppc/ppc64/initrd.img' failed with 3.
kern/file.c:148: Opening `/ppc/ppc64/initrd.img' succeeded.
error: ../../grub-core/kern/mm.c:552:out of memory.
Signed-off-by: Avnish Chouhan <avnish@linux.ibm.com>
Link: https://lore.kernel.org/r/20250115121605.56049-1-avnish@linux.ibm.com
---
grub-core/kern/ieee1275/init.c | 33 +++++++++++++++++++++++++++++----
1 file changed, 29 insertions(+), 4 deletions(-)
diff --git a/grub-core/kern/ieee1275/init.c b/grub-core/kern/ieee1275/init.c
index 8e08e5dd5c..e0634603ef 100644
--- a/grub-core/kern/ieee1275/init.c
+++ b/grub-core/kern/ieee1275/init.c
@@ -855,7 +855,7 @@ grub_ieee1275_ibm_cas (void)
.vec1 = 0x80, /* ignore */
.vec2_size = 1 + sizeof (struct option_vector2) - 2,
.vec2 = {
- 0, 0, -1, -1, -1, -1, -1, 512, -1, 0, 48
+ 0, 0, -1, -1, -1, -1, -1, 768, -1, 0, 48
},
.vec3_size = 2 - 1,
.vec3 = 0x00e0, /* ask for FP + VMX + DFP but don't halt if unsatisfied */
@@ -892,6 +892,10 @@ grub_claim_heap (void)
{
grub_err_t err;
grub_uint32_t total = HEAP_MAX_SIZE;
+#if defined(__powerpc__)
+ grub_uint32_t ibm_ca_support_reboot;
+ grub_ssize_t actual;
+#endif
err = grub_ieee1275_total_mem (&rmo_top);
@@ -904,11 +908,32 @@ grub_claim_heap (void)
grub_mm_add_region_fn = grub_ieee1275_mm_add_region;
#if defined(__powerpc__)
+ /* Check if it's a CAS reboot with below property. If so, we will skip CAS call */
+ ibm_ca_support_reboot = 0;
+ if (grub_ieee1275_get_integer_property (grub_ieee1275_chosen,
+ "ibm,client-architecture-support-reboot",
+ &ibm_ca_support_reboot,
+ sizeof (ibm_ca_support_reboot),
+ &actual) >= 0)
+ grub_dprintf ("ieee1275", "ibm,client-architecture-support-reboot: %u\n",
+ ibm_ca_support_reboot);
+
if (grub_ieee1275_test_flag (GRUB_IEEE1275_FLAG_CAN_TRY_CAS_FOR_MORE_MEMORY))
{
- /* if we have an error, don't call CAS, just hope for the best */
- if (err == GRUB_ERR_NONE && rmo_top < (512 * 1024 * 1024))
- grub_ieee1275_ibm_cas ();
+ /*
+ * If we have an error or the reboot is detected as CAS reboot,
+ * don't call CAS, just hope for the best.
+ * Along with the above, if the rmo_top is 512 MB or above. We
+ * will skip the CAS call. Though if we call CAS, the rmo_top will
+ * be set to 768 MB via CAS Vector2. This condition is required to avoid the
+ * issue where the older Linux kernels are still using rmo_top as 512 MB.
+ * Calling CAS when rmo_top is less then 768 MB will result in a issue
+ * where we won't be able to boot to a newer kernel and continue to
+ * boot with older kernel having rmo_top as 512 MB.
+ */
+ if (!ibm_ca_support_reboot && err == GRUB_ERR_NONE
+ && rmo_top < (512 * 1024 * 1024))
+ grub_ieee1275_ibm_cas ();
}
#endif
--
2.48.1

View File

@@ -0,0 +1,116 @@
From 468a37601083ef3352ff6e5d4f40ec8b1cebc4ef Mon Sep 17 00:00:00 2001
From: Michael Chang <mchang@suse.com>
Date: Tue, 8 Jul 2025 11:57:42 +0800
Subject: [PATCH] tcp: Fix TCP port number reused on reboot
GRUB's TCP stack assigns source ports for outgoing connections starting
at 21550 and increments sequentially by 1 (e.g., 21550, 21551, ...).
While this generally works, it can lead to failures if the system
reboots rapidly and reuses the same source port too soon.
This issue was observed on powerpc-ieee1275 platforms using CAS (Client
Architecture Support) reboot. In such cases, loading the initrd over
HTTP may fail with connection timeouts. Packet captures show the failed
connections are flagged as "TCP Port Number Reused" by Wireshark.
The root cause is that GRUB reuses the same port shortly after reboot,
while the server may still be tracking the previous connection in
TIME_WAIT. This can result in the server rejecting the connection
attempt or responding with a stale ACK or RST, leading to handshake
failure.
This patch fixes the issue by introducing a time based source port
selection strategy. Instead of always starting from port 21550, GRUB now
computes an initial base port based on the current RTC time, divided
into 5 minute windows. The purpose of this time based strategy is to
ensure that GRUB avoids reusing the same source port within a 5 minute
window, thereby preventing collisions with stale server side connection
tracking that could interfere with a new TCP handshake.
A step size of 8 ensures that the same port will not be reused across
reboots unless GRUB opens more than 8 TCP connections per second on
average, something that is highly unlikely. In typical usage, a GRUB
boot cycle lasts about 15 seconds and may open fewer than 100
connections total, well below the reuse threshold. This makes the
approach robust against short reboot intervals while keeping the logic
simple and deterministic.
Signed-off-by: Michael Chang <mchang@suse.com>
Reviewed-by: Sudhakar Kuppusamy <sudhakar@linux.ibm.com>
---
grub-core/net/tcp.c | 39 ++++++++++++++++++++++++++++++++++++++-
1 file changed, 38 insertions(+), 1 deletion(-)
diff --git a/grub-core/net/tcp.c b/grub-core/net/tcp.c
index 93dee0caa..d0cc602dc 100644
--- a/grub-core/net/tcp.c
+++ b/grub-core/net/tcp.c
@@ -22,6 +22,7 @@
#include <grub/net/netbuff.h>
#include <grub/time.h>
#include <grub/priority_queue.h>
+#include <grub/datetime.h>
#define TCP_SYN_RETRANSMISSION_TIMEOUT GRUB_NET_INTERVAL
#define TCP_SYN_RETRANSMISSION_COUNT GRUB_NET_TRIES
@@ -552,6 +553,36 @@ grub_net_tcp_accept (grub_net_tcp_socket_t sock,
return GRUB_ERR_NONE;
}
+/*
+ * Derive a time-based source port to avoid reusing the same port across
+ * reboots. This helps prevent failures caused by server side TCP state (e.g.
+ * TIME_WAIT) from interfering with new connections using the same socket.
+ *
+ * The base port starts at 21550 and increments every second by 8 across a 5
+ * minute window (300 seconds), giving 2400 possible distinct base ports per
+ * window. In typical GRUB usage, the number of connections per boot is small,
+ * so reuse is effectively avoided.
+ */
+static grub_uint16_t
+get_initial_base_port (void)
+{
+ grub_err_t err;
+ struct grub_datetime date;
+ grub_int64_t t = 0;
+ grub_uint64_t r = 0;
+
+ err = grub_get_datetime (&date);
+ if (err != GRUB_ERR_NONE || !grub_datetime2unixtime (&date, &t))
+ {
+ grub_errno = GRUB_ERR_NONE;
+ return 21550;
+ }
+
+ grub_divmod64 (t, 300, &r);
+
+ return 21550 + (r << 3);
+}
+
grub_net_tcp_socket_t
grub_net_tcp_open (char *server,
grub_uint16_t out_port,
@@ -569,13 +600,19 @@ grub_net_tcp_open (char *server,
struct grub_net_network_level_interface *inf;
grub_net_network_level_address_t gateway;
grub_net_tcp_socket_t socket;
- static grub_uint16_t in_port = 21550;
+ static grub_uint16_t in_port;
struct grub_net_buff *nb;
struct tcphdr *tcph;
int i;
grub_uint8_t *nbd;
grub_net_link_level_address_t ll_target_addr;
+ if (!in_port)
+ {
+ in_port = get_initial_base_port ();
+ grub_dprintf ("net", "base port: %d\n", in_port);
+ }
+
err = grub_net_resolve_address (server, &addr);
if (err)
return NULL;
--
2.50.1

View File

@@ -0,0 +1,38 @@
From f0a08324d0f923527ba611887a3780c1f2cb1578 Mon Sep 17 00:00:00 2001
From: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Date: Tue, 21 Jan 2025 11:01:26 -0600
Subject: [PATCH] term/ns8250-spcr: Return if redirection is disabled
The Microsoft spec for SPCR says "The base address of the Serial Port
register set described using the ACPI Generic Address Structure, or
0 if console redirection is disabled". So, return early if redirection
is disabled (base address = 0). If this check is not done we may get
invalid ports on machines with redirection disabled and boot may hang
when reading the grub.cfg file.
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Reviewed-by: Leo Sandoval <lsandova@redhat.com>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
---
grub-core/term/ns8250-spcr.c | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/grub-core/term/ns8250-spcr.c b/grub-core/term/ns8250-spcr.c
index 4efaaf768..428b2d59a 100644
--- a/grub-core/term/ns8250-spcr.c
+++ b/grub-core/term/ns8250-spcr.c
@@ -76,6 +76,11 @@ grub_ns8250_spcr_init (void)
config.speed = 115200;
break;
};
+
+ /* If base address is 0 it means redirection is disabled. */
+ if (spcr->base_addr.addr == 0)
+ return NULL;
+
switch (spcr->base_addr.space_id)
{
case GRUB_ACPI_GENADDR_MEM_SPACE:
--
2.51.0

View File

@@ -0,0 +1,44 @@
From cda4b7a415eb45743ea54a7760b302c0cfe718cf Mon Sep 17 00:00:00 2001
From: Michael Chang <mchang@suse.com>
Date: Mon, 23 Sep 2024 10:32:18 +0800
Subject: [PATCH] tpm: Skip loopback image measurement
The loopback image is configured to function as a disk by being mapped
as a block device. Instead of measuring the entire block device, we
should focus on tracking the individual files accessed from it. For
example, we do not directly measure block devices like disk hd0, but the
files opened from it.
This method is important to avoid running out of memory, since loopback
images can be very large. Trying to read and measure the whole image at
once could cause out of memory errors and disrupt the boot process.
Signed-Off-by: Michael Chang <mchang@suse.com>
---
grub-core/commands/tpm.c | 10 ++++++++++
1 file changed, 10 insertions(+)
diff --git a/grub-core/commands/tpm.c b/grub-core/commands/tpm.c
index bb9aee210..ebbb4fef0 100644
--- a/grub-core/commands/tpm.c
+++ b/grub-core/commands/tpm.c
@@ -41,6 +41,16 @@ grub_tpm_verify_init (grub_file_t io,
{
*context = io->name;
*flags |= GRUB_VERIFY_FLAGS_SINGLE_CHUNK;
+
+ /*
+ * The loopback image is mapped as a disk, allowing it to function like a
+ * block device. However, we measure the files read from the block device,
+ * not the device itself. For example, we don't measure block devices like
+ * disk hd0 directly. This process is crucial to prevent out-of-memory
+ * errors, as loopback images are inherently large.
+ */
+ if ((type & GRUB_FILE_TYPE_MASK) == GRUB_FILE_TYPE_LOOPBACK)
+ *flags = GRUB_VERIFY_FLAGS_SKIP_VERIFICATION;
return GRUB_ERR_NONE;
}
--
2.46.1

View File

@@ -0,0 +1,241 @@
From 76a2bcb99754ee5b4159c35f66042e392139b815 Mon Sep 17 00:00:00 2001
From: Gary Lin <glin@suse.com>
Date: Fri, 15 Nov 2024 15:34:59 +0800
Subject: [PATCH] tpm2_key_protector: Add grub-emu support
As a preparation to test tpm2_key_protector with grub-emu, the new
option, --tpm-device, is introduced to specify the TPM device for
grub-emu so that grub-emu can access an emulated TPM device from
the host.
Since grub-emu can directly access the device on host, it's easy to
implement the essential TCG2 command submission function with the
read/write functions and enable tpm2_key_protector module for grub-emu,
so that we can further test TPM2 key unsealing with grub-emu.
Signed-off-by: Gary Lin <glin@suse.com>
Reviewed-by: Stefan Berger <stefanb@linux.ibm.com>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
Tested-by: Stefan Berger <stefanb@linux.ibm.com>
---
grub-core/Makefile.core.def | 3 +++
grub-core/kern/emu/main.c | 11 +++++++-
grub-core/kern/emu/misc.c | 51 +++++++++++++++++++++++++++++++++++
grub-core/lib/tss2/tcg2_emu.c | 49 +++++++++++++++++++++++++++++++++
include/grub/emu/misc.h | 5 ++++
5 files changed, 118 insertions(+), 1 deletion(-)
create mode 100644 grub-core/lib/tss2/tcg2_emu.c
Index: grub-2.12/grub-core/Makefile.core.def
===================================================================
--- grub-2.12.orig/grub-core/Makefile.core.def
+++ grub-2.12/grub-core/Makefile.core.def
@@ -2628,7 +2628,9 @@ module = {
common = lib/tss2/tpm2_cmd.c;
common = lib/tss2/tss2.c;
efi = lib/efi/tcg2.c;
+ emu = lib/tss2/tcg2_emu.c;
enable = efi;
+ enable = emu;
cppflags = '-I$(srcdir)/lib/tss2';
};
@@ -2640,6 +2642,7 @@ module = {
common = commands/tpm2_key_protector/tpm2key_asn1_tab.c;
/* The plaform support of tpm2_key_protector depends on the tcg2 implementation in tss2. */
enable = efi;
+ enable = emu;
cppflags = '-I$(srcdir)/lib/tss2';
};
Index: grub-2.12/grub-core/kern/emu/main.c
===================================================================
--- grub-2.12.orig/grub-core/kern/emu/main.c
+++ grub-2.12/grub-core/kern/emu/main.c
@@ -55,7 +55,7 @@
static jmp_buf main_env;
/* Store the prefix specified by an argument. */
-static char *root_dev = NULL, *dir = NULL;
+static char *root_dev = NULL, *dir = NULL, *tpm_dev = NULL;
grub_addr_t grub_modbase = 0;
@@ -108,6 +108,7 @@ static struct argp_option options[] = {
{"verbose", 'v', 0, 0, N_("print verbose messages."), 0},
{"hold", 'H', N_("SECS"), OPTION_ARG_OPTIONAL, N_("wait until a debugger will attach"), 0},
{"kexec", 'X', 0, 0, N_("use kexec to boot Linux kernels via systemctl (pass twice to enable dangerous fallback to non-systemctl)."), 0},
+ {"tpm-device", 't', N_("DEV"), 0, N_("set TPM device."), 0},
{ 0, 0, 0, 0, 0, 0 }
};
@@ -168,6 +169,10 @@ argp_parser (int key, char *arg, struct
case 'X':
grub_util_set_kexecute ();
break;
+ case 't':
+ free (tpm_dev);
+ tpm_dev = xstrdup (arg);
+ break;
case ARGP_KEY_ARG:
{
@@ -282,6 +287,9 @@ main (int argc, char *argv[])
dir = xstrdup (dir);
+ if (tpm_dev)
+ grub_util_tpm_open (tpm_dev);
+
/* Start GRUB! */
if (setjmp (main_env) == 0)
grub_main ();
@@ -289,6 +297,7 @@ main (int argc, char *argv[])
grub_fini_all ();
grub_hostfs_fini ();
grub_host_fini ();
+ grub_util_tpm_close ();
grub_machine_fini (GRUB_LOADER_FLAG_NORETURN);
Index: grub-2.12/grub-core/kern/emu/misc.c
===================================================================
--- grub-2.12.orig/grub-core/kern/emu/misc.c
+++ grub-2.12/grub-core/kern/emu/misc.c
@@ -28,6 +28,8 @@
#include <string.h>
#include <sys/time.h>
#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
#include <grub/mm.h>
#include <grub/err.h>
@@ -41,6 +43,8 @@
int verbosity;
int kexecute;
+static int grub_util_tpm_fd = -1;
+
void
grub_util_warn (const char *fmt, ...)
{
@@ -230,3 +234,50 @@ grub_util_get_kexecute (void)
{
return kexecute;
}
+
+grub_err_t
+grub_util_tpm_open (const char *tpm_dev)
+{
+ if (grub_util_tpm_fd != -1)
+ return GRUB_ERR_NONE;
+
+ grub_util_tpm_fd = open (tpm_dev, O_RDWR);
+ if (grub_util_tpm_fd == -1)
+ grub_util_error (_("cannot open TPM device '%s': %s"), tpm_dev, strerror (errno));
+
+ return GRUB_ERR_NONE;
+}
+
+grub_err_t
+grub_util_tpm_close (void)
+{
+ int err;
+
+ if (grub_util_tpm_fd == -1)
+ return GRUB_ERR_NONE;
+
+ err = close (grub_util_tpm_fd);
+ if (err != GRUB_ERR_NONE)
+ grub_util_error (_("cannot close TPM device: %s"), strerror (errno));
+
+ grub_util_tpm_fd = -1;
+ return GRUB_ERR_NONE;
+}
+
+grub_size_t
+grub_util_tpm_read (void *output, grub_size_t size)
+{
+ if (grub_util_tpm_fd == -1)
+ return -1;
+
+ return read (grub_util_tpm_fd, output, size);
+}
+
+grub_size_t
+grub_util_tpm_write (const void *input, grub_size_t size)
+{
+ if (grub_util_tpm_fd == -1)
+ return -1;
+
+ return write (grub_util_tpm_fd, input, size);
+}
Index: grub-2.12/grub-core/lib/tss2/tcg2_emu.c
===================================================================
--- /dev/null
+++ grub-2.12/grub-core/lib/tss2/tcg2_emu.c
@@ -0,0 +1,49 @@
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2024 SUSE LLC
+ * Copyright (C) 2024 Free Software Foundation, Inc.
+ *
+ * GRUB is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GRUB is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GRUB. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <grub/mm.h>
+#include <grub/emu/misc.h>
+
+#include <tss2_buffer.h>
+#include <tss2_structs.h>
+#include <tcg2.h>
+
+grub_err_t
+grub_tcg2_get_max_output_size (grub_size_t *size)
+{
+ if (size == NULL)
+ return GRUB_ERR_BAD_ARGUMENT;
+
+ *size = GRUB_TPM2_BUFFER_CAPACITY;
+
+ return GRUB_ERR_NONE;
+}
+
+grub_err_t
+grub_tcg2_submit_command (grub_size_t input_size, grub_uint8_t *input,
+ grub_size_t output_size, grub_uint8_t *output)
+{
+ if (grub_util_tpm_write (input, input_size) != input_size)
+ return GRUB_ERR_BAD_DEVICE;
+
+ if (grub_util_tpm_read (output, output_size) < sizeof (TPM_RESPONSE_HEADER_t))
+ return GRUB_ERR_BAD_DEVICE;
+
+ return GRUB_ERR_NONE;
+}
Index: grub-2.12/include/grub/emu/misc.h
===================================================================
--- grub-2.12.orig/include/grub/emu/misc.h
+++ grub-2.12/include/grub/emu/misc.h
@@ -75,4 +75,9 @@ grub_util_fopen (const char *path, const
int grub_util_file_sync (FILE *f);
+grub_err_t grub_util_tpm_open (const char *tpm_dev);
+grub_err_t grub_util_tpm_close (void);
+grub_size_t EXPORT_FUNC(grub_util_tpm_read) (void *output, grub_size_t size);
+grub_size_t EXPORT_FUNC(grub_util_tpm_write) (const void *input, grub_size_t size);
+
#endif /* GRUB_EMU_MISC_H */

View File

@@ -0,0 +1,253 @@
From 617dab9e476e8ea5aa314dcc5412bbd8a6f1f465 Mon Sep 17 00:00:00 2001
From: Gary Lin <glin@suse.com>
Date: Mon, 7 Apr 2025 16:29:15 +0800
Subject: [PATCH 1/7] tpm2_key_protector: Dump PCRs on policy fail
PCR mismatch is one common cause of TPM key unsealing fail. Since the
system may be compromised, it is not safe to boot into OS to get the PCR
values and TPM eventlog for the further investigation.
To provide some hints, GRUB now dumps PCRs on policy fail, so the user
can check the current PCR values. PCR 0~15 are chosen to cover the
firmware, bootloader, and OS.
The sample output:
PCR Mismatch! Check firmware and bootloader before typing passphrase!
TPM PCR [sha256]:
00: 17401f37710984c1d8a03a81fff3ab567ae9291bac61e21715b890ee28879738
01: 7a114329ba388445a96e8db2a072785937c1b7a8803ed7cc682b87f3ff3dd7a8
02: 11c2776849e8e24b7d80c926cbc4257871bffa744dadfefd3ed049ce25143e05
03: 6c33b362073e28e30b47302bbdd3e6f9cee4debca3a304e646f8c68245724350
04: 62d38838483ecfd2484ee3a2e5450d8ca3b35fc72cda6a8c620f9f43521c37d1
05: d8a85cb37221ab7d1f2cc5f554dbe0463acb6784b5b8dc3164ccaa66d8fff0e1
06: 9262e37cbe71ed4daf815b4a4881fb7251c9d371092dde827557d5368121e10e
07: 219d542233be492d62b079ffe46cf13396a8c27e520e88b08eaf2e6d3b7e70f5
08: de1f61c973b673e505adebe0d7e8fb65fde6c24dd4ab4fbaff9e28b18df6ecd3
09: c1de7274fa3e879a16d7e6e7629e3463d95f68adcfd17c477183846dccc41c89
10: 0000000000000000000000000000000000000000000000000000000000000000
11: 0000000000000000000000000000000000000000000000000000000000000000
12: 0000000000000000000000000000000000000000000000000000000000000000
13: 0000000000000000000000000000000000000000000000000000000000000000
14: 9ab9ebe4879a7f4dd00c04f37e79cfd69d0dd7a8bcc6b01135525b67676a3e40
15: 0000000000000000000000000000000000000000000000000000000000000000
16: 0000000000000000000000000000000000000000000000000000000000000000
17: ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
18: ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
19: ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
20: ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
21: ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
22: ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
23: 0000000000000000000000000000000000000000000000000000000000000000
error: failed to unseal sealed key (TPM2_Unseal: 0x99d).
error: no key protector provided a usable key for luks (af16e48f-746b-4a12-aae1-c14dcee429e0).
If the user happens to have the PCR values for key sealing, the PCR dump
can be used to identify the changed PCRs and narrow down the scope for
closer inspection.
Please note that the PCR dump is trustworthy only if the GRUB binary is
authentic, so the user has to check the GRUB binary thoroughly before
using the PCR dump.
Signed-off-by: Gary Lin <glin@suse.com>
Reviewed-by: Stefan Berger <stefanb@linux.ibm.com>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
---
.../commands/tpm2_key_protector/module.c | 118 +++++++++++++++++-
1 file changed, 114 insertions(+), 4 deletions(-)
diff --git a/grub-core/commands/tpm2_key_protector/module.c b/grub-core/commands/tpm2_key_protector/module.c
index 74e79a545..d5e530f77 100644
--- a/grub-core/commands/tpm2_key_protector/module.c
+++ b/grub-core/commands/tpm2_key_protector/module.c
@@ -790,7 +790,7 @@ tpm2_protector_simple_policy_seq (const tpm2_protector_context_t *ctx,
static grub_err_t
tpm2_protector_unseal (tpm2key_policy_t policy_seq, TPM_HANDLE_t sealed_handle,
- grub_uint8_t **key, grub_size_t *key_size)
+ grub_uint8_t **key, grub_size_t *key_size, bool *dump_pcr)
{
TPMS_AUTH_COMMAND_t authCmd = {0};
TPM2B_SENSITIVE_DATA_t data;
@@ -801,6 +801,8 @@ tpm2_protector_unseal (tpm2key_policy_t policy_seq, TPM_HANDLE_t sealed_handle,
TPM_RC_t rc;
grub_err_t err;
+ *dump_pcr = false;
+
/* Start Auth Session */
nonceCaller.size = TPM_SHA256_DIGEST_SIZE;
symmetric.algorithm = TPM_ALG_NULL;
@@ -820,6 +822,13 @@ tpm2_protector_unseal (tpm2key_policy_t policy_seq, TPM_HANDLE_t sealed_handle,
rc = grub_tpm2_unseal (sealed_handle, &authCmd, &data, NULL);
if (rc != TPM_RC_SUCCESS)
{
+ /*
+ * Trigger PCR dump on policy fail
+ * TPM_RC_S (0x800) | TPM_RC_1 (0x100) | RC_FMT (0x80) | TPM_RC_POLICY_FAIL (0x1D)
+ */
+ if (rc == 0x99D)
+ *dump_pcr = true;
+
err = grub_error (GRUB_ERR_BAD_DEVICE, "failed to unseal sealed key (TPM2_Unseal: 0x%x)", rc);
goto error;
}
@@ -845,6 +854,91 @@ tpm2_protector_unseal (tpm2key_policy_t policy_seq, TPM_HANDLE_t sealed_handle,
return err;
}
+#define TPM_PCR_STR_SIZE (sizeof (TPMU_HA_t) * 2 + 1)
+
+static grub_err_t
+tpm2_protector_get_pcr_str (const TPM_ALG_ID_t algo, grub_uint32_t index, char *pcr_str, grub_uint16_t buf_size)
+{
+ TPML_PCR_SELECTION_t pcr_sel = {
+ .count = 1,
+ .pcrSelections = {
+ {
+ .hash = algo,
+ .sizeOfSelect = 3,
+ .pcrSelect = {0}
+ },
+ }
+ };
+ TPML_DIGEST_t digest = {0};
+ grub_uint16_t i;
+ TPM_RC_t rc;
+
+ if (buf_size < TPM_PCR_STR_SIZE)
+ {
+ grub_snprintf (pcr_str, buf_size, "insufficient buffer");
+ return GRUB_ERR_OUT_OF_MEMORY;
+ }
+
+ TPMS_PCR_SELECTION_SelectPCR (&pcr_sel.pcrSelections[0], index);
+
+ rc = grub_tpm2_pcr_read (NULL, &pcr_sel, NULL, NULL, &digest, NULL);
+ if (rc != TPM_RC_SUCCESS)
+ {
+ grub_snprintf (pcr_str, buf_size, "TPM2_PCR_Read: 0x%x", rc);
+ return GRUB_ERR_BAD_DEVICE;
+ }
+
+ /* Check the returned digest number and size */
+ if (digest.count != 1 || digest.digests[0].size > sizeof (TPMU_HA_t))
+ {
+ grub_snprintf (pcr_str, buf_size, "invalid digest");
+ return GRUB_ERR_BAD_DEVICE;
+ }
+
+ /* Print the digest to the buffer */
+ for (i = 0; i < digest.digests[0].size; i++)
+ grub_snprintf (pcr_str + 2 * i, buf_size - 2 * i, "%02x", digest.digests[0].buffer[i]);
+
+ return GRUB_ERR_NONE;
+}
+
+static void
+tpm2_protector_dump_pcr (const TPM_ALG_ID_t bank)
+{
+ const char *algo_name;
+ char pcr_str[TPM_PCR_STR_SIZE];
+ grub_uint8_t i;
+ grub_err_t err;
+
+ if (bank == TPM_ALG_SHA1)
+ algo_name = "sha1";
+ else if (bank == TPM_ALG_SHA256)
+ algo_name = "sha256";
+ else if (bank == TPM_ALG_SHA384)
+ algo_name = "sha384";
+ else if (bank == TPM_ALG_SHA512)
+ algo_name = "sha512";
+ else
+ algo_name = "other";
+
+ /* Try to fetch PCR 0 */
+ err = tpm2_protector_get_pcr_str (bank, 0, pcr_str, sizeof (pcr_str));
+ if (err != GRUB_ERR_NONE)
+ {
+ grub_printf ("Unsupported PCR bank [%s]: %s\n", algo_name, pcr_str);
+ return;
+ }
+
+ grub_printf ("TPM PCR [%s]:\n", algo_name);
+
+ grub_printf (" %02d: %s\n", 0, pcr_str);
+ for (i = 1; i < TPM_MAX_PCRS; i++)
+ {
+ tpm2_protector_get_pcr_str (bank, i, pcr_str, sizeof (pcr_str));
+ grub_printf (" %02d: %s\n", i, pcr_str);
+ }
+}
+
static grub_err_t
tpm2_protector_srk_recover (const tpm2_protector_context_t *ctx,
grub_uint8_t **key, grub_size_t *key_size)
@@ -859,6 +953,7 @@ tpm2_protector_srk_recover (const tpm2_protector_context_t *ctx,
tpm2key_policy_t policy_seq = NULL;
tpm2key_authpolicy_t authpol = NULL;
tpm2key_authpolicy_t authpol_seq = NULL;
+ bool dump_pcr = false;
grub_err_t err;
/*
@@ -924,7 +1019,7 @@ tpm2_protector_srk_recover (const tpm2_protector_context_t *ctx,
/* Iterate the authpolicy sequence to find one that unseals the key */
FOR_LIST_ELEMENTS (authpol, authpol_seq)
{
- err = tpm2_protector_unseal (authpol->policy_seq, sealed_handle, key, key_size);
+ err = tpm2_protector_unseal (authpol->policy_seq, sealed_handle, key, key_size, &dump_pcr);
if (err == GRUB_ERR_NONE)
break;
@@ -952,13 +1047,20 @@ tpm2_protector_srk_recover (const tpm2_protector_context_t *ctx,
goto exit2;
}
- err = tpm2_protector_unseal (policy_seq, sealed_handle, key, key_size);
+ err = tpm2_protector_unseal (policy_seq, sealed_handle, key, key_size, &dump_pcr);
}
/* Pop error messages on success */
if (err == GRUB_ERR_NONE)
while (grub_error_pop ());
+ /* Dump PCRs if necessary */
+ if (dump_pcr == true)
+ {
+ grub_printf ("PCR Mismatch! Check firmware and bootloader before typing passphrase!\n");
+ tpm2_protector_dump_pcr (ctx->bank);
+ }
+
exit2:
grub_tpm2_flushcontext (sealed_handle);
@@ -978,6 +1080,7 @@ tpm2_protector_nv_recover (const tpm2_protector_context_t *ctx,
{
TPM_HANDLE_t sealed_handle = ctx->nv;
tpm2key_policy_t policy_seq = NULL;
+ bool dump_pcr = false;
grub_err_t err;
/* Create a basic policy sequence based on the given PCR selection */
@@ -985,7 +1088,14 @@ tpm2_protector_nv_recover (const tpm2_protector_context_t *ctx,
if (err != GRUB_ERR_NONE)
goto exit;
- err = tpm2_protector_unseal (policy_seq, sealed_handle, key, key_size);
+ err = tpm2_protector_unseal (policy_seq, sealed_handle, key, key_size, &dump_pcr);
+
+ /* Dump PCRs if necessary */
+ if (dump_pcr == true)
+ {
+ grub_printf ("PCR Mismatch! Check firmware and bootloader before typing passphrase!\n");
+ tpm2_protector_dump_pcr (ctx->bank);
+ }
exit:
grub_tpm2_flushcontext (sealed_handle);
--
2.43.0

View File

@@ -0,0 +1,81 @@
From 53e24662523d033ae3506b73787b972ef332db36 Mon Sep 17 00:00:00 2001
From: Patrick Colp <patrick.colp@oracle.com>
Date: Mon, 31 Jul 2023 07:01:45 -0700
Subject: [PATCH] tpm2_key_protector: Implement NV index
Currently with the TPM2 protector, only SRK mode is supported and
NV index support is just a stub. Implement the NV index option.
Note: This only extends support on the unseal path. grub-protect
has not been updated. tpm2-tools can be used to insert a key into
the NV index.
An example of inserting a key using tpm2-tools:
# Get random key.
tpm2_getrandom 32 > key.dat
# Create primary object.
tpm2_createprimary -C o -g sha256 -G ecc -c primary.ctx
# Create policy object. `pcrs.dat` contains the PCR values to seal against.
tpm2_startauthsession -S session.dat
tpm2_policypcr -S session.dat -l sha256:7,11 -f pcrs.dat -L policy.dat
tpm2_flushcontext session.dat
# Seal key into TPM.
cat key.dat | tpm2_create -C primary.ctx -u key.pub -r key.priv -L policy.dat -i-
tpm2_load -C primary.ctx -u key.pub -r key.priv -n sealing.name -c sealing.ctx
tpm2_evictcontrol -C o -c sealing.ctx 0x81000000
Then to unseal the key in grub, add this to grub.cfg:
tpm2_key_protector_init --mode=nv --nvindex=0x81000000 --pcrs=7,11
cryptomount -u <UUID> --protector tpm2
Signed-off-by: Patrick Colp <patrick.colp@oracle.com>
Signed-off-by: Gary Lin <glin@suse.com>
Reviewed-by: Stefan Berger <stefanb@linux.ibm.com>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
---
.../commands/tpm2_key_protector/module.c | 23 +++++++++++++++----
1 file changed, 19 insertions(+), 4 deletions(-)
diff --git a/grub-core/commands/tpm2_key_protector/module.c b/grub-core/commands/tpm2_key_protector/module.c
index 6b4b5d460..74e79a545 100644
--- a/grub-core/commands/tpm2_key_protector/module.c
+++ b/grub-core/commands/tpm2_key_protector/module.c
@@ -973,11 +973,26 @@ tpm2_protector_srk_recover (const tpm2_protector_context_t *ctx,
}
static grub_err_t
-tpm2_protector_nv_recover (const tpm2_protector_context_t *ctx __attribute__ ((unused)),
- grub_uint8_t **key __attribute__ ((unused)),
- grub_size_t *key_size __attribute__ ((unused)))
+tpm2_protector_nv_recover (const tpm2_protector_context_t *ctx,
+ grub_uint8_t **key, grub_size_t *key_size)
{
- return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, "NV Index mode is not implemented yet");
+ TPM_HANDLE_t sealed_handle = ctx->nv;
+ tpm2key_policy_t policy_seq = NULL;
+ grub_err_t err;
+
+ /* Create a basic policy sequence based on the given PCR selection */
+ err = tpm2_protector_simple_policy_seq (ctx, &policy_seq);
+ if (err != GRUB_ERR_NONE)
+ goto exit;
+
+ err = tpm2_protector_unseal (policy_seq, sealed_handle, key, key_size);
+
+ exit:
+ grub_tpm2_flushcontext (sealed_handle);
+
+ grub_tpm2key_free_policy_seq (policy_seq);
+
+ return err;
}
static grub_err_t
--
2.43.0

View File

@@ -0,0 +1,158 @@
From 7ef1b9b357c803cb8e30bbbebd44494b2b5c9d09 Mon Sep 17 00:00:00 2001
From: Gary Lin <glin@suse.com>
Date: Thu, 6 Apr 2023 16:00:25 +0800
Subject: [PATCH] tpm2_key_protector: Support authorized policy
This commit handles the TPM2_PolicyAuthorize command from the key file
in TPM 2.0 Key File format.
TPM2_PolicyAuthorize is the essential command to support authorized
policy which allows the users to sign TPM policies with their own keys.
Per TPM 2.0 Key File(*1), CommandPolicy for TPM2_PolicyAuthorize
comprises 'TPM2B_PUBLIC pubkey', 'TPM2B_DIGEST policy_ref', and
'TPMT_SIGNATURE signature'. To verify the signature, the current policy
digest is hashed with the hash algorithm written in 'signature', and then
'signature' is verified with the hashed policy digest and 'pubkey'. Once
TPM accepts 'signature', TPM2_PolicyAuthorize is invoked to authorize the
signed policy.
To create the key file with authorized policy, here are the pcr-oracle(*2)
commands:
# Generate the RSA key and create the authorized policy file
$ pcr-oracle \
--rsa-generate-key \
--private-key policy-key.pem \
--auth authorized.policy \
create-authorized-policy 0,2,4,7,9
# Seal the secret with the authorized policy
$ pcr-oracle \
--key-format tpm2.0 \
--auth authorized.policy \
--input disk-secret.txt \
--output sealed.key \
seal-secret
# Sign the predicted PCR policy
$ pcr-oracle \
--key-format tpm2.0 \
--private-key policy-key.pem \
--from eventlog \
--stop-event "grub-file=grub.cfg" \
--after \
--input sealed.key \
--output /boot/efi/efi/grub/sealed.tpm \
sign 0,2,4,7,9
Then specify the key file and the key protector to grub.cfg in the EFI
system partition:
tpm2_key_protector_init -a RSA --tpm2key=(hd0,gpt1)/efi/grub/sealed.tpm
cryptomount -u <PART_UUID> -P tpm2
For any change in the boot components, just run the 'sign' command again
to update the signature in sealed.tpm, and TPM can unseal the key file
with the updated PCR policy.
(*1) https://www.hansenpartnership.com/draft-bottomley-tpm2-keys.html
(*2) https://github.com/okirch/pcr-oracle
Signed-off-by: Gary Lin <glin@suse.com>
Reviewed-by: Stefan Berger <stefanb@linux.ibm.com>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
---
.../commands/tpm2_key_protector/module.c | 70 +++++++++++++++++++
1 file changed, 70 insertions(+)
diff --git a/grub-core/commands/tpm2_key_protector/module.c b/grub-core/commands/tpm2_key_protector/module.c
index 70d4d0df7..6b4b5d460 100644
--- a/grub-core/commands/tpm2_key_protector/module.c
+++ b/grub-core/commands/tpm2_key_protector/module.c
@@ -618,6 +618,73 @@ tpm2_protector_policypcr (TPMI_SH_AUTH_SESSION_t session, struct grub_tpm2_buffe
return GRUB_ERR_NONE;
}
+static grub_err_t
+tpm2_protector_policyauthorize (TPMI_SH_AUTH_SESSION_t session, struct grub_tpm2_buffer *cmd_buf)
+{
+ TPM2B_PUBLIC_t pubkey;
+ TPM2B_DIGEST_t policy_ref;
+ TPMT_SIGNATURE_t signature;
+ TPM2B_DIGEST_t pcr_policy;
+ TPM2B_DIGEST_t pcr_policy_hash;
+ TPMI_ALG_HASH_t sig_hash;
+ TPMT_TK_VERIFIED_t verification_ticket;
+ TPM_HANDLE_t pubkey_handle = 0;
+ TPM2B_NAME_t pubname;
+ TPM_RC_t rc;
+ grub_err_t err;
+
+ grub_Tss2_MU_TPM2B_PUBLIC_Unmarshal (cmd_buf, &pubkey);
+ grub_Tss2_MU_TPM2B_DIGEST_Unmarshal (cmd_buf, &policy_ref);
+ grub_Tss2_MU_TPMT_SIGNATURE_Unmarshal (cmd_buf, &signature);
+ if (cmd_buf->error != 0)
+ return grub_error (GRUB_ERR_BAD_ARGUMENT, "failed to unmarshal the buffer for TPM2_PolicyAuthorize");
+
+ /* Retrieve Policy Digest */
+ rc = grub_tpm2_policygetdigest (session, NULL, &pcr_policy, NULL);
+ if (rc != TPM_RC_SUCCESS)
+ return grub_error (GRUB_ERR_BAD_DEVICE, "failed to get policy digest (TPM2_PolicyGetDigest: 0x%x).", rc);
+
+ /* Calculate the digest of the polcy for VerifySignature */
+ sig_hash = TPMT_SIGNATURE_get_hash_alg (&signature);
+ if (sig_hash == TPM_ALG_NULL)
+ return grub_error (GRUB_ERR_BAD_ARGUMENT, "failed to get the hash algorithm of the signature");
+
+ rc = grub_tpm2_hash (NULL, (TPM2B_MAX_BUFFER_t *) &pcr_policy, sig_hash,
+ TPM_RH_NULL, &pcr_policy_hash, NULL, NULL);
+ if (rc != TPM_RC_SUCCESS)
+ return grub_error (GRUB_ERR_BAD_DEVICE, "failed to create PCR policy hash (TPM2_Hash: 0x%x)", rc);
+
+ /* Load the public key */
+ rc = grub_tpm2_loadexternal (NULL, NULL, &pubkey, TPM_RH_OWNER, &pubkey_handle, &pubname, NULL);
+ if (rc != TPM_RC_SUCCESS)
+ return grub_error (GRUB_ERR_BAD_DEVICE, "failed to load public key (TPM2_LoadExternal: 0x%x)", rc);
+
+ /* Verify the signature against the public key and the policy digest */
+ rc = grub_tpm2_verifysignature (pubkey_handle, NULL, &pcr_policy_hash, &signature,
+ &verification_ticket, NULL);
+ if (rc != TPM_RC_SUCCESS)
+ {
+ err = grub_error (GRUB_ERR_BAD_DEVICE, "failed to verify signature (TPM2_VerifySignature: 0x%x)", rc);
+ goto error;
+ }
+
+ /* Authorize the signed policy with the public key and the verification ticket */
+ rc = grub_tpm2_policyauthorize (session, NULL, &pcr_policy, &policy_ref, &pubname,
+ &verification_ticket, NULL);
+ if (rc != TPM_RC_SUCCESS)
+ {
+ err = grub_error (GRUB_ERR_BAD_DEVICE, "failed to authorize PCR policy (TPM2_PolicyAuthorize: 0x%x)", rc);
+ goto error;
+ }
+
+ err = GRUB_ERR_NONE;
+
+ error:
+ grub_tpm2_flushcontext (pubkey_handle);
+
+ return err;
+}
+
static grub_err_t
tpm2_protector_enforce_policy (tpm2key_policy_t policy, TPMI_SH_AUTH_SESSION_t session)
{
@@ -636,6 +703,9 @@ tpm2_protector_enforce_policy (tpm2key_policy_t policy, TPMI_SH_AUTH_SESSION_t s
case TPM_CC_PolicyPCR:
err = tpm2_protector_policypcr (session, &buf);
break;
+ case TPM_CC_PolicyAuthorize:
+ err = tpm2_protector_policyauthorize (session, &buf);
+ break;
default:
return grub_error (GRUB_ERR_BAD_ARGUMENT, "unknown TPM Command: 0x%x", policy->cmd_code);
}
--
2.43.0

View File

@@ -0,0 +1,101 @@
From 99ee68a0149b1132f160c80924ab2987ebafcbdd Mon Sep 17 00:00:00 2001
From: Stefan Berger <stefanb@linux.ibm.com>
Date: Tue, 26 Nov 2024 15:39:40 -0500
Subject: [PATCH 1/7] tss2: Adjust bit fields for big endian targets
The TPM bit fields need to be in reverse order for big endian targets,
such as ieee1275 PowerPC platforms that run GRUB in big endian mode.
Signed-off-by: Stefan Berger <stefanb@linux.ibm.com>
Reviewed-by: Gary Lin <glin@suse.com>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
---
grub-core/lib/tss2/tss2_structs.h | 38 +++++++++++++++++++++++++++++++
1 file changed, 38 insertions(+)
diff --git a/grub-core/lib/tss2/tss2_structs.h b/grub-core/lib/tss2/tss2_structs.h
index ca33db3ec..e5390ab56 100644
--- a/grub-core/lib/tss2/tss2_structs.h
+++ b/grub-core/lib/tss2/tss2_structs.h
@@ -147,6 +147,15 @@ typedef TPM2B_DIGEST_t TPM2B_NONCE_t;
/* TPMA_SESSION Structure */
struct TPMA_SESSION
{
+#ifdef GRUB_TARGET_WORDS_BIGENDIAN
+ grub_uint8_t audit:1;
+ grub_uint8_t encrypt:1;
+ grub_uint8_t decrypt:1;
+ grub_uint8_t reserved:2;
+ grub_uint8_t auditReset:1;
+ grub_uint8_t auditExclusive:1;
+ grub_uint8_t continueSession:1;
+#else
grub_uint8_t continueSession:1;
grub_uint8_t auditExclusive:1;
grub_uint8_t auditReset:1;
@@ -154,6 +163,7 @@ struct TPMA_SESSION
grub_uint8_t decrypt:1;
grub_uint8_t encrypt:1;
grub_uint8_t audit:1;
+#endif
};
typedef struct TPMA_SESSION TPMA_SESSION_t;
@@ -206,6 +216,24 @@ typedef struct TPM2B_SENSITIVE_CREATE TPM2B_SENSITIVE_CREATE_t;
/* TPMA_OBJECT Structure */
struct TPMA_OBJECT
{
+#ifdef GRUB_TARGET_WORDS_BIGENDIAN
+ grub_uint32_t reserved5:13;
+ grub_uint32_t sign:1;
+ grub_uint32_t decrypt:1;
+ grub_uint32_t restricted:1;
+ grub_uint32_t reserved4:4;
+ grub_uint32_t encryptedDuplication:1;
+ grub_uint32_t noDA:1;
+ grub_uint32_t reserved3:2;
+ grub_uint32_t adminWithPolicy:1;
+ grub_uint32_t userWithAuth:1;
+ grub_uint32_t sensitiveDataOrigin:1;
+ grub_uint32_t fixedParent:1;
+ grub_uint32_t reserved2:1;
+ grub_uint32_t stClear:1;
+ grub_uint32_t fixedTPM:1;
+ grub_uint32_t reserved1:1;
+#else
grub_uint32_t reserved1:1;
grub_uint32_t fixedTPM:1;
grub_uint32_t stClear:1;
@@ -222,6 +250,7 @@ struct TPMA_OBJECT
grub_uint32_t decrypt:1;
grub_uint32_t sign:1;
grub_uint32_t reserved5:13;
+#endif
};
typedef struct TPMA_OBJECT TPMA_OBJECT_t;
@@ -516,12 +545,21 @@ typedef struct TPM2B_DATA TPM2B_DATA_t;
/* TPMA_LOCALITY Structure */
struct TPMA_LOCALITY
{
+#ifdef GRUB_TARGET_WORDS_BIGENDIAN
+ grub_uint8_t Extended:3;
+ grub_uint8_t TPM_LOC_FOUR:1;
+ grub_uint8_t TPM_LOC_THREE:1;
+ grub_uint8_t TPM_LOC_TWO:1;
+ grub_uint8_t TPM_LOC_ONE:1;
+ grub_uint8_t TPM_LOC_ZERO:1;
+#else
grub_uint8_t TPM_LOC_ZERO:1;
grub_uint8_t TPM_LOC_ONE:1;
grub_uint8_t TPM_LOC_TWO:1;
grub_uint8_t TPM_LOC_THREE:1;
grub_uint8_t TPM_LOC_FOUR:1;
grub_uint8_t Extended:3;
+#endif
};
typedef struct TPMA_LOCALITY TPMA_LOCALITY_t;
--
2.43.0

View File

@@ -0,0 +1,188 @@
From 200dc727d1fdf3bac7aa725569b60a54b3841867 Mon Sep 17 00:00:00 2001
From: Gary Lin <glin@suse.com>
Date: Fri, 22 Mar 2024 16:23:38 +0800
Subject: [PATCH] util/bash-completion: Fix for bash-completion 2.12
_split_longopt() was the bash-completion private API and removed since
bash-completion 2.12. This commit initializes the bash-completion
general variables with _init_completion() to avoid the potential
'command not found' error.
Although bash-completion 2.12 introduces _comp_initialize() to deprecate
_init_completion(), _init_completion() is still chosen for the better
backward compatibility.
Signed-off-by: Gary Lin <glin@suse.com>
---
.../bash-completion.d/grub-completion.bash.in | 61 +++++++------------
1 file changed, 22 insertions(+), 39 deletions(-)
diff --git a/util/bash-completion.d/grub-completion.bash.in b/util/bash-completion.d/grub-completion.bash.in
index 4c88ee901..749a5d3cf 100644
--- a/util/bash-completion.d/grub-completion.bash.in
+++ b/util/bash-completion.d/grub-completion.bash.in
@@ -151,13 +151,10 @@ __grub_list_modules () {
# grub-set-default & grub-reboot
#
__grub_set_entry () {
- local cur prev split=false
+ local cur prev words cword split
+ _init_completion -s || return
COMPREPLY=()
- cur=`_get_cword`
- prev=${COMP_WORDS[COMP_CWORD-1]}
-
- _split_longopt && split=true
case "$prev" in
--boot-directory)
@@ -180,11 +177,10 @@ __grub_set_entry () {
# grub-editenv
#
__grub_editenv () {
- local cur prev
+ local cur prev words cword
+ _init_completion || return
COMPREPLY=()
- cur=`_get_cword`
- prev=${COMP_WORDS[COMP_CWORD-1]}
case "$prev" in
create|list|set|unset)
@@ -201,10 +197,10 @@ __grub_editenv () {
# grub-mkconfig
#
__grub_mkconfig () {
- local cur prev
+ local cur prev words cword
+ _init_completion || return
COMPREPLY=()
- cur=`_get_cword`
if [[ "$cur" == -* ]]; then
__grubcomp "$(__grub_get_options_from_help)"
@@ -217,13 +213,10 @@ __grub_mkconfig () {
# grub-setup
#
__grub_setup () {
- local cur prev split=false
+ local cur prev words cword split
+ _init_completion -s || return
COMPREPLY=()
- cur=`_get_cword`
- prev=${COMP_WORDS[COMP_CWORD-1]}
-
- _split_longopt && split=true
case "$prev" in
-d|--directory)
@@ -246,15 +239,12 @@ __grub_setup () {
# grub-install
#
__grub_install () {
- local cur prev last split=false
+ local cur prev words cword split last
+ _init_completion -s || return
COMPREPLY=()
- cur=`_get_cword`
- prev=${COMP_WORDS[COMP_CWORD-1]}
last=$(__grub_get_last_option)
- _split_longopt && split=true
-
case "$prev" in
--boot-directory)
_filedir -d
@@ -287,10 +277,10 @@ __grub_install () {
# grub-mkfont
#
__grub_mkfont () {
- local cur
+ local cur prev words cword
+ _init_completion || return
COMPREPLY=()
- cur=`_get_cword`
if [[ "$cur" == -* ]]; then
__grubcomp "$(__grub_get_options_from_help)"
@@ -304,11 +294,10 @@ __grub_mkfont () {
# grub-mkrescue
#
__grub_mkrescue () {
- local cur prev last
+ local cur prev words cword last
+ _init_completion || return
COMPREPLY=()
- cur=`_get_cword`
- prev=${COMP_WORDS[COMP_CWORD-1]}
last=$(__grub_get_last_option)
if [[ "$cur" == -* ]]; then
@@ -330,13 +319,10 @@ __grub_mkrescue () {
# grub-mkimage
#
__grub_mkimage () {
- local cur prev split=false
+ local cur prev words cword split
+ _init_completion -s || return
COMPREPLY=()
- cur=`_get_cword`
- prev=${COMP_WORDS[COMP_CWORD-1]}
-
- _split_longopt && split=true
case "$prev" in
-d|--directory|-p|--prefix)
@@ -367,10 +353,10 @@ __grub_mkimage () {
# grub-mkpasswd-pbkdf2
#
__grub_mkpasswd_pbkdf2 () {
- local cur
+ local cur prev words cword
+ _init_completion || return
COMPREPLY=()
- cur=`_get_cword`
if [[ "$cur" == -* ]]; then
__grubcomp "$(__grub_get_options_from_help)"
@@ -384,13 +370,10 @@ __grub_mkpasswd_pbkdf2 () {
# grub-probe
#
__grub_probe () {
- local cur prev split=false
+ local cur prev words cword split
+ _init_completion -s || return
COMPREPLY=()
- cur=`_get_cword`
- prev=${COMP_WORDS[COMP_CWORD-1]}
-
- _split_longopt && split=true
case "$prev" in
-t|--target)
@@ -417,10 +400,10 @@ __grub_probe () {
# grub-script-check
#
__grub_script_check () {
- local cur
+ local cur prev words cword
+ _init_completion || return
COMPREPLY=()
- cur=`_get_cword`
if [[ "$cur" == -* ]]; then
__grubcomp "$(__grub_get_options_from_help)"
--
2.35.3

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,83 @@
From 6c06378c1bf6ae21788427e62ab0011b7f1bc2f0 Mon Sep 17 00:00:00 2001
From: Michael Chang <mchang@suse.com>
Date: Fri, 25 Nov 2022 16:11:24 +0800
Subject: [PATCH] xen_boot: add missing grub_arch_efi_linux_load_image_header
The new xen_boot module has used grub_arch_efi_linux_load_image_header
exported by grub-core/loader/arm64/linux.c. It is not a problem for
upstream but many downstream projects may not use it and take
grub-core/loader/arm64/efi/linux.c as a replacement as PE entry is the
preferred way in combination with shim loader.
This patch did a trivial workaround just adding back the dropped
defintion to the xen_boot itself.
Signed-off-by: Michael Chang <mchang@suse.com>
---
grub-core/loader/arm64/xen_boot.c | 50 +++++++++++++++++++++++++++++++
1 file changed, 50 insertions(+)
diff --git a/grub-core/loader/arm64/xen_boot.c b/grub-core/loader/arm64/xen_boot.c
index 26e1472c9..b82a2db89 100644
--- a/grub-core/loader/arm64/xen_boot.c
+++ b/grub-core/loader/arm64/xen_boot.c
@@ -84,6 +84,56 @@ static int loaded;
static struct xen_boot_binary *xen_hypervisor;
static struct xen_boot_binary *module_head;
+/* The function is exported by grub-core/loader/arm64/linux.c that is not built
+ * because we use PE entry provided by grub-core/loader/arm64/efi/linux.c
+ */
+static bool initrd_use_loadfile2 = false;
+
+grub_err_t
+grub_arch_efi_linux_load_image_header (grub_file_t file,
+ struct linux_arch_kernel_header * lh)
+{
+ grub_file_seek (file, 0);
+ if (grub_file_read (file, lh, sizeof (*lh)) < (grub_ssize_t) sizeof (*lh))
+ return grub_error(GRUB_ERR_FILE_READ_ERROR, "failed to read Linux image header");
+
+ if ((lh->code0 & 0xffff) != GRUB_PE32_MAGIC)
+ return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET,
+ N_("plain image kernel not supported - rebuild with CONFIG_(U)EFI_STUB enabled"));
+
+ grub_dprintf ("linux", "UEFI stub kernel:\n");
+ grub_dprintf ("linux", "PE/COFF header @ %08x\n", lh->hdr_offset);
+
+ /*
+ * The PE/COFF spec permits the COFF header to appear anywhere in the file, so
+ * we need to double check whether it was where we expected it, and if not, we
+ * must load it from the correct offset into the pe_image_header field of
+ * struct linux_arch_kernel_header.
+ */
+ if ((grub_uint8_t *) lh + lh->hdr_offset != (grub_uint8_t *) &lh->pe_image_header)
+ {
+ if (grub_file_seek (file, lh->hdr_offset) == (grub_off_t) -1
+ || grub_file_read (file, &lh->pe_image_header,
+ sizeof (struct grub_pe_image_header))
+ != sizeof (struct grub_pe_image_header))
+ return grub_error (GRUB_ERR_FILE_READ_ERROR, "failed to read COFF image header");
+ }
+
+ /*
+ * Linux kernels built for any architecture are guaranteed to support the
+ * LoadFile2 based initrd loading protocol if the image version is >= 1.
+ */
+ if (lh->pe_image_header.optional_header.major_image_version >= 1)
+ initrd_use_loadfile2 = true;
+ else
+ initrd_use_loadfile2 = false;
+
+ grub_dprintf ("linux", "LoadFile2 initrd loading %sabled\n",
+ initrd_use_loadfile2 ? "en" : "dis");
+
+ return GRUB_ERR_NONE;
+}
+
static __inline grub_addr_t
xen_boot_address_align (grub_addr_t start, grub_size_t align)
{
--
2.41.0

View File

@@ -0,0 +1,57 @@
From f01314a822dbe9ad39b2f7d0f3717ef6e4c24f4a Mon Sep 17 00:00:00 2001
From: Michael Chang <mchang@suse.com>
Date: Fri, 15 Apr 2022 21:45:04 +0800
Subject: [PATCH 2/2] Mark environmet blocks as used for image embedding.
Now that grub will attempt to use full btrfs bootloader area, the
embedded image could have overlapped with environment blocks if it's
size grows too much. Let's define a dedicated area for environment
blocks to the used block mappings for the embedding process so it can be
skipped.
Signed-off-by: Michael Chang <mchang@suse.com>
---
grub-core/fs/btrfs.c | 3 ++-
include/grub/fs.h | 2 ++
util/grub-editenv.c | 2 +-
3 files changed, 5 insertions(+), 2 deletions(-)
--- a/grub-core/fs/btrfs.c
+++ b/grub-core/fs/btrfs.c
@@ -2637,7 +2637,7 @@
static const struct {
struct embed_region available;
- struct embed_region used[6];
+ struct embed_region used[7];
} btrfs_head = {
.available = {0, GRUB_DISK_KiB_TO_SECTORS (1024)}, /* The first 1 MiB. */
.used = {
@@ -2645,6 +2645,7 @@
{GRUB_DISK_KiB_TO_SECTORS (64) - 1, 1}, /* Overflow guard. */
{GRUB_DISK_KiB_TO_SECTORS (64), GRUB_DISK_KiB_TO_SECTORS (4)}, /* 4 KiB superblock. */
{GRUB_DISK_KiB_TO_SECTORS (68), 1}, /* Overflow guard. */
+ {GRUB_DISK_KiB_TO_SECTORS (ENV_BTRFS_OFFSET) - 1, 3}, /* Environment Block. */
{GRUB_DISK_KiB_TO_SECTORS (1024) - 1, 1}, /* Overflow guard. */
{0, 0} /* Array terminator. */
}
--- a/include/grub/fs.h
+++ b/include/grub/fs.h
@@ -128,4 +128,6 @@
grub_fs_t EXPORT_FUNC(grub_fs_probe) (grub_device_t device);
+#define ENV_BTRFS_OFFSET (256)
+
#endif /* ! GRUB_FS_HEADER */
--- a/util/grub-editenv.c
+++ b/util/grub-editenv.c
@@ -128,7 +128,7 @@
int offset;
int size;
} fs_envblk_spec[] = {
- { "btrfs", 256 * 1024, GRUB_DISK_SECTOR_SIZE },
+ { "btrfs", ENV_BTRFS_OFFSET * 1024, GRUB_DISK_SECTOR_SIZE },
{ NULL, 0, 0 }
};

View File

@@ -0,0 +1,278 @@
From 0ed98269c5631c4d094b2cee81ce385687803730 Mon Sep 17 00:00:00 2001
From: Michael Chang <mchang@suse.com>
Date: Thu, 29 Aug 2024 13:27:30 +0800
Subject: [PATCH 2/2] Requiring authentication after tpm unlock for CLI access
The GRUB may use TPM to verify the integrity of boot components and the
result can determine whether a previously sealed key can be released. If
everything checks out, showing nothing has been tampered with, the key
is released and GRUB unlocks the encrypted root partition for the next
stage of booting.
However, the liberal Command Line Interface (CLI) can be misused by
anyone in this case to access files in the encrypted partition one way
or another. Despite efforts to keep the CLI secure by preventing utility
command output from leaking file content, many techniques in the wild
could still be used to exploit the CLI, enabling attacks or learning
methods to attack. It's nearly impossible to account for all scenarios
where a hack could be applied.
Therefore, to mitigate potential misuse of the CLI after the root device
has been successfully unlocked via TPM, the user should be required to
authenticate using the LUKS password. This added layer of security
ensures that only authorized users can access the CLI reducing the risk
of exploitation or unauthorized access to the encrypted partition.
Fixes: CVE-2024-49504
Signed-off-by: Michael Chang <mchang@suse.com>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
---
grub-core/disk/cryptodisk.c | 84 +++++++++++++++++++++++++++++++++++
grub-core/kern/main.c | 12 +++++
grub-core/normal/auth.c | 30 +++++++++++++
grub-core/normal/main.c | 4 ++
grub-core/normal/menu_entry.c | 4 ++
include/grub/auth.h | 1 +
include/grub/cryptodisk.h | 3 ++
include/grub/misc.h | 2 +
8 files changed, 140 insertions(+)
--- a/grub-core/disk/cryptodisk.c
+++ b/grub-core/disk/cryptodisk.c
@@ -1183,6 +1183,9 @@
ret = grub_cryptodisk_insert (dev, name, source);
if (ret != GRUB_ERR_NONE)
goto error;
+#ifndef GRUB_UTIL
+ grub_cli_set_auth_needed ();
+#endif
goto cleanup;
}
}
@@ -1700,6 +1703,89 @@
return ret;
}
+#ifdef GRUB_MACHINE_EFI
+grub_err_t
+grub_cryptodisk_challenge_password (void)
+{
+ grub_cryptodisk_t cr_dev;
+
+ for (cr_dev = cryptodisk_list; cr_dev != NULL; cr_dev = cr_dev->next)
+ {
+ grub_cryptodisk_dev_t cr;
+ grub_disk_t source = NULL;
+ grub_err_t ret = GRUB_ERR_NONE;
+ grub_cryptodisk_t dev = NULL;
+ char *part = NULL;
+ struct grub_cryptomount_args cargs = {0};
+
+ cargs.check_boot = 0;
+ cargs.search_uuid = cr_dev->uuid;
+
+ source = grub_disk_open (cr_dev->source);
+
+ if (source == NULL)
+ {
+ ret = grub_errno;
+ goto error_out;
+ }
+
+ FOR_CRYPTODISK_DEVS (cr)
+ {
+ dev = cr->scan (source, &cargs);
+ if (grub_errno)
+ {
+ ret = grub_errno;
+ goto error_out;
+ }
+ if (dev == NULL)
+ continue;
+ break;
+ }
+
+ if (dev == NULL)
+ {
+ ret = grub_error (GRUB_ERR_BAD_MODULE, "no cryptodisk module can handle this device");
+ goto error_out;
+ }
+
+ part = grub_partition_get_name (source->partition);
+ grub_printf_ (N_("Enter passphrase for %s%s%s (%s): "), source->name,
+ source->partition != NULL ? "," : "",
+ part != NULL ? part : N_("UNKNOWN"), cr_dev->uuid);
+ grub_free (part);
+
+ cargs.key_data = grub_malloc (GRUB_CRYPTODISK_MAX_PASSPHRASE);
+ if (cargs.key_data == NULL)
+ {
+ ret = grub_errno;
+ goto error_out;
+ }
+
+ if (!grub_password_get ((char *) cargs.key_data, GRUB_CRYPTODISK_MAX_PASSPHRASE))
+ {
+ ret = grub_error (GRUB_ERR_BAD_ARGUMENT, "passphrase not supplied");
+ goto error_out;
+ }
+ cargs.key_len = grub_strlen ((char *) cargs.key_data);
+ ret = cr->recover_key (source, dev, &cargs);
+
+ error_out:
+ grub_disk_close (source);
+ if (dev != NULL)
+ cryptodisk_close (dev);
+ if (cargs.key_data)
+ {
+ grub_memset (cargs.key_data, 0, cargs.key_len);
+ grub_free (cargs.key_data);
+ }
+
+ return ret;
+ }
+
+ return GRUB_ERR_NONE;
+}
+#endif /* GRUB_MACHINE_EFI */
+
struct grub_procfs_entry luks_script =
{
.name = "luks_script",
--- a/grub-core/kern/main.c
+++ b/grub-core/kern/main.c
@@ -37,6 +37,7 @@
#endif
static bool cli_disabled = false;
+static bool cli_need_auth = false;
grub_addr_t
grub_modules_get_end (void)
@@ -246,6 +247,17 @@
return cli_disabled;
}
+bool
+grub_is_cli_need_auth (void)
+{
+ return cli_need_auth;
+}
+
+void grub_cli_set_auth_needed (void)
+{
+ cli_need_auth = true;
+}
+
static void
check_is_cli_disabled (void)
{
--- a/grub-core/normal/auth.c
+++ b/grub-core/normal/auth.c
@@ -25,6 +25,10 @@
#include <grub/time.h>
#include <grub/i18n.h>
+#ifdef GRUB_MACHINE_EFI
+#include <grub/cryptodisk.h>
+#endif
+
struct grub_auth_user
{
struct grub_auth_user *next;
@@ -201,6 +205,32 @@
}
grub_err_t
+grub_auth_check_cli_access (void)
+{
+ if (grub_is_cli_need_auth () == true)
+ {
+#ifdef GRUB_MACHINE_EFI
+ static bool authenticated = false;
+
+ if (authenticated == false)
+ {
+ grub_err_t ret;
+
+ ret = grub_cryptodisk_challenge_password ();
+ if (ret == GRUB_ERR_NONE)
+ authenticated = true;
+ return ret;
+ }
+ return GRUB_ERR_NONE;
+#else
+ return GRUB_ACCESS_DENIED;
+#endif
+ }
+
+ return GRUB_ERR_NONE;
+}
+
+grub_err_t
grub_auth_check_authentication (const char *userlist)
{
char login[1024];
--- a/grub-core/normal/main.c
+++ b/grub-core/normal/main.c
@@ -560,9 +560,13 @@
}
while (err && force_auth);
+ if (err == GRUB_ERR_NONE)
+ err = grub_auth_check_cli_access ();
+
if (err)
{
grub_print_error ();
+ grub_wait_after_message ();
grub_errno = GRUB_ERR_NONE;
return;
}
--- a/grub-core/normal/menu_entry.c
+++ b/grub-core/normal/menu_entry.c
@@ -1256,9 +1256,13 @@
err = grub_auth_check_authentication (NULL);
+ if (err == GRUB_ERR_NONE)
+ err = grub_auth_check_cli_access ();
+
if (err)
{
grub_print_error ();
+ grub_wait_after_message ();
grub_errno = GRUB_ERR_NONE;
return;
}
--- a/include/grub/auth.h
+++ b/include/grub/auth.h
@@ -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 */
--- a/include/grub/cryptodisk.h
+++ b/include/grub/cryptodisk.h
@@ -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);
+#ifdef GRUB_MACHINE_EFI
+grub_err_t grub_cryptodisk_challenge_password (void);
+#endif
#endif
--- a/include/grub/misc.h
+++ b/include/grub/misc.h
@@ -392,6 +392,8 @@
grub_uint64_t *r);
extern bool EXPORT_FUNC(grub_is_cli_disabled) (void);
+extern bool EXPORT_FUNC(grub_is_cli_need_auth) (void);
+extern void EXPORT_FUNC(grub_cli_set_auth_needed) (void);
/* Must match softdiv group in gentpl.py. */
#if !defined(GRUB_MACHINE_EMU) && (defined(__arm__) || defined(__ia64__) || \

View File

@@ -1,69 +0,0 @@
From a2d103ac650e5ea10ac6d40f3a5c1a136ee96613 Mon Sep 17 00:00:00 2001
From: Michael Chang <mchang@suse.com>
Date: Mon, 19 Jan 2026 14:29:05 +0800
Subject: [PATCH 2/2] Revert "configure: Check linker for --image-base support"
This reverts commit 1a5417f39a0ccefcdd5440f2a67f84d2d2e26960.
---
acinclude.m4 | 5 -----
configure.ac | 14 ++------------
2 files changed, 2 insertions(+), 17 deletions(-)
diff --git a/acinclude.m4 b/acinclude.m4
index 70c1912f8..fa7840f09 100644
--- a/acinclude.m4
+++ b/acinclude.m4
@@ -79,11 +79,6 @@ AC_DEFUN([grub_PROG_OBJCOPY_ABSOLUTE],
[AC_MSG_CHECKING([whether ${TARGET_OBJCOPY} works for absolute addresses])
AC_CACHE_VAL(grub_cv_prog_objcopy_absolute,
[cat > conftest.c <<\EOF
-asm (
- ".globl start, _start, __start\n"
- ".ifdef cmain; .set start = _start = __start = cmain\n.endif\n"
- ".ifdef _cmain; .set start = _start = __start = _cmain\n.endif\n"
-);
void cmain (void);
void
cmain (void)
diff --git a/configure.ac b/configure.ac
index b4d4db944..450524d47 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1461,6 +1461,7 @@ elif test x$grub_cv_target_cc_link_format = x-mi386pe || test x$grub_cv_target_c
TARGET_IMG_LDSCRIPT='$(top_srcdir)'"/conf/i386-cygwin-img-ld.sc"
TARGET_IMG_LDFLAGS="-Wl,-T${TARGET_IMG_LDSCRIPT}"
TARGET_IMG_LDFLAGS_AC="-Wl,-T${srcdir}/conf/i386-cygwin-img-ld.sc"
+ TARGET_IMG_BASE_LDOPT="-Wl,-Ttext"
TARGET_IMG_CFLAGS=
else
TARGET_APPLE_LINKER=0
@@ -1468,6 +1469,7 @@ else
TARGET_IMG_LDSCRIPT=
TARGET_IMG_LDFLAGS='-Wl,-N'
TARGET_IMG_LDFLAGS_AC='-Wl,-N'
+ TARGET_IMG_BASE_LDOPT="-Wl,-Ttext"
TARGET_IMG_CFLAGS=
fi
@@ -1793,18 +1795,6 @@ LIBS=""
grub_ASM_USCORE
grub_PROG_TARGET_CC
if test "x$TARGET_APPLE_LINKER" != x1 ; then
-AX_CHECK_LINK_FLAG([-Wl,--image-base,0x400000],
- [TARGET_IMG_BASE_LDOPT="-Wl,--image-base"],
- [TARGET_IMG_BASE_LDOPT="-Wl,-Ttext"],
- [],
- [AC_LANG_SOURCE([
-asm (".globl start; start:");
-asm (".globl _start; _start:");
-asm (".globl __start; __start:");
-void __main (void);
-void __main (void) {}
-int main (void);
- ])])
grub_PROG_OBJCOPY_ABSOLUTE
fi
grub_PROG_LD_BUILD_ID_NONE
--
2.52.0

View File

@@ -16,7 +16,7 @@ Signed-off-by: Michael Chang <mchang@suse.com>
--- a/grub-core/Makefile.core.def
+++ b/grub-core/Makefile.core.def
@@ -1920,7 +1920,6 @@
@@ -1860,7 +1860,6 @@
x86_64_efi = loader/efi/linux.c;
emu = loader/emu/linux.c;
common = loader/linux.c;
@@ -24,9 +24,9 @@ Signed-off-by: Michael Chang <mchang@suse.com>
};
module = {
@@ -2787,3 +2786,8 @@
cflags = '-Wno-uninitialized';
cppflags = '-I$(srcdir)/lib/libtasn1-grub -I$(srcdir)/tests/asn1/';
@@ -2611,3 +2610,8 @@
efi = commands/bli.c;
enable = efi;
};
+
+module = {

View File

@@ -0,0 +1,134 @@
From 9ad07efefe389568c2cedc77a4a6b48cb830dc0a Mon Sep 17 00:00:00 2001
From: Maxim Suhanov <dfirblog@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 <dfirblog@gmail.com>
Reviewed-by: Daniel Kiper <daniel.kiper@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

View File

@@ -0,0 +1,43 @@
From e62b26f9765e309691e014f322d4b02b220956a1 Mon Sep 17 00:00:00 2001
From: Patrick Colp <patrick.colp@oracle.com>
Date: Sun, 30 Jul 2023 12:58:18 -0700
Subject: [PATCH 2/4] cryptodisk: Fallback to passphrase
If a protector is specified, but it fails to unlock the disk, fall back
to asking for the passphrase. However, an error was set indicating that
the protector(s) failed. Later code (e.g., LUKS code) fails as
`grub_errno` is now set. Print the existing errors out first, before
proceeding with the passphrase.
Signed-off-by: Patrick Colp <patrick.colp@oracle.com>
Signed-off-by: Gary Lin <glin@suse.com>
Reviewed-by: Stefan Berger <stefanb@linux.ibm.com>
---
grub-core/disk/cryptodisk.c | 7 ++++++-
1 file changed, 6 insertions(+), 1 deletion(-)
diff --git a/grub-core/disk/cryptodisk.c b/grub-core/disk/cryptodisk.c
index af4104178..f9842f776 100644
--- a/grub-core/disk/cryptodisk.c
+++ b/grub-core/disk/cryptodisk.c
@@ -1193,11 +1193,16 @@ grub_cryptodisk_scan_device_real (const char *name,
source->name, source->partition != NULL ? "," : "",
part != NULL ? part : N_("UNKNOWN"), dev->uuid);
grub_free (part);
- goto error;
}
if (!cargs->key_len)
{
+ if (grub_errno)
+ {
+ grub_print_error ();
+ grub_errno = GRUB_ERR_NONE;
+ }
+
/* Get the passphrase from the user, if no key data. */
askpass = 1;
part = grub_partition_get_name (source->partition);
--
2.35.3

View File

@@ -0,0 +1,34 @@
From daec67a7ea73b859e1e0b6a4e9122157c7525676 Mon Sep 17 00:00:00 2001
From: B Horn <b@horn.uk>
Date: Sun, 12 May 2024 02:03:33 +0100
Subject: [PATCH 02/20] fs/ufs: Fix a heap OOB write
grub_strcpy() was used to copy a symlink name from the filesystem
image to a heap allocated buffer. This led to a OOB write to adjacent
heap allocations. Fix by using grub_strlcpy().
Fixes: CVE-2024-45781
Reported-by: B Horn <b@horn.uk>
Signed-off-by: B Horn <b@horn.uk>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
---
grub-core/fs/ufs.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/grub-core/fs/ufs.c b/grub-core/fs/ufs.c
index a354c92d93..01235101b4 100644
--- a/grub-core/fs/ufs.c
+++ b/grub-core/fs/ufs.c
@@ -463,7 +463,7 @@ grub_ufs_lookup_symlink (struct grub_ufs_data *data, int ino)
/* Check against zero is paylindromic, no need to swap. */
if (data->inode.nblocks == 0
&& INODE_SIZE (data) <= sizeof (data->inode.symlink))
- grub_strcpy (symlink, (char *) data->inode.symlink);
+ grub_strlcpy (symlink, (char *) data->inode.symlink, sz);
else
{
if (grub_ufs_read_file (data, 0, 0, 0, sz, symlink) < 0)
--
2.48.1

View File

@@ -0,0 +1,52 @@
From 3a69e9126d532214d940c1386f2933a124611a6c Mon Sep 17 00:00:00 2001
From: Egor Ignatov <egori@altlinux.org>
Date: Thu, 23 Jan 2025 20:44:14 +0300
Subject: [PATCH 2/3] fs/xfs: Fix grub_xfs_iterate_dir() return value in case
of failure
Commit ef7850c757 (fs/xfs: Fix issues found while fuzzing the XFS
filesystem) introduced multiple boundary checks in grub_xfs_iterate_dir()
but handled the error incorrectly returning error code instead of 0.
Fix it. Also change the error message so that it doesn't match the
message in grub_xfs_read_inode().
Fixes: ef7850c757 (fs/xfs: Fix issues found while fuzzing the XFS filesystem)
Signed-off-by: Egor Ignatov <egori@altlinux.org>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
---
grub-core/fs/xfs.c | 11 +++++++++--
1 file changed, 9 insertions(+), 2 deletions(-)
diff --git a/grub-core/fs/xfs.c b/grub-core/fs/xfs.c
index e3a69fe498..30e3e7f6d9 100644
--- a/grub-core/fs/xfs.c
+++ b/grub-core/fs/xfs.c
@@ -859,7 +859,11 @@ grub_xfs_iterate_dir (grub_fshelp_node_t dir,
grub_uint8_t c;
if ((inopos + (smallino ? 4 : 8)) > (grub_uint8_t *) dir + grub_xfs_fshelp_size (dir->data))
- return grub_error (GRUB_ERR_BAD_FS, "not a correct XFS inode");
+ {
+ grub_error (GRUB_ERR_BAD_FS, "invalid XFS inode");
+ return 0;
+ }
+
/* inopos might be unaligned. */
if (smallino)
@@ -968,7 +972,10 @@ grub_xfs_iterate_dir (grub_fshelp_node_t dir,
filename = (char *)(direntry + 1);
if (filename + direntry->len + 1 > (char *) end)
- return grub_error (GRUB_ERR_BAD_FS, "invalid XFS directory entry");
+ {
+ grub_error (GRUB_ERR_BAD_FS, "invalid XFS directory entry");
+ return 0;
+ }
/* The byte after the filename is for the filetype, padding, or
tag, which is not used by GRUB. So it can be overwritten. */
--
2.48.1

View File

@@ -0,0 +1,216 @@
From ec0951f742d03f585454f0a50f588fc7ea42a257 Mon Sep 17 00:00:00 2001
From: Sudhakar Kuppusamy <sudhakar@linux.ibm.com>
Date: Mon, 24 Feb 2025 18:40:11 +0530
Subject: [PATCH 2/9] ieee1275: Platform Keystore (PKS) Support
enhancing the infrastructure to enable the Platform Keystore (PKS) feature,
which provides access to the SB VERSION, DB, and DBX secure boot variables
from PKS.
Signed-off-by: Sudhakar Kuppusamy <sudhakar@linux.ibm.com>
Reviewed-by: Stefan Berger <stefanb@linux.ibm.com>
Reviewed-by: Avnish Chouhan <avnish@linux.ibm.com>
---
grub-core/Makefile.am | 1 +
grub-core/Makefile.core.def | 1 +
grub-core/kern/powerpc/ieee1275/ieee1275.c | 140 +++++++++++++++++++++
include/grub/powerpc/ieee1275/ieee1275.h | 14 +++
4 files changed, 156 insertions(+)
create mode 100644 grub-core/kern/powerpc/ieee1275/ieee1275.c
diff --git a/grub-core/Makefile.am b/grub-core/Makefile.am
index 9d3d5f5193..40ed353aba 100644
--- a/grub-core/Makefile.am
+++ b/grub-core/Makefile.am
@@ -241,6 +241,7 @@ KERNEL_HEADER_FILES += $(top_builddir)/include/grub/machine/kernel.h
endif
if COND_powerpc_ieee1275
+KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/powerpc/ieee1275/ieee1275.h
KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/ieee1275/ieee1275.h
KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/ieee1275/alloc.h
KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/terminfo.h
diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def
index e1698a6923..1dfcf5f991 100644
--- a/grub-core/Makefile.core.def
+++ b/grub-core/Makefile.core.def
@@ -328,6 +328,7 @@ kernel = {
extra_dist = video/sis315_init.c;
mips_loongson = commands/keylayouts.c;
+ powerpc_ieee1275 = kern/powerpc/ieee1275/ieee1275.c;
powerpc_ieee1275 = kern/powerpc/cache.S;
powerpc_ieee1275 = kern/powerpc/dl.c;
powerpc_ieee1275 = kern/powerpc/compiler-rt.S;
diff --git a/grub-core/kern/powerpc/ieee1275/ieee1275.c b/grub-core/kern/powerpc/ieee1275/ieee1275.c
new file mode 100644
index 0000000000..f685afcfff
--- /dev/null
+++ b/grub-core/kern/powerpc/ieee1275/ieee1275.c
@@ -0,0 +1,140 @@
+/* of.c - Access the Open Firmware client interface. */
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2003,2004,2005,2007,2008,2009 Free Software Foundation, Inc.
+ *
+ * GRUB is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GRUB is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GRUB. If not, see <http://www.gnu.org/licenses/>.
+ */
+#include <grub/ieee1275/ieee1275.h>
+#include <grub/powerpc/ieee1275/ieee1275.h>
+#include <grub/misc.h>
+
+#define IEEE1275_CELL_INVALID ((grub_ieee1275_cell_t) - 1)
+
+int
+grub_ieee1275_test (const char *name, grub_ieee1275_cell_t *missing)
+{
+ struct test_args
+ {
+ struct grub_ieee1275_common_hdr common;
+ grub_ieee1275_cell_t name;
+ grub_ieee1275_cell_t missing;
+ } args;
+
+ INIT_IEEE1275_COMMON (&args.common, "test", 1, 1);
+ args.name = (grub_ieee1275_cell_t) name;
+
+ if (IEEE1275_CALL_ENTRY_FN (&args) == -1)
+ return -1;
+
+ if (args.missing == IEEE1275_CELL_INVALID)
+ return -1;
+
+ *missing = args.missing;
+
+ return 0;
+}
+
+int
+grub_ieee1275_pks_max_object_size (grub_size_t *result)
+{
+ struct mos_args
+ {
+ struct grub_ieee1275_common_hdr common;
+ grub_ieee1275_cell_t size;
+ } args;
+
+ INIT_IEEE1275_COMMON (&args.common, "pks-max-object-size", 0, 1);
+
+ if (IEEE1275_CALL_ENTRY_FN (&args) == -1)
+ return -1;
+
+ if (args.size == IEEE1275_CELL_INVALID)
+ return -1;
+
+ *result = args.size;
+
+ return 0;
+}
+
+int
+grub_ieee1275_pks_read_object (grub_uint8_t consumer, grub_uint8_t *label,
+ grub_size_t label_len, grub_uint8_t *buffer,
+ grub_size_t buffer_len, grub_size_t *data_len,
+ grub_uint32_t *policies)
+{
+ struct pks_read_args
+ {
+ struct grub_ieee1275_common_hdr common;
+ grub_ieee1275_cell_t consumer;
+ grub_ieee1275_cell_t label;
+ grub_ieee1275_cell_t label_len;
+ grub_ieee1275_cell_t buffer;
+ grub_ieee1275_cell_t buffer_len;
+ grub_ieee1275_cell_t data_len;
+ grub_ieee1275_cell_t policies;
+ grub_ieee1275_cell_t rc;
+ } args;
+
+ INIT_IEEE1275_COMMON (&args.common, "pks-read-object", 5, 3);
+ args.consumer = (grub_ieee1275_cell_t) consumer;
+ args.label = (grub_ieee1275_cell_t) label;
+ args.label_len = (grub_ieee1275_cell_t) label_len;
+ args.buffer = (grub_ieee1275_cell_t) buffer;
+ args.buffer_len = (grub_ieee1275_cell_t) buffer_len;
+
+ if (IEEE1275_CALL_ENTRY_FN (&args) == -1)
+ return -1;
+
+ if (args.data_len == IEEE1275_CELL_INVALID)
+ return -1;
+
+ *data_len = args.data_len;
+ *policies = args.policies;
+
+ return (int) args.rc;
+}
+
+int
+grub_ieee1275_pks_read_sbvar (grub_uint8_t sbvarflags, grub_uint8_t sbvartype,
+ grub_uint8_t *buffer, grub_size_t buffer_len,
+ grub_size_t *data_len)
+{
+ struct pks_read_sbvar_args
+ {
+ struct grub_ieee1275_common_hdr common;
+ grub_ieee1275_cell_t sbvarflags;
+ grub_ieee1275_cell_t sbvartype;
+ grub_ieee1275_cell_t buffer;
+ grub_ieee1275_cell_t buffer_len;
+ grub_ieee1275_cell_t data_len;
+ grub_ieee1275_cell_t rc;
+ } args;
+
+ INIT_IEEE1275_COMMON (&args.common, "pks-read-sbvar", 4, 2);
+ args.sbvarflags = (grub_ieee1275_cell_t) sbvarflags;
+ args.sbvartype = (grub_ieee1275_cell_t) sbvartype;
+ args.buffer = (grub_ieee1275_cell_t) buffer;
+ args.buffer_len = (grub_ieee1275_cell_t) buffer_len;
+
+ if (IEEE1275_CALL_ENTRY_FN (&args) == -1)
+ return -1;
+
+ if (args.data_len == IEEE1275_CELL_INVALID)
+ return -1;
+
+ *data_len = args.data_len;
+
+ return (int) args.rc;
+}
diff --git a/include/grub/powerpc/ieee1275/ieee1275.h b/include/grub/powerpc/ieee1275/ieee1275.h
index 4eb2070188..0d48331c26 100644
--- a/include/grub/powerpc/ieee1275/ieee1275.h
+++ b/include/grub/powerpc/ieee1275/ieee1275.h
@@ -28,4 +28,18 @@ typedef grub_uint32_t grub_ieee1275_cell_t;
#define PRIxGRUB_IEEE1275_CELL_T PRIxGRUB_UINT32_T
#define PRIuGRUB_IEEE1275_CELL_T PRIuGRUB_UINT32_T
+int EXPORT_FUNC (grub_ieee1275_test) (const char *name,
+ grub_ieee1275_cell_t *missing);
+
+int grub_ieee1275_pks_max_object_size (grub_size_t *result);
+
+int grub_ieee1275_pks_read_object (grub_uint8_t consumer, grub_uint8_t *label,
+ grub_size_t label_len, grub_uint8_t *buffer,
+ grub_size_t buffer_len, grub_size_t *data_len,
+ grub_uint32_t *policies);
+
+int grub_ieee1275_pks_read_sbvar (grub_uint8_t sbvarflags, grub_uint8_t sbvartype,
+ grub_uint8_t *buffer, grub_size_t buffer_len,
+ grub_size_t *data_len);
+
#endif /* ! GRUB_IEEE1275_MACHINE_HEADER */
--
2.48.1

View File

@@ -29,7 +29,7 @@ Fix gcc-12 error: pointer 'device_path' may be used after 'free'
#ifdef __sparc__
typedef enum
@@ -757,13 +758,74 @@
@@ -754,13 +755,74 @@
return new;
}
@@ -90,8 +90,8 @@ Fix gcc-12 error: pointer 'device_path' may be used after 'free'
char *
grub_util_devname_to_ofpath (const char *sys_devname)
{
- char *name_buf, *device, *devnode, *devicenode, *ofpath = NULL;
+ char *name_buf, *device, *devnode, *devicenode, *ofpath = NULL, *realname;
- char *name_buf, *device, *devnode, *devicenode, *ofpath;
+ char *name_buf, *device, *devnode, *devicenode, *ofpath, *realname;
name_buf = xrealpath (sys_devname);
@@ -104,4 +104,4 @@ Fix gcc-12 error: pointer 'device_path' may be used after 'free'
+
device = get_basename (name_buf);
devnode = strip_trailing_digits (name_buf);
if (devnode == NULL)
devicenode = strip_trailing_digits (device);

View File

@@ -0,0 +1,91 @@
From 7126da87f17ff41334b9fa6969ad032ff9940979 Mon Sep 17 00:00:00 2001
From: Gary Lin <glin@suse.com>
Date: Wed, 13 Aug 2025 09:57:04 +0800
Subject: [PATCH 2/2] lib/pbkdf2: Optimize PBKDF2 by reusing HMAC handle
The previous PBKDF2 implementation used grub_crypto_hmac_buffer(), which
allocates and frees an HMAC handle on every call. This approach caused
significant performance overhead, slowing down the boot process
considerably.
This commit refactors the PBKDF2 code to use the new HMAC functions,
allowing the HMAC handle and its buffers to be allocated once and reused
across multiple operations. This change significantly reduces disk
unlocking time.
In a QEMU/OVMF test environment, this patch reduced the time to unlock a
LUKS2(*) partition from approximately 15 seconds to 4 seconds.
(*) PBKDF2 SHA256 with 3454944 iterations
Signed-off-by: Gary Lin <glin@suse.com>
---
grub-core/lib/pbkdf2.c | 21 +++++++++++++--------
1 file changed, 13 insertions(+), 8 deletions(-)
diff --git a/grub-core/lib/pbkdf2.c b/grub-core/lib/pbkdf2.c
index 28aa96c46..410eff580 100644
--- a/grub-core/lib/pbkdf2.c
+++ b/grub-core/lib/pbkdf2.c
@@ -39,6 +39,7 @@ grub_crypto_pbkdf2 (const struct gcry_md_spec *md,
unsigned int c,
grub_uint8_t *DK, grub_size_t dkLen)
{
+ struct grub_crypto_hmac_handle *hnd = NULL;
unsigned int hLen = md->mdlen;
grub_uint8_t U[GRUB_CRYPTO_MAX_MDLEN];
grub_uint8_t T[GRUB_CRYPTO_MAX_MDLEN];
@@ -47,7 +48,6 @@ grub_crypto_pbkdf2 (const struct gcry_md_spec *md,
unsigned int r;
unsigned int i;
unsigned int k;
- gcry_err_code_t rc;
grub_uint8_t *tmp;
grub_size_t tmplen = Slen + 4;
@@ -72,6 +72,13 @@ grub_crypto_pbkdf2 (const struct gcry_md_spec *md,
grub_memcpy (tmp, S, Slen);
+ hnd = grub_crypto_hmac_init (md, P, Plen);
+ if (hnd == NULL)
+ {
+ grub_free (tmp);
+ return GPG_ERR_OUT_OF_MEMORY;
+ }
+
for (i = 1; i - 1 < l; i++)
{
grub_memset (T, 0, hLen);
@@ -85,16 +92,13 @@ grub_crypto_pbkdf2 (const struct gcry_md_spec *md,
tmp[Slen + 2] = (i & 0x0000ff00) >> 8;
tmp[Slen + 3] = (i & 0x000000ff) >> 0;
- rc = grub_crypto_hmac_buffer (md, P, Plen, tmp, tmplen, U);
+ grub_crypto_hmac_write (hnd, tmp, tmplen);
}
else
- rc = grub_crypto_hmac_buffer (md, P, Plen, U, hLen, U);
+ grub_crypto_hmac_write (hnd, U, hLen);
- if (rc != GPG_ERR_NO_ERROR)
- {
- grub_free (tmp);
- return rc;
- }
+ grub_crypto_hmac_final (hnd, U);
+ grub_crypto_hmac_reset (hnd);
for (k = 0; k < hLen; k++)
T[k] ^= U[k];
@@ -103,6 +107,7 @@ grub_crypto_pbkdf2 (const struct gcry_md_spec *md,
grub_memcpy (DK + (i - 1) * hLen, T, i == l ? r : hLen);
}
+ grub_crypto_hmac_free (hnd);
grub_free (tmp);
return GPG_ERR_NO_ERROR;
--
2.51.0

View File

@@ -1,113 +0,0 @@
From 1e5d19972bb64b0fcb39083042a69cf05e0cb783 Mon Sep 17 00:00:00 2001
From: Michael Chang <mchang@suse.com>
Date: Sat, 26 Apr 2025 15:33:28 +0800
Subject: [PATCH 2/4] linux: fallback to direct PE entry boot on arm64
On the arm64 platform, when the shim loader protocol is unavailable and
UEFI Secure Boot is enabled, fall back to booting via the direct PE/COFF
image entry point instead of requesting UEFI to load and start the
image. This fallback allows booting binaries validated by shim's vendor
DB, even if they are not listed in the UEFI DB.
Signed-off-by: Michael Chang <mchang@suse.com>
---
grub-core/Makefile.core.def | 1 +
grub-core/loader/arm64/efi/linux.c | 26 +++++++-------------------
grub-core/loader/efi/linux.c | 6 +++---
3 files changed, 11 insertions(+), 22 deletions(-)
diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def
index 1811661c3..2100d7ff2 100644
--- a/grub-core/Makefile.core.def
+++ b/grub-core/Makefile.core.def
@@ -1898,6 +1898,7 @@ module = {
arm_coreboot = loader/arm/linux.c;
arm_efi = loader/efi/linux.c;
arm_uboot = loader/arm/linux.c;
+ arm64 = loader/efi/linux.c;
arm64 = loader/arm64/efi/linux.c;
loongarch64 = loader/efi/linux.c;
riscv32 = loader/efi/linux.c;
diff --git a/grub-core/loader/arm64/efi/linux.c b/grub-core/loader/arm64/efi/linux.c
index a9f5e05e4..8eab1dc86 100644
--- a/grub-core/loader/arm64/efi/linux.c
+++ b/grub-core/loader/arm64/efi/linux.c
@@ -190,8 +190,8 @@ free_params (void)
}
}
-grub_err_t
-grub_arch_efi_linux_boot_image (grub_addr_t addr,
+static grub_err_t
+grub_arm64_efi_linux_boot_image (grub_addr_t addr,
grub_size_t size __attribute__ ((unused)),
char *args)
{
@@ -213,7 +213,7 @@ grub_arch_efi_linux_boot_image (grub_addr_t addr,
static grub_err_t
grub_linux_boot (void)
{
- return (grub_arch_efi_linux_boot_image ((grub_addr_t)kernel_addr, kernel_size, linux_args));
+ return (grub_arm64_efi_linux_boot_image ((grub_addr_t)kernel_addr, kernel_size, linux_args));
}
static grub_err_t
@@ -464,20 +464,8 @@ fail:
return grub_errno;
}
+extern grub_err_t __attribute__((alias("grub_cmd_linux")))
+grub_cmd_linux_efi_fallback (grub_command_t cmd, int argc, char *argv[]);
-static grub_command_t cmd_linux, cmd_initrd;
-
-GRUB_MOD_INIT (linux)
-{
- cmd_linux = grub_register_command ("linux", grub_cmd_linux, 0,
- N_("Load Linux."));
- cmd_initrd = grub_register_command ("initrd", grub_cmd_initrd, 0,
- N_("Load initrd."));
- my_mod = mod;
-}
-
-GRUB_MOD_FINI (linux)
-{
- grub_unregister_command (cmd_linux);
- grub_unregister_command (cmd_initrd);
-}
+extern grub_err_t __attribute__((alias("grub_cmd_initrd")))
+grub_cmd_initrd_efi_fallback (grub_command_t cmd, int argc, char *argv[]);
diff --git a/grub-core/loader/efi/linux.c b/grub-core/loader/efi/linux.c
index b20dec404..d29e32cba 100644
--- a/grub-core/loader/efi/linux.c
+++ b/grub-core/loader/efi/linux.c
@@ -388,7 +388,7 @@ grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)),
goto fail;
}
-#if defined(__i386__) || defined(__x86_64__)
+#if defined(__i386__) || defined(__x86_64__) || defined(__aarch64__)
if (grub_is_using_legacy_shim_lock_protocol () == true ||
!initrd_use_loadfile2)
return grub_cmd_initrd_efi_fallback (cmd, argc, argv);
@@ -472,7 +472,7 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
if (grub_is_using_legacy_shim_lock_protocol () == true)
{
-#if defined(__i386__) || defined(__x86_64__)
+#if defined(__i386__) || defined(__x86_64__) || defined (__aarch64__)
grub_dprintf ("linux", "using legacy shim_lock protocol, falling back to legacy Linux kernel loader\n");
err = grub_cmd_linux_efi_fallback (cmd, argc, argv);
@@ -499,7 +499,7 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
kernel_size = grub_file_size (file);
if (grub_arch_efi_linux_load_image_header (file, &lh) != GRUB_ERR_NONE)
-#if !defined(__i386__) && !defined(__x86_64__)
+#if !defined(__i386__) && !defined(__x86_64__) && !defined (__aarch64__)
goto fail;
#else
goto fallback;
--
2.50.1

View File

@@ -0,0 +1,35 @@
From c9af7dfdd068beb1f47b1837bcc143118a87fbb1 Mon Sep 17 00:00:00 2001
From: Thomas Frauendorfer | Miray Software <tf@miray.de>
Date: Fri, 9 May 2025 14:20:47 +0200
Subject: [PATCH 2/7] net/net: Unregister net_set_vlan command on unload
The commit 954c48b9c (net/net: Add net_set_vlan command) added command
net_set_vlan to the net module. Unfortunately the commit only added the
grub_register_command() call on module load but missed the
grub_unregister_command() on unload. Let's fix this.
Fixes: CVE-2025-54770
Fixes: 954c48b9c (net/net: Add net_set_vlan command)
Reported-by: Thomas Frauendorfer | Miray Software <tf@miray.de>
Signed-off-by: Thomas Frauendorfer | Miray Software <tf@miray.de>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
---
grub-core/net/net.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/grub-core/net/net.c b/grub-core/net/net.c
index df13c3aaa..7bd8f1bf7 100644
--- a/grub-core/net/net.c
+++ b/grub-core/net/net.c
@@ -2151,6 +2151,7 @@ GRUB_MOD_FINI(net)
grub_unregister_command (cmd_deladdr);
grub_unregister_command (cmd_addroute);
grub_unregister_command (cmd_delroute);
+ grub_unregister_command (cmd_setvlan);
grub_unregister_command (cmd_lsroutes);
grub_unregister_command (cmd_lscards);
grub_unregister_command (cmd_lsaddr);
--
2.51.1

View File

@@ -31,15 +31,15 @@ Signed-off-by: Michael Chang <mchang@suse.com>
--- a/grub-core/disk/ieee1275/ofdisk.c
+++ b/grub-core/disk/ieee1275/ofdisk.c
@@ -26,6 +26,7 @@
@@ -25,6 +25,7 @@
#include <grub/i18n.h>
#include <grub/time.h>
#include <grub/safemath.h>
#include <grub/env.h>
+#include <grub/command.h>
#define RETRY_DEFAULT_TIMEOUT 15
@@ -61,6 +62,9 @@
@@ -60,6 +61,9 @@
#define OFDISK_HASH_SZ 8
static struct ofdisk_hash_ent *ofdisk_hash[OFDISK_HASH_SZ];
@@ -49,7 +49,7 @@ Signed-off-by: Michael Chang <mchang@suse.com>
static int
ofdisk_hash_fn (const char *devpath)
{
@@ -1167,10 +1171,10 @@
@@ -1132,10 +1136,10 @@
return NULL;
}
else
@@ -62,7 +62,7 @@ Signed-off-by: Michael Chang <mchang@suse.com>
grub_free (canon);
return parent;
@@ -1221,9 +1225,9 @@
@@ -1179,9 +1183,9 @@
boot_parent = get_boot_device_parent (bootpath, &is_boot_nvmeof);
boot_type = grub_ieee1275_get_device_type (boot_parent);
if (boot_type)
@@ -74,7 +74,7 @@ Signed-off-by: Michael Chang <mchang@suse.com>
}
grub_free (type);
grub_free (bootpath);
@@ -1247,7 +1251,7 @@
@@ -1205,7 +1209,7 @@
static char *ret;
if (!ret)
@@ -83,7 +83,7 @@ Signed-off-by: Michael Chang <mchang@suse.com>
boot_parent,
boot_type ? : "unknown",
is_boot_nvmeof);
@@ -1263,6 +1267,17 @@
@@ -1221,6 +1225,17 @@
return NULL;
}
@@ -101,7 +101,7 @@ Signed-off-by: Michael Chang <mchang@suse.com>
void
grub_ofdisk_init (void)
{
@@ -1272,6 +1287,9 @@
@@ -1230,6 +1245,9 @@
grub_register_variable_hook ("ofdisk_boot_type", grub_env_get_boot_type,
grub_env_set_boot_type );
@@ -111,7 +111,7 @@ Signed-off-by: Michael Chang <mchang@suse.com>
grub_disk_dev_register (&grub_ofdisk_dev);
}
@@ -1320,3 +1338,50 @@
@@ -1278,3 +1296,50 @@
return 0;
}

View File

@@ -0,0 +1,31 @@
From 29d1bd2a96948bc120cb5906188117f670797fcf Mon Sep 17 00:00:00 2001
From: Stefan Berger <stefanb@linux.ibm.com>
Date: Tue, 26 Nov 2024 15:39:41 -0500
Subject: [PATCH 2/7] term/ieee1275/serial: Cast 0 to proper type
Cast 0 to proper type grub_ieee1275_ihandle_t. This type is
used for struct grub_serial_port's handle that assigns or
compares with IEEE1275_IHANDLE_INVALID.
Signed-off-by: Stefan Berger <stefanb@linux.ibm.com>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
---
grub-core/term/ieee1275/serial.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/grub-core/term/ieee1275/serial.c b/grub-core/term/ieee1275/serial.c
index 0e4cac4c4..9bc44b306 100644
--- a/grub-core/term/ieee1275/serial.c
+++ b/grub-core/term/ieee1275/serial.c
@@ -25,7 +25,7 @@
#include <grub/i18n.h>
#include <grub/ieee1275/console.h>
-#define IEEE1275_IHANDLE_INVALID ((grub_ieee1275_cell_t) 0)
+#define IEEE1275_IHANDLE_INVALID ((grub_ieee1275_ihandle_t) 0)
struct ofserial_hash_ent
{
--
2.43.0

View File

@@ -0,0 +1,84 @@
From 46c9f3a8dac5274c8d117ea131ca5c5842f9276f Mon Sep 17 00:00:00 2001
From: Gary Lin <glin@suse.com>
Date: Mon, 7 Apr 2025 16:29:16 +0800
Subject: [PATCH 2/7] tpm2_key_protector: Add tpm2_dump_pcr command
The user may need to inspect the TPM 2.0 PCR values with the GRUB shell,
so the new tpm2_dump_pcr command is added to print all PCRs of the
specified bank.
Also update the document for the new command.
Signed-off-by: Gary Lin <glin@suse.com>
Tested-by: Stefan Berger <stefanb@linux.ibm.com>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
---
docs/grub.texi | 13 +++++++
.../commands/tpm2_key_protector/module.c | 35 +++++++++++++++++++
2 files changed, 48 insertions(+)
Index: grub-2.12/grub-core/commands/tpm2_key_protector/module.c
===================================================================
--- grub-2.12.orig/grub-core/commands/tpm2_key_protector/module.c
+++ grub-2.12/grub-core/commands/tpm2_key_protector/module.c
@@ -160,6 +160,8 @@ static grub_extcmd_t tpm2_protector_init
static grub_extcmd_t tpm2_protector_clear_cmd;
static tpm2_protector_context_t tpm2_protector_ctx = {0};
+static grub_command_t tpm2_dump_pcr_cmd;
+
static grub_err_t
tpm2_protector_srk_read_file (const char *filepath, void **buffer, grub_size_t *buffer_size)
{
@@ -1327,6 +1329,33 @@ static struct grub_key_protector tpm2_ke
.recover_key = tpm2_protector_recover_key
};
+static grub_err_t
+tpm2_dump_pcr (grub_command_t cmd __attribute__((__unused__)),
+ int argc, char *argv[])
+{
+ TPM_ALG_ID_t pcr_bank;
+
+ if (argc == 0)
+ pcr_bank = TPM_ALG_SHA256;
+ else if (grub_strcmp (argv[0], "sha1") == 0)
+ pcr_bank = TPM_ALG_SHA1;
+ else if (grub_strcmp (argv[0], "sha256") == 0)
+ pcr_bank = TPM_ALG_SHA256;
+ else if (grub_strcmp (argv[0], "sha384") == 0)
+ pcr_bank = TPM_ALG_SHA384;
+ else if (grub_strcmp (argv[0], "sha512") == 0)
+ pcr_bank = TPM_ALG_SHA512;
+ else
+ {
+ grub_printf ("Unknown PCR bank\n");
+ return GRUB_ERR_BAD_ARGUMENT;
+ }
+
+ tpm2_protector_dump_pcr (pcr_bank);
+
+ return GRUB_ERR_NONE;
+}
+
GRUB_MOD_INIT (tpm2_key_protector)
{
tpm2_protector_init_cmd =
@@ -1348,6 +1377,10 @@ GRUB_MOD_INIT (tpm2_key_protector)
N_("Clear the TPM2 key protector if previously initialized."),
NULL);
grub_key_protector_register (&tpm2_key_protector);
+
+ tpm2_dump_pcr_cmd =
+ grub_register_command ("tpm2_dump_pcr", tpm2_dump_pcr, N_("Dump TPM2 PCRs"),
+ N_("Print all PCRs of the specified TPM 2.0 bank"));
}
GRUB_MOD_FINI (tpm2_key_protector)
@@ -1357,4 +1390,6 @@ GRUB_MOD_FINI (tpm2_key_protector)
grub_key_protector_unregister (&tpm2_key_protector);
grub_unregister_extcmd (tpm2_protector_clear_cmd);
grub_unregister_extcmd (tpm2_protector_init_cmd);
+
+ grub_unregister_command (tpm2_dump_pcr_cmd);
}

View File

@@ -210,8 +210,8 @@ Signed-off-by: Peter Jones <pjones@redhat.com>
- params->type_of_loader = 0x21;
+ grub_dprintf ("linux", "setting lh->ext_loader_{type,ver}\n");
+ params->hdr.ext_loader_type = 0;
+ params->hdr.ext_loader_ver = 2;
+ params->ext_loader_type = 0;
+ params->ext_loader_ver = 2;
+ grub_dprintf("linux", "kernel_mem: %p handover_offset: %08x\n",
+ kernel_mem, handover_offset);
@@ -232,7 +232,7 @@ Signed-off-by: Peter Jones <pjones@redhat.com>
grub_efi_free_pages((grub_efi_physical_address_t)(grub_addr_t)kernel_mem, BYTES_TO_PAGES(kernel_size));
--- a/include/grub/i386/linux.h
+++ b/include/grub/i386/linux.h
@@ -402,6 +402,11 @@
@@ -148,6 +148,11 @@
grub_uint32_t kernel_alignment;
grub_uint8_t relocatable;
grub_uint8_t min_alignment;

View File

@@ -0,0 +1,57 @@
From 3526c4e467ee01a3cfd2f4d627433d078a1ab780 Mon Sep 17 00:00:00 2001
From: Peter Jones <pjones@redhat.com>
Date: Mon, 27 Aug 2018 13:14:06 -0400
Subject: [PATCH 3/9] Make grub_error() more verbose
Signed-off-by: Peter Jones <pjones@redhat.com>
---
grub-core/kern/efi/mm.c | 17 ++++++++++++++---
grub-core/kern/err.c | 13 +++++++++++--
include/grub/err.h | 5 ++++-
3 files changed, 29 insertions(+), 6 deletions(-)
--- a/grub-core/kern/err.c
+++ b/grub-core/kern/err.c
@@ -33,15 +33,24 @@
static int grub_error_stack_pos;
static int grub_error_stack_assert;
+#ifdef grub_error
+#undef grub_error
+#endif
+
grub_err_t
-grub_error (grub_err_t n, const char *fmt, ...)
+grub_error (grub_err_t n, const char *file, const int line, const char *fmt, ...)
{
va_list ap;
+ int m;
grub_errno = n;
+ m = grub_snprintf (grub_errmsg, sizeof (grub_errmsg), "%s:%d:", file, line);
+ if (m < 0)
+ m = 0;
+
va_start (ap, fmt);
- grub_vsnprintf (grub_errmsg, sizeof (grub_errmsg), _(fmt), ap);
+ grub_vsnprintf (grub_errmsg + m, sizeof (grub_errmsg) - m, _(fmt), ap);
va_end (ap);
return n;
--- a/include/grub/err.h
+++ b/include/grub/err.h
@@ -86,8 +86,11 @@
extern grub_err_t EXPORT_VAR(grub_errno);
extern char EXPORT_VAR(grub_errmsg)[GRUB_MAX_ERRMSG];
-grub_err_t EXPORT_FUNC(grub_error) (grub_err_t n, const char *fmt, ...)
- __attribute__ ((format (GNU_PRINTF, 2, 3)));
+grub_err_t EXPORT_FUNC(grub_error) (grub_err_t n, const char *file, const int line, const char *fmt, ...)
+ __attribute__ ((format (GNU_PRINTF, 4, 5)));
+
+#define grub_error(n, fmt, ...) grub_error (n, __FILE__, __LINE__, fmt, ##__VA_ARGS__)
+
void EXPORT_FUNC(grub_fatal) (const char *fmt, ...) __attribute__ ((noreturn));
void EXPORT_FUNC(grub_error_push) (void);
int EXPORT_FUNC(grub_error_pop) (void);

View File

@@ -21,10 +21,10 @@ V1:
--- a/grub-core/net/bootp.c
+++ b/grub-core/net/bootp.c
@@ -25,6 +25,98 @@
@@ -24,6 +24,98 @@
#include <grub/net/netbuff.h>
#include <grub/net/udp.h>
#include <grub/datetime.h>
#include <grub/safemath.h>
+#include <grub/time.h>
+#include <grub/list.h>
+
@@ -120,7 +120,7 @@ V1:
struct grub_dhcp_discover_options
{
@@ -611,6 +703,578 @@
@@ -610,6 +702,578 @@
return err;
}
@@ -699,7 +699,7 @@ V1:
/*
* This is called directly from net/ip.c:handle_dgram(), because those
* BOOTP/DHCP packets are a bit special due to their improper
@@ -679,6 +1343,77 @@
@@ -678,6 +1342,77 @@
}
}
@@ -777,7 +777,7 @@ V1:
static grub_err_t
grub_cmd_dhcpopt (struct grub_command *cmd __attribute__ ((unused)),
int argc, char **args)
@@ -918,7 +1653,174 @@
@@ -903,7 +1638,174 @@
return err;
}
@@ -953,7 +953,7 @@ V1:
void
grub_bootp_init (void)
@@ -932,6 +1834,9 @@
@@ -917,6 +1819,9 @@
cmd_getdhcp = grub_register_command ("net_get_dhcp_option", grub_cmd_dhcpopt,
N_("VAR INTERFACE NUMBER DESCRIPTION"),
N_("retrieve DHCP option and save it into VAR. If VAR is - then print the value."));
@@ -963,7 +963,7 @@ V1:
}
void
@@ -940,4 +1845,5 @@
@@ -925,4 +1830,5 @@
grub_unregister_command (cmd_getdhcp);
grub_unregister_command (cmd_bootp);
grub_unregister_command (cmd_dhcp);

View File

@@ -0,0 +1,38 @@
From 370e435b6ada53314888f04dcd8f096fc11cfadb Mon Sep 17 00:00:00 2001
From: Gary Lin <glin@suse.com>
Date: Thu, 3 Aug 2023 15:52:52 +0800
Subject: [PATCH 3/4] cryptodisk: wipe out the cached keys from protectors
An attacker may insert a malicious disk with the same crypto UUID and
trick grub2 to mount the fake root. Even though the key from the key
protector fails to unlock the fake root, it's not wiped out cleanly so
the attacker could dump the memory to retrieve the secret key. To defend
such attack, wipe out the cached key when we don't need it.
Cc: Fabian Vogt <fvogt@suse.com>
Signed-off-by: Gary Lin <glin@suse.com>
Reviewed-by: Stefan Berger <stefanb@linux.ibm.com>
---
grub-core/disk/cryptodisk.c | 6 +++++-
1 file changed, 5 insertions(+), 1 deletion(-)
diff --git a/grub-core/disk/cryptodisk.c b/grub-core/disk/cryptodisk.c
index f9842f776..aa0d43562 100644
--- a/grub-core/disk/cryptodisk.c
+++ b/grub-core/disk/cryptodisk.c
@@ -1355,7 +1355,11 @@ grub_cryptodisk_clear_key_cache (struct grub_cryptomount_args *cargs)
return;
for (i = 0; cargs->protectors[i]; i++)
- grub_free (cargs->key_cache[i].key);
+ {
+ if (cargs->key_cache[i].key)
+ grub_memset (cargs->key_cache[i].key, 0, cargs->key_cache[i].key_len);
+ grub_free (cargs->key_cache[i].key);
+ }
grub_free (cargs->key_cache);
}
--
2.35.3

View File

@@ -0,0 +1,136 @@
From 781d736bd5d0004c705d73b0348b154d8ab838cf Mon Sep 17 00:00:00 2001
From: Maxim Suhanov <dfirblog@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 <dfirblog@gmail.com>
Reviewed-by: Daniel Kiper <daniel.kiper@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

View File

@@ -1,43 +0,0 @@
From 43b0319936f51dc6b4cba3518449195924e83dc8 Mon Sep 17 00:00:00 2001
From: Michael Chang <mchang@suse.com>
Date: Sat, 26 Apr 2025 15:39:43 +0800
Subject: [PATCH 3/4] efi/chainloader: fallback to direct image execution
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
When the shim loader protocol is unavailable and UEFI Secure Boot is
enabled, fall back to chainloading the PE/COFF image by manually
relocating it to the loaded memory address and jumping to its entry
point, rather than invoking UEFI to load and start the image. This
fallback supports booting binaries validated by shims vendor DB, even
if they are not present in the UEFI DB.
Signed-off-by: Michael Chang <mchang@suse.com>
---
grub-core/loader/efi/chainloader.c | 6 +++++-
1 file changed, 5 insertions(+), 1 deletion(-)
diff --git a/grub-core/loader/efi/chainloader.c b/grub-core/loader/efi/chainloader.c
index 1830de223..7e2847217 100644
--- a/grub-core/loader/efi/chainloader.c
+++ b/grub-core/loader/efi/chainloader.c
@@ -805,10 +805,14 @@ grub_cmd_chainloader (grub_command_t cmd __attribute__ ((unused)),
#ifdef SUPPORT_SECURE_BOOT
/* FIXME is secure boot possible also with universal binaries? */
- if (debug_secureboot || (grub_efi_get_secureboot () == GRUB_EFI_SECUREBOOT_MODE_ENABLED && grub_secure_validate ((void *)address, size)))
+ if (debug_secureboot ||
+ (grub_efi_get_secureboot () == GRUB_EFI_SECUREBOOT_MODE_ENABLED &&
+ grub_is_using_legacy_shim_lock_protocol () == true &&
+ grub_secure_validate ((void *)address, size)))
{
struct grub_secureboot_chainloader_context *sb_context;
+ grub_dprintf ("chain", "Falling back to PE loader\n");
sb_context = grub_malloc (sizeof (*sb_context));
if (!sb_context)
goto fail;
--
2.50.1

View File

@@ -0,0 +1,34 @@
From 96f51e8fb8daf43da636f6475827d697829fdb8b Mon Sep 17 00:00:00 2001
From: B Horn <b@horn.uk>
Date: Sun, 12 May 2024 02:48:33 +0100
Subject: [PATCH 03/20] fs/hfs: Fix stack OOB write with grub_strcpy()
Replaced with grub_strlcpy().
Fixes: CVE-2024-45782
Fixes: CVE-2024-56737
Fixes: https://savannah.gnu.org/bugs/?66599
Reported-by: B Horn <b@horn.uk>
Signed-off-by: B Horn <b@horn.uk>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
---
grub-core/fs/hfs.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/grub-core/fs/hfs.c b/grub-core/fs/hfs.c
index 91dc0e69c3..920112b03e 100644
--- a/grub-core/fs/hfs.c
+++ b/grub-core/fs/hfs.c
@@ -379,7 +379,7 @@ grub_hfs_mount (grub_disk_t disk)
volume name. */
key.parent_dir = grub_cpu_to_be32_compile_time (1);
key.strlen = data->sblock.volname[0];
- grub_strcpy ((char *) key.str, (char *) (data->sblock.volname + 1));
+ grub_strlcpy ((char *) key.str, (char *) (data->sblock.volname + 1), sizeof (key.str));
if (grub_hfs_find_node (data, (char *) &key, data->cat_root,
0, (char *) &dir, sizeof (dir)) == 0)
--
2.48.1

View File

@@ -0,0 +1,49 @@
From 846b1d8bebd316a18fae9fb90efb3e8451ec70cc Mon Sep 17 00:00:00 2001
From: Eric Sandeen <sandeen@redhat.com>
Date: Wed, 4 Dec 2024 07:50:28 -0600
Subject: [PATCH 3/3] fs/xfs: fix large extent counters incompat feature
support
When large extent counter / NREXT64 support was added to grub, it missed
a couple of direct reads of nextents which need to be changed to the new
NREXT64-aware helper as well. Without this, we'll have mis-reads of some
directories with this feature enabled.
(The large extent counter fix likely raced on merge with
07318ee7e ("fs/xfs: Fix XFS directory extent parsing") which added the new
direct nextents reads just prior, causing this issue.)
Fixes: aa7c1322671e ("fs/xfs: Add large extent counters incompat feature support")
Signed-off-by: Eric Sandeen <sandeen@redhat.com>
Reviewed-by: Anthony Iliopoulos <ailiop@suse.com>
Reviewed-by: Jon DeVree <nuxi@vault24.org>
Link: https://lore.kernel.org/r/985816b8-35e6-4083-994f-ec9138bd35d2@redhat.com
---
grub-core/fs/xfs.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/grub-core/fs/xfs.c b/grub-core/fs/xfs.c
index 30e3e7f6d9..3ba232436e 100644
--- a/grub-core/fs/xfs.c
+++ b/grub-core/fs/xfs.c
@@ -937,7 +937,7 @@ grub_xfs_iterate_dir (grub_fshelp_node_t dir,
* Leaf and tail information are only in the data block if the number
* of extents is 1.
*/
- if (dir->inode.nextents == grub_cpu_to_be32_compile_time (1))
+ if (grub_xfs_get_inode_nextents(&dir->inode) == 1)
{
end = (char *) tail;
@@ -992,7 +992,7 @@ grub_xfs_iterate_dir (grub_fshelp_node_t dir,
* The expected number of directory entries is only tracked for the
* single extent case.
*/
- if (dir->inode.nextents == grub_cpu_to_be32_compile_time (1))
+ if (grub_xfs_get_inode_nextents(&dir->inode) == 1)
{
/* Check if last direntry in this block is reached. */
entries--;
--
2.48.1

View File

@@ -0,0 +1,66 @@
From 04f3a7beebd029c10e80e9cbea5c1d8452b066ce Mon Sep 17 00:00:00 2001
From: Alec Brown <alec.r.brown@oracle.com>
Date: Thu, 21 Aug 2025 21:14:06 +0000
Subject: [PATCH 3/7] gettext/gettext: Unregister gettext command on module
unload
When the gettext module is loaded, the gettext command is registered but
isn't unregistered when the module is unloaded. We need to add a call to
grub_unregister_command() when unloading the module.
Fixes: CVE-2025-61662
Reported-by: Alec Brown <alec.r.brown@oracle.com>
Signed-off-by: Alec Brown <alec.r.brown@oracle.com>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
---
grub-core/gettext/gettext.c | 19 ++++++++++++-------
1 file changed, 12 insertions(+), 7 deletions(-)
diff --git a/grub-core/gettext/gettext.c b/grub-core/gettext/gettext.c
index 9ffc73428..edebed998 100644
--- a/grub-core/gettext/gettext.c
+++ b/grub-core/gettext/gettext.c
@@ -502,6 +502,8 @@ grub_cmd_translate (grub_command_t cmd __attribute__ ((unused)),
return 0;
}
+static grub_command_t cmd;
+
GRUB_MOD_INIT (gettext)
{
const char *lang;
@@ -521,13 +523,14 @@ GRUB_MOD_INIT (gettext)
grub_register_variable_hook ("locale_dir", NULL, read_main);
grub_register_variable_hook ("secondary_locale_dir", NULL, read_secondary);
- grub_register_command_p1 ("gettext", grub_cmd_translate,
- N_("STRING"),
- /* TRANSLATORS: It refers to passing the string through gettext.
- So it's "translate" in the same meaning as in what you're
- doing now.
- */
- N_("Translates the string with the current settings."));
+ cmd = grub_register_command_p1 ("gettext", grub_cmd_translate,
+ N_("STRING"),
+ /*
+ * TRANSLATORS: It refers to passing the string through gettext.
+ * So it's "translate" in the same meaning as in what you're
+ * doing now.
+ */
+ N_("Translates the string with the current settings."));
/* Reload .mo file information if lang changes. */
grub_register_variable_hook ("lang", NULL, grub_gettext_env_write_lang);
@@ -544,6 +547,8 @@ GRUB_MOD_FINI (gettext)
grub_register_variable_hook ("secondary_locale_dir", NULL, NULL);
grub_register_variable_hook ("lang", NULL, NULL);
+ grub_unregister_command (cmd);
+
grub_gettext_delete_list (&main_context);
grub_gettext_delete_list (&secondary_context);
--
2.51.1

View File

@@ -0,0 +1,95 @@
From 7344b3c7cee8dea94dbc97211c5e6d1925848865 Mon Sep 17 00:00:00 2001
From: Stefan Berger <stefanb@linux.ibm.com>
Date: Tue, 26 Nov 2024 15:39:42 -0500
Subject: [PATCH 3/7] ieee1275: Consolidate repeated definitions of
IEEE1275_IHANDLE_INVALID
Consolidate repeated definitions of IEEE1275_IHANDLE_INVALID that are cast
to the type grub_ieee1275_ihandle_t. On the occasion add "GRUB_" prefix to
the constant name.
Signed-off-by: Stefan Berger <stefanb@linux.ibm.com>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
---
grub-core/commands/ieee1275/ibmvtpm.c | 4 +---
grub-core/term/ieee1275/serial.c | 8 +++-----
include/grub/ieee1275/ieee1275.h | 1 +
3 files changed, 5 insertions(+), 8 deletions(-)
diff --git a/grub-core/commands/ieee1275/ibmvtpm.c b/grub-core/commands/ieee1275/ibmvtpm.c
index a6fee5c51..dd30c7432 100644
--- a/grub-core/commands/ieee1275/ibmvtpm.c
+++ b/grub-core/commands/ieee1275/ibmvtpm.c
@@ -29,8 +29,6 @@
static grub_ieee1275_ihandle_t tpm_ihandle;
static grub_uint8_t tpm_version;
-#define IEEE1275_IHANDLE_INVALID ((grub_ieee1275_ihandle_t) 0)
-
static void
tpm_get_tpm_version (void)
{
@@ -53,7 +51,7 @@ tpm_init (void)
{
if (grub_ieee1275_open ("/vdevice/vtpm", &tpm_ihandle) < 0)
{
- tpm_ihandle = IEEE1275_IHANDLE_INVALID;
+ tpm_ihandle = GRUB_IEEE1275_IHANDLE_INVALID;
return GRUB_ERR_UNKNOWN_DEVICE;
}
diff --git a/grub-core/term/ieee1275/serial.c b/grub-core/term/ieee1275/serial.c
index 9bc44b306..ac2a8f827 100644
--- a/grub-core/term/ieee1275/serial.c
+++ b/grub-core/term/ieee1275/serial.c
@@ -25,8 +25,6 @@
#include <grub/i18n.h>
#include <grub/ieee1275/console.h>
-#define IEEE1275_IHANDLE_INVALID ((grub_ieee1275_ihandle_t) 0)
-
struct ofserial_hash_ent
{
char *devpath;
@@ -44,7 +42,7 @@ do_real_config (struct grub_serial_port *port)
if (grub_ieee1275_open (port->elem->devpath, &port->handle)
|| port->handle == (grub_ieee1275_ihandle_t) -1)
- port->handle = IEEE1275_IHANDLE_INVALID;
+ port->handle = GRUB_IEEE1275_IHANDLE_INVALID;
port->configured = 1;
}
@@ -58,7 +56,7 @@ serial_hw_fetch (struct grub_serial_port *port)
do_real_config (port);
- if (port->handle == IEEE1275_IHANDLE_INVALID)
+ if (port->handle == GRUB_IEEE1275_IHANDLE_INVALID)
return -1;
grub_ieee1275_read (port->handle, &c, 1, &actual);
@@ -76,7 +74,7 @@ serial_hw_put (struct grub_serial_port *port, const int c)
do_real_config (port);
- if (port->handle == IEEE1275_IHANDLE_INVALID)
+ if (port->handle == GRUB_IEEE1275_IHANDLE_INVALID)
return;
grub_ieee1275_write (port->handle, &c0, 1, &actual);
diff --git a/include/grub/ieee1275/ieee1275.h b/include/grub/ieee1275/ieee1275.h
index dddb38514..c445d0499 100644
--- a/include/grub/ieee1275/ieee1275.h
+++ b/include/grub/ieee1275/ieee1275.h
@@ -60,6 +60,7 @@ struct grub_ieee1275_common_hdr
typedef grub_uint32_t grub_ieee1275_ihandle_t;
typedef grub_uint32_t grub_ieee1275_phandle_t;
+#define GRUB_IEEE1275_IHANDLE_INVALID ((grub_ieee1275_ihandle_t) 0)
#define GRUB_IEEE1275_PHANDLE_INVALID ((grub_ieee1275_phandle_t) -1)
struct grub_ieee1275_devalias
--
2.43.0

View File

@@ -0,0 +1,693 @@
From 07b675536e5ae8a0f34d65c40027458d0474d802 Mon Sep 17 00:00:00 2001
From: Sudhakar Kuppusamy <sudhakar@linux.ibm.com>
Date: Mon, 24 Feb 2025 20:01:51 +0530
Subject: [PATCH 3/9] ieee1275: Read the DB and DBX secure boot variables
If secure boot is enabled with PKS, it will read secure boot variables
such as db and dbx from PKS and extract ESL's from it.
The ESL's would be saved in the platform keystore buffer, and
the appendedsig (module) would read it later to extract
the certificate's details from ESL.
In the following scenarios, static key mode will be activated:
1. When Secure Boot is enabled with static keys
2. When SB Version is unavailable but Secure Boot is enabled
3. When PKS support is unavailable but Secure Boot is enabled
Note:-
SB Version - Secure Boot mode
1 - PKS
0 - static key (embeded key)
Signed-off-by: Sudhakar Kuppusamy <sudhakar@linux.ibm.com>
Reviewed-by: Stefan Berger <stefanb@linux.ibm.com>
Reviewed-by: Avnish Chouhan <avnish@linux.ibm.com>
---
grub-core/Makefile.am | 1 +
grub-core/Makefile.core.def | 1 +
grub-core/kern/ieee1275/init.c | 15 +-
.../kern/powerpc/ieee1275/platform_keystore.c | 335 ++++++++++++++++++
.../grub/powerpc/ieee1275/platform_keystore.h | 225 ++++++++++++
include/grub/types.h | 9 +
6 files changed, 584 insertions(+), 2 deletions(-)
create mode 100644 grub-core/kern/powerpc/ieee1275/platform_keystore.c
create mode 100644 include/grub/powerpc/ieee1275/platform_keystore.h
diff --git a/grub-core/Makefile.am b/grub-core/Makefile.am
index 40ed353aba..999e62788f 100644
--- a/grub-core/Makefile.am
+++ b/grub-core/Makefile.am
@@ -247,6 +247,7 @@ KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/ieee1275/alloc.h
KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/terminfo.h
KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/extcmd.h
KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/lib/arg.h
+KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/powerpc/ieee1275/platform_keystore.h
endif
if COND_sparc64_ieee1275
diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def
index 1dfcf5f991..85e717c122 100644
--- a/grub-core/Makefile.core.def
+++ b/grub-core/Makefile.core.def
@@ -333,6 +333,7 @@ kernel = {
powerpc_ieee1275 = kern/powerpc/dl.c;
powerpc_ieee1275 = kern/powerpc/compiler-rt.S;
powerpc_ieee1275 = kern/lockdown.c;
+ powerpc_ieee1275 = kern/powerpc/ieee1275/platform_keystore.c;
sparc64_ieee1275 = kern/sparc64/cache.S;
sparc64_ieee1275 = kern/sparc64/dl.c;
diff --git a/grub-core/kern/ieee1275/init.c b/grub-core/kern/ieee1275/init.c
index 0e1cbf24c3..45f787eff4 100644
--- a/grub-core/kern/ieee1275/init.c
+++ b/grub-core/kern/ieee1275/init.c
@@ -50,6 +50,8 @@
#include <grub/ieee1275/alloc.h>
#endif
#include <grub/lockdown.h>
+#include <grub/powerpc/ieee1275/ieee1275.h>
+#include <grub/powerpc/ieee1275/platform_keystore.h>
/* The maximum heap size we're going to claim at boot. Not used by sparc. */
#ifdef __i386__
@@ -985,7 +987,7 @@ grub_get_ieee1275_secure_boot (void)
{
grub_ieee1275_phandle_t root;
int rc;
- grub_uint32_t is_sb;
+ grub_uint32_t is_sb = 0;
if (grub_ieee1275_finddevice ("/", &root))
{
@@ -1009,7 +1011,16 @@ grub_get_ieee1275_secure_boot (void)
* We only support enforce.
*/
if (is_sb >= 2)
- grub_lockdown ();
+ {
+ grub_printf ("Secure Boot Enabled\n");
+ rc = grub_pks_keystore_init ();
+ if (rc != GRUB_ERR_NONE)
+ grub_printf ("Initialization of the Platform Keystore failed!\n");
+
+ grub_lockdown ();
+ }
+ else
+ grub_printf ("Secure Boot Disabled\n");
}
grub_addr_t grub_modbase;
diff --git a/grub-core/kern/powerpc/ieee1275/platform_keystore.c b/grub-core/kern/powerpc/ieee1275/platform_keystore.c
new file mode 100644
index 0000000000..ea9f27eb22
--- /dev/null
+++ b/grub-core/kern/powerpc/ieee1275/platform_keystore.c
@@ -0,0 +1,335 @@
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2024 Free Software Foundation, Inc.
+ * Copyright (C) 2024 IBM Corporation
+ *
+ * GRUB is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GRUB is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GRUB. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <grub/mm.h>
+#include <grub/powerpc/ieee1275/ieee1275.h>
+#include <grub/types.h>
+#include <grub/misc.h>
+#include <grub/lockdown.h>
+#include <grub/powerpc/ieee1275/platform_keystore.h>
+
+#define PKS_CONSUMER_FW 1
+#define SB_VERSION_KEY_NAME ((grub_uint8_t *) "SB_VERSION")
+#define SB_VERSION_KEY_LEN 10
+#define DB 1
+#define DBX 2
+#define PKS_OBJECT_NOT_FOUND ((grub_err_t) - 7)
+
+/* Platform Keystore */
+static grub_size_t pks_max_object_size;
+grub_uint8_t grub_pks_use_keystore = 0;
+grub_pks_t grub_pks_keystore = { .db = NULL, .dbx = NULL, .db_entries = 0, .dbx_entries = 0 };
+
+/* Convert the esl data into the ESL */
+static grub_esl_t *
+convert_to_esl (const grub_uint8_t *esl_data, const grub_size_t esl_data_size)
+{
+ grub_esl_t *esl = NULL;
+
+ if (esl_data_size < sizeof (grub_esl_t) || esl_data == NULL)
+ return esl;
+
+ esl = (grub_esl_t *) esl_data;
+
+ return esl;
+}
+
+/*
+ * Import the GUID, esd, and its size into the pks sd buffer and
+ * pks sd entries from the EFI signature list.
+ */
+static grub_err_t
+esd_from_esl (const grub_uint8_t *esl_data, grub_size_t esl_size,
+ const grub_size_t signature_size, const grub_uuid_t *guid,
+ grub_pks_sd_t **pks_sd, grub_size_t *pks_sd_entries)
+{
+ grub_esd_t *esd = NULL;
+ grub_pks_sd_t *signature = *pks_sd;
+ grub_size_t entries = *pks_sd_entries;
+ grub_size_t data_size = 0, offset = 0;
+
+ /* reads the esd from esl */
+ while (esl_size > 0)
+ {
+ esd = (grub_esd_t *) (esl_data + offset);
+ data_size = signature_size - sizeof (grub_esd_t);
+
+ signature = grub_realloc (signature, (entries + 1) * sizeof (grub_pks_sd_t));
+ if (signature == NULL)
+ return grub_error (GRUB_ERR_OUT_OF_MEMORY, "out of memory");
+
+ signature[entries].data = grub_malloc (data_size * sizeof (grub_uint8_t));
+ if (signature[entries].data == NULL)
+ {
+ /*
+ * allocated memory will be freed by
+ * grub_free_platform_keystore
+ */
+ *pks_sd = signature;
+ *pks_sd_entries = entries + 1;
+ return grub_error (GRUB_ERR_OUT_OF_MEMORY, "out of memory");
+ }
+
+ grub_memcpy (signature[entries].data, esd->signaturedata, data_size);
+ signature[entries].data_size = data_size;
+ signature[entries].guid = *guid;
+ entries++;
+ esl_size -= signature_size;
+ offset += signature_size;
+ }
+
+ *pks_sd = signature;
+ *pks_sd_entries = entries;
+
+ return GRUB_ERR_NONE;
+}
+
+/*
+ * Extract the esd after removing the esl header from esl.
+ */
+static grub_err_t
+esl_to_esd (const grub_uint8_t *esl_data, grub_size_t *next_esl,
+ grub_pks_sd_t **pks_sd, grub_size_t *pks_sd_entries)
+{
+ grub_uuid_t guid = { 0 };
+ grub_esl_t *esl = NULL;
+ grub_size_t offset = 0, esl_size = 0,
+ signature_size = 0, signature_header_size = 0;
+
+ esl = convert_to_esl (esl_data, *next_esl);
+ if (esl == NULL)
+ return grub_error (GRUB_ERR_BUG, "invalid ESL");
+
+ esl_size = grub_le_to_cpu32 (esl->signaturelistsize);
+ signature_header_size = grub_le_to_cpu32 (esl->signatureheadersize);
+ signature_size = grub_le_to_cpu32 (esl->signaturesize);
+ guid = esl->signaturetype;
+
+ if (esl_size < sizeof (grub_esl_t) || esl_size > *next_esl)
+ return grub_error (GRUB_ERR_BUG, "invalid ESL size (%u)\n", esl_size);
+
+ *next_esl = esl_size;
+ offset = sizeof (grub_esl_t) + signature_header_size;
+ esl_size = esl_size - offset;
+
+ return esd_from_esl (esl_data + offset, esl_size, signature_size, &guid,
+ pks_sd, pks_sd_entries);
+}
+
+/*
+ * Import the EFI signature data and the number of esd from the esl
+ * into the pks sd buffer and pks sd entries.
+ */
+static grub_err_t
+pks_sd_from_esl (const grub_uint8_t *esl_data, grub_size_t esl_size,
+ grub_pks_sd_t **pks_sd, grub_size_t *pks_sd_entries)
+{
+ grub_err_t rc = GRUB_ERR_NONE;
+ grub_size_t next_esl = esl_size;
+
+ do
+ {
+ rc = esl_to_esd (esl_data, &next_esl, pks_sd, pks_sd_entries);
+ if (rc != GRUB_ERR_NONE)
+ break;
+
+ esl_data += next_esl;
+ esl_size -= next_esl;
+ next_esl = esl_size;
+ }
+ while (esl_size > 0);
+
+ return rc;
+}
+
+/*
+ * Read the secure boot version from PKS as an object.
+ * caller must free result
+ */
+static grub_err_t
+read_sbversion_from_pks (grub_uint8_t **out, grub_size_t *outlen, grub_size_t *policy)
+{
+ *out = grub_malloc (pks_max_object_size);
+ if (*out == NULL)
+ return grub_error (GRUB_ERR_OUT_OF_MEMORY, "out of memory");
+
+ return grub_ieee1275_pks_read_object (PKS_CONSUMER_FW, SB_VERSION_KEY_NAME,
+ SB_VERSION_KEY_LEN, *out, pks_max_object_size,
+ outlen, policy);
+}
+
+/*
+ * reads the secure boot variable from PKS.
+ * caller must free result
+ */
+static grub_err_t
+read_sbvar_from_pks (const grub_uint8_t sbvarflags, const grub_uint8_t sbvartype,
+ grub_uint8_t **out, grub_size_t *outlen)
+{
+ *out = grub_malloc (pks_max_object_size);
+ if (*out == NULL)
+ return grub_error (GRUB_ERR_OUT_OF_MEMORY, "out of memory");
+
+ return grub_ieee1275_pks_read_sbvar (sbvarflags, sbvartype, *out,
+ pks_max_object_size, outlen);
+}
+
+/* Test the availability of PKS support. */
+static int
+is_support_pks (void)
+{
+ grub_err_t rc = GRUB_ERR_NONE;
+ grub_ieee1275_cell_t missing = 0;
+
+ rc = grub_ieee1275_test ("pks-max-object-size", &missing);
+ if (rc != GRUB_ERR_NONE || (int) missing == -1)
+ grub_printf ("Firmware doesn't have PKS support!\n");
+ else
+ {
+ rc = grub_ieee1275_pks_max_object_size (&pks_max_object_size);
+ if (rc != GRUB_ERR_NONE)
+ grub_printf ("PKS support is there but it has zero objects!\n");
+ }
+
+ return rc;
+}
+
+/*
+ * Retrieve the secure boot variable from PKS, unpacks it, read the esd
+ * from ESL, and store the information in the pks sd buffer.
+ */
+static grub_err_t
+read_secure_boot_variables (const grub_uint8_t sbvarflags, const grub_uint8_t sbvartype,
+ grub_pks_sd_t **pks_sd, grub_size_t *pks_sd_entries)
+{
+ grub_err_t rc = GRUB_ERR_NONE;
+ grub_uint8_t *esl_data = NULL;
+ grub_size_t esl_data_size = 0;
+
+ rc = read_sbvar_from_pks (sbvarflags, sbvartype, &esl_data, &esl_data_size);
+ /*
+ * at this point we have SB_VERSION, so any error is worth
+ * at least some user-visible info
+ */
+ if (rc != GRUB_ERR_NONE)
+ rc = grub_error (rc, "secure boot variable %s reading (%d)",
+ (sbvartype == DB ? "db" : "dbx"), rc);
+ else if (esl_data_size != 0)
+ rc = pks_sd_from_esl ((const grub_uint8_t *) esl_data, esl_data_size,
+ pks_sd, pks_sd_entries);
+ grub_free (esl_data);
+
+ return rc;
+}
+
+/* reads secure boot version (SB_VERSION) and it supports following
+ * SB_VERSION
+ * 1 - PKS
+ * 0 - static key (embeded key)
+ */
+static grub_err_t
+get_secure_boot_version (void)
+{
+ grub_err_t rc = GRUB_ERR_NONE;
+ grub_uint8_t *data = NULL;
+ grub_size_t len = 0, policy = 0;
+
+ rc = read_sbversion_from_pks (&data, &len, &policy);
+ if (rc != GRUB_ERR_NONE)
+ grub_printf ("SB version read failed! (%d)\n", rc);
+ else if (len != 1 || (*data != 1 && *data != 0))
+ {
+ grub_printf ("found unexpected SB version! (%d)\n", *data);
+ rc = GRUB_ERR_INVALID_COMMAND;
+ }
+
+ if (rc != GRUB_ERR_NONE)
+ {
+ grub_printf ("Switch to Static Key!\n");
+ if (grub_is_lockdown () == GRUB_LOCKDOWN_ENABLED)
+ grub_fatal ("Secure Boot locked down");
+ }
+ else
+ grub_pks_use_keystore = *data;
+
+ grub_free (data);
+
+ return rc;
+}
+
+/* Free allocated memory */
+void
+grub_pks_free_keystore (void)
+{
+ grub_size_t i = 0;
+
+ for (i = 0; i < grub_pks_keystore.db_entries; i++)
+ grub_free (grub_pks_keystore.db[i].data);
+
+ for (i = 0; i < grub_pks_keystore.dbx_entries; i++)
+ grub_free (grub_pks_keystore.dbx[i].data);
+
+ grub_free (grub_pks_keystore.db);
+ grub_free (grub_pks_keystore.dbx);
+ grub_memset (&grub_pks_keystore, 0, sizeof (grub_pks_t));
+}
+
+/* Initialization of the Platform Keystore */
+grub_err_t
+grub_pks_keystore_init (void)
+{
+ grub_err_t rc = GRUB_ERR_NONE;
+
+ grub_printf ("trying to load Platform Keystore\n");
+
+ rc = is_support_pks ();
+ if (rc != GRUB_ERR_NONE)
+ {
+ grub_printf ("Switch to Static Key!\n");
+ return rc;
+ }
+
+ /* SB_VERSION */
+ rc = get_secure_boot_version ();
+ if (rc != GRUB_ERR_NONE)
+ return rc;
+
+ if (grub_pks_use_keystore)
+ {
+ grub_memset (&grub_pks_keystore, 0, sizeof (grub_pks_t));
+ /* DB */
+ rc = read_secure_boot_variables (0, DB, &grub_pks_keystore.db, &grub_pks_keystore.db_entries);
+ if (rc == GRUB_ERR_NONE)
+ {
+ /* DBX */
+ rc = read_secure_boot_variables (0, DBX, &grub_pks_keystore.dbx, &grub_pks_keystore.dbx_entries);
+ if (rc == PKS_OBJECT_NOT_FOUND)
+ {
+ grub_printf ("dbx is not found!\n");
+ rc = GRUB_ERR_NONE;
+ }
+ }
+
+ }
+
+ if (rc != GRUB_ERR_NONE)
+ grub_pks_free_keystore ();
+
+ return rc;
+}
diff --git a/include/grub/powerpc/ieee1275/platform_keystore.h b/include/grub/powerpc/ieee1275/platform_keystore.h
new file mode 100644
index 0000000000..0641adb0f1
--- /dev/null
+++ b/include/grub/powerpc/ieee1275/platform_keystore.h
@@ -0,0 +1,225 @@
+/*
+ * Copyright (c) 2006 - 2015, Intel Corporation. All rights reserved. This
+ * program and the accompanying materials are licensed and made available
+ * under the terms and conditions of the 2-Clause BSD License which
+ * accompanies this distribution.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ *
+ * https://github.com/tianocore/edk2-staging (edk2-staging repo of tianocore),
+ * the ImageAuthentication.h file under it, and here's the copyright and license.
+ *
+ * MdePkg/Include/Guid/ImageAuthentication.h
+ *
+ * Copyright 2024 IBM Corp.
+ */
+
+#ifndef __PLATFORM_KEYSTORE_H__
+#define __PLATFORM_KEYSTORE_H__
+
+#include <grub/symbol.h>
+#include <grub/mm.h>
+#include <grub/types.h>
+
+#if __GNUC__ >= 9
+#pragma GCC diagnostic ignored "-Waddress-of-packed-member"
+#endif
+
+#define GRUB_MAX_HASH_SIZE 64
+
+typedef struct grub_esd grub_esd_t;
+typedef struct grub_esl grub_esl_t;
+
+/*
+ * It is derived from EFI_SIGNATURE_DATA
+ * https://github.com/tianocore/edk2-staging/blob/master/MdePkg/Include/Guid/ImageAuthentication.h
+ *
+ * The structure of an EFI signature database (ESD).*/
+struct grub_esd
+{
+ /*
+ * An identifier which identifies the agent which added
+ * the signature to the list.
+ */
+ grub_uuid_t signatureowner;
+ /* The format of the signature is defined by the SignatureType.*/
+ grub_uint8_t signaturedata[];
+} GRUB_PACKED;
+
+/*
+ * It is derived from EFI_SIGNATURE_LIST
+ * https://github.com/tianocore/edk2-staging/blob/master/MdePkg/Include/Guid/ImageAuthentication.h
+ *
+ * The structure of an EFI signature list (ESL).*/
+struct grub_esl
+{
+ /* Type of the signature. GUID signature types are defined in below.*/
+ grub_uuid_t signaturetype;
+ /* Total size of the signature list, including this header.*/
+ grub_uint32_t signaturelistsize;
+ /*
+ * Size of the signature header which precedes
+ * the array of signatures.
+ */
+ grub_uint32_t signatureheadersize;
+ /* Size of each signature.*/
+ grub_uint32_t signaturesize;
+} GRUB_PACKED;
+
+/*
+ * It is derived from EFI_CERT_X509_GUID
+ * https://github.com/tianocore/edk2-staging/blob/master/MdePkg/Include/Guid/ImageAuthentication.h
+ */
+#define GRUB_PKS_CERT_X509_GUID \
+ (grub_uuid_t) \
+ { \
+ { \
+ 0xa1, 0x59, 0xc0, 0xa5, 0xe4, 0x94, \
+ 0xa7, 0x4a, 0x87, 0xb5, 0xab, 0x15, \
+ 0x5c, 0x2b, 0xf0, 0x72 \
+ } \
+ }
+
+/*
+ * It is derived from EFI_CERT_SHA256_GUID
+ * https://github.com/tianocore/edk2-staging/blob/master/MdePkg/Include/Guid/ImageAuthentication.h
+ */
+#define GRUB_PKS_CERT_SHA256_GUID \
+ (grub_uuid_t) \
+ { \
+ { \
+ 0x26, 0x16, 0xc4, 0xc1, 0x4c, 0x50, \
+ 0x92, 0x40, 0xac, 0xa9, 0x41, 0xf9, \
+ 0x36, 0x93, 0x43, 0x28 \
+ } \
+ }
+
+/*
+ * It is derived from EFI_CERT_SHA384_GUID
+ * https://github.com/tianocore/edk2-staging/blob/master/MdePkg/Include/Guid/ImageAuthentication.h
+ */
+#define GRUB_PKS_CERT_SHA384_GUID \
+ (grub_uuid_t) \
+ { \
+ { \
+ 0x07, 0x53, 0x3e, 0xff, 0xd0, 0x9f, \
+ 0xc9, 0x48, 0x85, 0xf1, 0x8a, 0xd5, \
+ 0x6c, 0x70, 0x1e, 0x1 \
+ } \
+ }
+
+/*
+ * It is derived from EFI_CERT_SHA512_GUID
+ * https://github.com/tianocore/edk2-staging/blob/master/MdePkg/Include/Guid/ImageAuthentication.h
+ */
+#define GRUB_PKS_CERT_SHA512_GUID \
+ (grub_uuid_t) \
+ { \
+ { \
+ 0xae, 0x0f, 0x3e, 0x09, 0xc4, 0xa6, \
+ 0x50, 0x4f, 0x9f, 0x1b, 0xd4, 0x1e, \
+ 0x2b, 0x89, 0xc1, 0x9a \
+ } \
+ }
+
+/*
+ * It is derived from EFI_CERT_X509_SHA256_GUID
+ * https://github.com/tianocore/edk2-staging/blob/master/MdePkg/Include/Guid/ImageAuthentication.h
+ */
+#define GRUB_PKS_CERT_X509_SHA256_GUID \
+ (grub_uuid_t) \
+ { \
+ { \
+ 0x92, 0xa4, 0xd2, 0x3b, 0xc0, 0x96, \
+ 0x79, 0x40, 0xb4, 0x20, 0xfc, 0xf9, \
+ 0x8e, 0xf1, 0x03, 0xed \
+ } \
+ }
+
+/*
+ * It is derived from EFI_CERT_X509_SHA384_GUID
+ * https://github.com/tianocore/edk2-staging/blob/master/MdePkg/Include/Guid/ImageAuthentication.h
+ */
+#define GRUB_PKS_CERT_X509_SHA384_GUID \
+ (grub_uuid_t) \
+ { \
+ { \
+ 0x6e, 0x87, 0x76, 0x70, 0xc2, 0x80, \
+ 0xe6, 0x4e, 0xaa, 0xd2, 0x28, 0xb3, \
+ 0x49, 0xa6, 0x86, 0x5b \
+ } \
+ }
+
+/*
+ * It is derived from EFI_CERT_X509_SHA512_GUID
+ * https://github.com/tianocore/edk2-staging/blob/master/MdePkg/Include/Guid/ImageAuthentication.h
+ */
+#define GRUB_PKS_CERT_X509_SHA512_GUID \
+ (grub_uuid_t) \
+ { \
+ { \
+ 0x63, 0xbf, 0x6d, 0x44, 0x02, 0x25, \
+ 0xda, 0x4c, 0xbc, 0xfa, 0x24, 0x65, \
+ 0xd2, 0xb0, 0xfe, 0x9d \
+ } \
+ }
+
+typedef struct grub_pks_sd grub_pks_sd_t;
+typedef struct grub_pks grub_pks_t;
+
+/* The structure of a PKS signature data.*/
+struct grub_pks_sd
+{
+ grub_uuid_t guid; /* signature type */
+ grub_uint8_t *data; /* signature data */
+ grub_size_t data_size; /* size of signature data */
+} GRUB_PACKED;
+
+/* The structure of a PKS.*/
+struct grub_pks
+{
+ grub_pks_sd_t *db; /* signature database */
+ grub_pks_sd_t *dbx; /* forbidden signature database */
+ grub_size_t db_entries; /* size of signature database */
+ grub_size_t dbx_entries; /* size of forbidden signature database */
+} GRUB_PACKED;
+
+#ifdef __powerpc__
+
+/* Initialization of the Platform Keystore */
+grub_err_t grub_pks_keystore_init (void);
+/* Free allocated memory */
+void EXPORT_FUNC(grub_pks_free_keystore) (void);
+extern grub_uint8_t EXPORT_VAR(grub_pks_use_keystore);
+extern grub_pks_t EXPORT_VAR(grub_pks_keystore);
+
+#else
+
+#define grub_pks_use_keystore 0
+grub_pks_t grub_pks_keystore = {NULL, NULL, 0, 0};
+void grub_pks_free_keystore (void);
+
+#endif
+
+#endif
diff --git a/include/grub/types.h b/include/grub/types.h
index 064066e2e1..5542b9aa09 100644
--- a/include/grub/types.h
+++ b/include/grub/types.h
@@ -388,4 +388,13 @@ struct grub_packed_guid
} GRUB_PACKED;
typedef struct grub_packed_guid grub_packed_guid_t;
+
+#define GRUB_UUID_SIZE 16
+typedef struct grub_uuid grub_uuid_t;
+/* The structure of a UUID.*/
+struct grub_uuid
+{
+ grub_uint8_t b[GRUB_UUID_SIZE];
+};
+
#endif /* ! GRUB_TYPES_HEADER */
--
2.48.1

View File

@@ -0,0 +1,66 @@
From 041164d00e79ffd2433675a5dd5b824833b9fc6a Mon Sep 17 00:00:00 2001
From: Gary Lin <glin@suse.com>
Date: Mon, 7 Apr 2025 16:29:17 +0800
Subject: [PATCH 3/7] tss2: Fix the missing authCommand
grub_tpm2_readpublic() and grub_tpm2_testparms() didn't check
authCommand when marshaling the input data buffer. Currently, there is
no caller using non-NULL authCommand. However, to avoid the potential
issue, the conditional check is added to insert authCommand into the
input buffer if necessary.
Also fix a few pointer checks.
Signed-off-by: Gary Lin <glin@suse.com>
Reviewed-by: Stefan Berger <stefanb@linux.ibm.com>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
---
grub-core/lib/tss2/tpm2_cmd.c | 10 +++++++---
1 file changed, 7 insertions(+), 3 deletions(-)
diff --git a/grub-core/lib/tss2/tpm2_cmd.c b/grub-core/lib/tss2/tpm2_cmd.c
index cd0c6fd31..211d807d5 100644
--- a/grub-core/lib/tss2/tpm2_cmd.c
+++ b/grub-core/lib/tss2/tpm2_cmd.c
@@ -341,6 +341,8 @@ grub_tpm2_readpublic (const TPMI_DH_OBJECT_t objectHandle,
/* Marshal */
grub_tpm2_buffer_init (&in);
grub_tpm2_buffer_pack_u32 (&in, objectHandle);
+ if (authCommand != NULL)
+ grub_Tss2_MU_TPMS_AUTH_COMMAND_Marshal (&in, authCommand);
if (in.error != 0)
return TPM_RC_FAILURE;
@@ -398,7 +400,7 @@ grub_tpm2_load (const TPMI_DH_OBJECT_t parent_handle,
/* Marshal */
grub_tpm2_buffer_init (&in);
grub_tpm2_buffer_pack_u32 (&in, parent_handle);
- if (authCommand)
+ if (authCommand != NULL)
grub_Tss2_MU_TPMS_AUTH_COMMAND_Marshal (&in, authCommand);
grub_Tss2_MU_TPM2B_Marshal (&in, inPrivate->size, inPrivate->buffer);
grub_Tss2_MU_TPM2B_PUBLIC_Marshal (&in, inPublic);
@@ -461,9 +463,9 @@ grub_tpm2_loadexternal (const TPMS_AUTH_COMMAND_t *authCommand,
/* Marshal */
grub_tpm2_buffer_init (&in);
- if (authCommand)
+ if (authCommand != NULL)
grub_Tss2_MU_TPMS_AUTH_COMMAND_Marshal (&in, authCommand);
- if (inPrivate)
+ if (inPrivate != NULL)
grub_Tss2_MU_TPM2B_SENSITIVE_Marshal (&in, inPrivate);
else
grub_tpm2_buffer_pack_u16 (&in, 0);
@@ -1023,6 +1025,8 @@ grub_tpm2_testparms (const TPMT_PUBLIC_PARMS_t *parms,
/* Marshal */
grub_tpm2_buffer_init (&in);
grub_Tss2_MU_TPMT_PUBLIC_PARMS_Marshal (&in, parms);
+ if (authCommand != NULL)
+ grub_Tss2_MU_TPMS_AUTH_COMMAND_Marshal (&in, authCommand);
if (in.error != 0)
return TPM_RC_FAILURE;
--
2.43.0

View File

@@ -0,0 +1,298 @@
From cf6b16f113b1b5e6efce79b569be1de3e504de8f Mon Sep 17 00:00:00 2001
From: Rashmica Gupta <rashmica.g@gmail.com>
Date: Thu, 11 Jun 2020 11:26:23 +1000
Subject: [PATCH 04/23] Add suport for signing grub with an appended signature
Add infrastructure to allow firmware to verify the integrity of grub
by use of a Linux-kernel-module-style appended signature. We initially
target powerpc-ieee1275, but the code should be extensible to other
platforms.
Usually these signatures are appended to a file without modifying the
ELF file itself. (This is what the 'sign-file' tool does, for example.)
The verifier loads the signed file from the file system and looks at the
end of the file for the appended signature. However, on powerpc-ieee1275
platforms, the bootloader is often stored directly in the PReP partition
as raw bytes without a file-system. This makes determining the location
of an appended signature more difficult.
To address this, we add a new ELF note.
The name field of shall be the string "Appended-Signature", zero-padded
to 4 byte alignment. The type field shall be 0x41536967 (the ASCII values
for the string "ASig"). It must be the final section in the ELF binary.
The description shall contain the appended signature structure as defined
by the Linux kernel. The description will also be padded to be a multiple
of 4 bytes. The padding shall be added before the appended signature
structure (not at the end) so that the final bytes of a signed ELF file
are the appended signature magic.
A subsequent patch documents how to create a grub core.img validly signed
under this scheme.
Signed-off-by: Daniel Axtens <dja@axtens.net>
Signed-off-by: Rashmica Gupta <rashmica.g@gmail.com>
---
You can experiment with this code with a patched version of SLOF
that verifies these signatures. You can find one at:
https://github.com/daxtens/SLOF
I will be proposing this for inclusion in a future Power Architecture
Platform Reference (PAPR).
---
include/grub/util/install.h | 8 ++++++--
include/grub/util/mkimage.h | 4 ++--
util/grub-install-common.c | 15 +++++++++++---
util/grub-mkimage.c | 11 +++++++++++
util/grub-mkimagexx.c | 39 ++++++++++++++++++++++++++++++++++++-
util/mkimage.c | 13 +++++++------
6 files changed, 76 insertions(+), 14 deletions(-)
--- a/include/grub/util/install.h
+++ b/include/grub/util/install.h
@@ -67,6 +67,9 @@
N_("SBAT metadata"), 0 }, \
{ "disable-shim-lock", GRUB_INSTALL_OPTIONS_DISABLE_SHIM_LOCK, 0, 0, \
N_("disable shim_lock verifier"), 0 }, \
+ { "appended-signature-size", GRUB_INSTALL_OPTIONS_APPENDED_SIGNATURE_SIZE,\
+ "SIZE", 0, N_("Add a note segment reserving SIZE bytes for an appended signature"), \
+ 1}, \
{ "verbose", 'v', 0, 0, \
N_("print verbose messages."), 1 }
@@ -130,7 +133,8 @@
GRUB_INSTALL_OPTIONS_INSTALL_CORE_COMPRESS,
GRUB_INSTALL_OPTIONS_DTB,
GRUB_INSTALL_OPTIONS_SBAT,
- GRUB_INSTALL_OPTIONS_DISABLE_SHIM_LOCK
+ GRUB_INSTALL_OPTIONS_DISABLE_SHIM_LOCK,
+ GRUB_INSTALL_OPTIONS_APPENDED_SIGNATURE_SIZE
};
extern char *grub_install_source_directory;
@@ -190,7 +194,7 @@
size_t npubkeys,
char *config_path,
const struct grub_install_image_target_desc *image_target,
- int note,
+ int note, size_t appsig_size,
grub_compression_t comp, const char *dtb_file,
const char *sbat_path, const int disable_shim_lock);
--- a/include/grub/util/mkimage.h
+++ b/include/grub/util/mkimage.h
@@ -51,12 +51,12 @@
const struct grub_install_image_target_desc *image_target);
void
grub_mkimage_generate_elf32 (const struct grub_install_image_target_desc *image_target,
- int note, char **core_img, size_t *core_size,
+ int note, size_t appsig_size, char **core_img, size_t *core_size,
Elf32_Addr target_addr,
struct grub_mkimage_layout *layout);
void
grub_mkimage_generate_elf64 (const struct grub_install_image_target_desc *image_target,
- int note, char **core_img, size_t *core_size,
+ int note, size_t appsig_size, char **core_img, size_t *core_size,
Elf64_Addr target_addr,
struct grub_mkimage_layout *layout);
--- a/util/grub-install-common.c
+++ b/util/grub-install-common.c
@@ -466,10 +466,12 @@
static char *sbat;
static int disable_shim_lock;
static grub_compression_t compression;
+static size_t appsig_size;
int
grub_install_parse (int key, char *arg)
{
+ const char *end;
switch (key)
{
case GRUB_INSTALL_OPTIONS_INSTALL_CORE_COMPRESS:
@@ -567,6 +569,12 @@
grub_util_error (_("Unrecognized compression `%s'"), arg);
case GRUB_INSTALL_OPTIONS_GRUB_MKIMAGE:
return 1;
+ case GRUB_INSTALL_OPTIONS_APPENDED_SIGNATURE_SIZE:
+ grub_errno = 0;
+ appsig_size = grub_strtol(arg, &end, 10);
+ if (grub_errno)
+ return 0;
+ return 1;
default:
return 0;
}
@@ -679,9 +687,11 @@
*p = '\0';
grub_util_info ("grub-mkimage --directory '%s' --prefix '%s' --output '%s'"
- " --format '%s' --compression '%s'%s%s%s\n",
+ " --format '%s' --compression '%s'"
+ " --appended-signature-size %zu%s%s%s\n",
dir, prefix, outname,
mkimage_target, compnames[compression],
+ appsig_size,
note ? " --note" : "",
disable_shim_lock ? " --disable-shim-lock" : "", s);
free (s);
@@ -693,7 +703,7 @@
grub_install_generate_image (dir, prefix, fp, outname,
modules.entries, memdisk_path,
pubkeys, npubkeys, config_path, tgt,
- note, compression, dtb, sbat,
+ note, appsig_size, compression, dtb, sbat,
disable_shim_lock);
while (dc--)
grub_install_pop_module ();
--- a/util/grub-mkimage.c
+++ b/util/grub-mkimage.c
@@ -84,6 +84,7 @@
{"sbat", 's', N_("FILE"), 0, N_("SBAT metadata"), 0},
{"disable-shim-lock", GRUB_INSTALL_OPTIONS_DISABLE_SHIM_LOCK, 0, 0, N_("disable shim_lock verifier"), 0},
{"verbose", 'v', 0, 0, N_("print verbose messages."), 0},
+ {"appended-signature-size", 'S', N_("SIZE"), 0, N_("Add a note segment reserving SIZE bytes for an appended signature"), 0},
{ 0, 0, 0, 0, 0, 0 }
};
@@ -128,6 +129,7 @@
char *sbat;
int note;
int disable_shim_lock;
+ size_t appsig_size;
const struct grub_install_image_target_desc *image_target;
grub_compression_t comp;
};
@@ -138,6 +140,7 @@
/* Get the input argument from argp_parse, which we
know is a pointer to our arguments structure. */
struct arguments *arguments = state->input;
+ const char* end;
switch (key)
{
@@ -170,6 +173,13 @@
arguments->note = 1;
break;
+ case 'S':
+ grub_errno = 0;
+ arguments->appsig_size = grub_strtol(arg, &end, 10);
+ if (grub_errno)
+ return 0;
+ break;
+
case 'm':
if (arguments->memdisk)
free (arguments->memdisk);
@@ -324,6 +334,7 @@
arguments.memdisk, arguments.pubkeys,
arguments.npubkeys, arguments.config,
arguments.image_target, arguments.note,
+ arguments.appsig_size,
arguments.comp, arguments.dtb,
arguments.sbat, arguments.disable_shim_lock);
--- a/util/grub-mkimagexx.c
+++ b/util/grub-mkimagexx.c
@@ -85,6 +85,15 @@
struct grub_ieee1275_note_desc descriptor;
};
+#define GRUB_APPENDED_SIGNATURE_NOTE_NAME "Appended-Signature"
+#define GRUB_APPENDED_SIGNATURE_NOTE_TYPE 0x41536967 /* "ASig" */
+
+struct grub_appended_signature_note
+{
+ Elf32_Nhdr header;
+ char name[ALIGN_UP(sizeof (GRUB_APPENDED_SIGNATURE_NOTE_NAME), 4)];
+};
+
#define GRUB_XEN_NOTE_NAME "Xen"
struct fixup_block_list
@@ -208,7 +217,7 @@
void
SUFFIX (grub_mkimage_generate_elf) (const struct grub_install_image_target_desc *image_target,
- int note, char **core_img, size_t *core_size,
+ int note, size_t appsig_size, char **core_img, size_t *core_size,
Elf_Addr target_addr,
struct grub_mkimage_layout *layout)
{
@@ -222,6 +231,12 @@
int shnum = 4;
int string_size = sizeof (".text") + sizeof ("mods") + 1;
+ if (appsig_size)
+ {
+ phnum++;
+ footer_size += ALIGN_UP(sizeof (struct grub_appended_signature_note) + appsig_size, 4);
+ }
+
if (image_target->id != IMAGE_LOONGSON_ELF)
phnum += 2;
@@ -485,6 +500,28 @@
phdr->p_offset = grub_host_to_target32 (header_size + program_size);
}
+ if (appsig_size) {
+ int note_size = ALIGN_UP(sizeof (struct grub_appended_signature_note) + appsig_size, 4);
+ struct grub_appended_signature_note *note_ptr = (struct grub_appended_signature_note *)
+ (elf_img + program_size + header_size + (note ? sizeof (struct grub_ieee1275_note) : 0));
+
+ note_ptr->header.n_namesz = grub_host_to_target32 (sizeof (GRUB_APPENDED_SIGNATURE_NOTE_NAME));
+ /* needs to sit at the end, so we round this up and sign some zero padding */
+ note_ptr->header.n_descsz = grub_host_to_target32 (ALIGN_UP(appsig_size, 4));
+ note_ptr->header.n_type = grub_host_to_target32 (GRUB_APPENDED_SIGNATURE_NOTE_TYPE);
+ strcpy (note_ptr->name, GRUB_APPENDED_SIGNATURE_NOTE_NAME);
+
+ phdr++;
+ phdr->p_type = grub_host_to_target32 (PT_NOTE);
+ phdr->p_flags = grub_host_to_target32 (PF_R);
+ phdr->p_align = grub_host_to_target32 (image_target->voidp_sizeof);
+ phdr->p_vaddr = 0;
+ phdr->p_paddr = 0;
+ phdr->p_filesz = grub_host_to_target32 (note_size);
+ phdr->p_memsz = 0;
+ phdr->p_offset = grub_host_to_target32 (header_size + program_size + (note ? sizeof (struct grub_ieee1275_note) : 0));
+ }
+
{
char *str_start = (elf_img + sizeof (*ehdr) + phnum * sizeof (*phdr)
+ shnum * sizeof (*shdr));
--- a/util/mkimage.c
+++ b/util/mkimage.c
@@ -885,8 +885,9 @@
char *memdisk_path, char **pubkey_paths,
size_t npubkeys, char *config_path,
const struct grub_install_image_target_desc *image_target,
- int note, grub_compression_t comp, const char *dtb_path,
- const char *sbat_path, int disable_shim_lock)
+ int note, size_t appsig_size, grub_compression_t comp,
+ const char *dtb_path, const char *sbat_path,
+ int disable_shim_lock)
{
char *kernel_img, *core_img;
size_t total_module_size, core_size;
@@ -1810,11 +1811,11 @@
else
target_addr = image_target->link_addr;
if (image_target->voidp_sizeof == 4)
- grub_mkimage_generate_elf32 (image_target, note, &core_img, &core_size,
- target_addr, &layout);
+ grub_mkimage_generate_elf32 (image_target, note, appsig_size, &core_img,
+ &core_size, target_addr, &layout);
else
- grub_mkimage_generate_elf64 (image_target, note, &core_img, &core_size,
- target_addr, &layout);
+ grub_mkimage_generate_elf64 (image_target, note, appsig_size, &core_img,
+ &core_size, target_addr, &layout);
}
break;
}

View File

@@ -27,9 +27,9 @@ Signed-off-by: Michael Chang <mchang@suse.com>
--- a/grub-core/Makefile.core.def
+++ b/grub-core/Makefile.core.def
@@ -2794,3 +2794,9 @@
name = cmdline;
common = lib/cmdline.c;
@@ -2679,3 +2679,9 @@
common = lib/libtasn1_wrap/tests/Test_strings.c;
common = lib/libtasn1_wrap/wrap_tests.c;
};
+
+module = {

View File

@@ -0,0 +1,798 @@
From eb82056864ac03155a9dd18adbf1ca1c60dc69b5 Mon Sep 17 00:00:00 2001
From: Sudhakar Kuppusamy <sudhakar@linux.ibm.com>
Date: Tue, 25 Feb 2025 00:06:18 +0530
Subject: [PATCH 4/9] appendedsig: The creation of trusted and distrusted lists
The trusted certificates and binary hashes, distrusted certificates and
binary/certificate hashes will be extracted from the platform keystore buffer
if Secure Boot is enabled with PKS.
In order to verify the integrity of the kernel, the extracted data
needs to be stored stored in the buffer db and dbx.
The trusted certificates will be extracted from the grub ELFNOTE if Secure Boot is
enabled with static key. In order to verify the integerity of the kernel,
the extracted data needs to be stored in the buffer db.
Note:-
If neither the trusted certificate nor binary hash exists in the distrusted list (dbx),
rejects it while extracting certificate/binary hash from the platform keystore buffer.
Signed-off-by: Sudhakar Kuppusamy <sudhakar@linux.ibm.com>
Reviewed-by: Stefan Berger <stefanb@linux.ibm.com>
Reviewed-by: Avnish Chouhan <avnish@linux.ibm.com>
---
grub-core/commands/appendedsig/appendedsig.c | 617 +++++++++++++++++--
grub-core/kern/file.c | 34 +
include/grub/file.h | 1 +
3 files changed, 590 insertions(+), 62 deletions(-)
diff --git a/grub-core/commands/appendedsig/appendedsig.c b/grub-core/commands/appendedsig/appendedsig.c
index e63ad1ac64..3df950c00b 100644
--- a/grub-core/commands/appendedsig/appendedsig.c
+++ b/grub-core/commands/appendedsig/appendedsig.c
@@ -33,7 +33,7 @@
#include <grub/libtasn1.h>
#include <grub/env.h>
#include <grub/lockdown.h>
-
+#include <grub/powerpc/ieee1275/platform_keystore.h>
#include "appendedsig.h"
GRUB_MOD_LICENSE ("GPLv3+");
@@ -66,8 +66,23 @@ struct grub_appended_signature
struct pkcs7_signedData pkcs7; /* Parsed PKCS#7 data */
};
-/* Trusted certificates for verifying appended signatures */
-struct x509_certificate *grub_trusted_key;
+/* This represents a trusted/distrusted list*/
+struct grub_database
+{
+ struct x509_certificate *keys; /* Certificates */
+ grub_size_t key_entries; /* Number of certificates */
+ grub_uint8_t **signatures; /* Certificate/binary hashes */
+ grub_size_t *signature_size; /* Size of certificate/binary hashes */
+ grub_size_t signature_entries; /* Number of certificate/binary hashes */
+};
+
+/* Trusted list */
+struct grub_database db = {.keys = NULL, .key_entries = 0, .signatures = NULL,
+ .signature_size = NULL, .signature_entries = 0};
+
+/* Distrusted list */
+struct grub_database dbx = {.signatures = NULL, .signature_size = NULL,
+ .signature_entries = 0};
/*
* Force gcry_rsa to be a module dependency.
@@ -89,6 +104,13 @@ struct x509_certificate *grub_trusted_key;
* also resolves our concerns about loading from the filesystem.
*/
extern gcry_pk_spec_t _gcry_pubkey_spec_rsa;
+extern gcry_md_spec_t _gcry_digest_spec_sha224;
+extern gcry_md_spec_t _gcry_digest_spec_sha384;
+
+/* Free trusted list memory */
+static void free_trusted_list (void);
+/* Free distrusted list memory */
+static void free_distrusted_list (void);
static enum
{ check_sigs_no = 0,
@@ -96,6 +118,204 @@ static enum
check_sigs_forced = 2
} check_sigs = check_sigs_no;
+/*
+ * GUID can be used to determine the hashing function and
+ * generate the hash using determined hashing function.
+ */
+static grub_err_t
+get_hash (const grub_uuid_t *guid, const grub_uint8_t *data, const grub_size_t data_size,
+ grub_uint8_t *hash, grub_size_t *hash_size)
+{
+ gcry_md_spec_t *hash_func = NULL;
+
+ if (guid == NULL)
+ return grub_error (GRUB_ERR_OUT_OF_RANGE, "GUID is null");
+
+ if (grub_memcmp (guid, &GRUB_PKS_CERT_SHA256_GUID, GRUB_UUID_SIZE) == 0 ||
+ grub_memcmp (guid, &GRUB_PKS_CERT_X509_SHA256_GUID, GRUB_UUID_SIZE) == 0)
+ hash_func = &_gcry_digest_spec_sha256;
+ else if (grub_memcmp (guid, &GRUB_PKS_CERT_SHA384_GUID, GRUB_UUID_SIZE) == 0 ||
+ grub_memcmp (guid, &GRUB_PKS_CERT_X509_SHA384_GUID, GRUB_UUID_SIZE) == 0)
+ hash_func = &_gcry_digest_spec_sha384;
+ else if (grub_memcmp (guid, &GRUB_PKS_CERT_SHA512_GUID, GRUB_UUID_SIZE) == 0 ||
+ grub_memcmp (guid, &GRUB_PKS_CERT_X509_SHA512_GUID, GRUB_UUID_SIZE) == 0)
+ hash_func = &_gcry_digest_spec_sha512;
+ else
+ return grub_error (GRUB_ERR_OUT_OF_RANGE, "Unsupported GUID for hash");
+
+ grub_memset (hash, 0, GRUB_MAX_HASH_SIZE);
+ grub_crypto_hash (hash_func, hash, data, data_size);
+ *hash_size = hash_func->mdlen;
+
+ return GRUB_ERR_NONE;
+}
+
+/* Add the certificate/binary hash into the trusted/distrusted list */
+static grub_err_t
+add_hash (const grub_uint8_t **data, const grub_size_t data_size,
+ grub_uint8_t ***signature_list, grub_size_t **signature_size_list,
+ grub_size_t *signature_list_entries)
+{
+ grub_uint8_t **signatures = *signature_list;
+ grub_size_t *signature_size = *signature_size_list;
+ grub_size_t signature_entries = *signature_list_entries;
+
+ if (*data == NULL || data_size == 0)
+ return grub_error (GRUB_ERR_OUT_OF_RANGE, "certificate/binary hash data/size is null");
+
+ signatures = grub_realloc (signatures, sizeof (grub_uint8_t *) * (signature_entries + 1));
+ signature_size = grub_realloc (signature_size,
+ sizeof (grub_size_t) * (signature_entries + 1));
+
+ if (signatures == NULL || signature_size == NULL)
+ {
+ /*
+ * allocated memory will be freed by
+ * free_trusted_list/free_distrusted_list
+ */
+ if (signatures != NULL)
+ {
+ *signature_list = signatures;
+ *signature_list_entries = signature_entries + 1;
+ }
+
+ if (signature_size != NULL)
+ *signature_size_list = signature_size;
+
+ return grub_error (GRUB_ERR_OUT_OF_MEMORY, "out of memory");
+ }
+
+ signatures[signature_entries] = (grub_uint8_t *) *data;
+ signature_size[signature_entries] = data_size;
+ signature_entries++;
+ *data = NULL;
+
+ *signature_list = signatures;
+ *signature_size_list = signature_size;
+ *signature_list_entries = signature_entries;
+
+ return GRUB_ERR_NONE;
+}
+
+static int
+is_x509 (const grub_uuid_t *guid)
+{
+ if (grub_memcmp (guid, &GRUB_PKS_CERT_X509_GUID, GRUB_UUID_SIZE) == 0)
+ return GRUB_ERR_NONE;
+
+ return GRUB_ERR_UNKNOWN_COMMAND;
+}
+
+static int
+is_cert_match (const struct x509_certificate *distrusted_cert,
+ const struct x509_certificate *db_cert)
+{
+
+ if (grub_memcmp (distrusted_cert->subject, db_cert->subject, db_cert->subject_len) == 0
+ && grub_memcmp (distrusted_cert->serial, db_cert->serial, db_cert->serial_len) == 0
+ && grub_memcmp (distrusted_cert->mpis[0], db_cert->mpis[0], sizeof (db_cert->mpis[0])) == 0
+ && grub_memcmp (distrusted_cert->mpis[1], db_cert->mpis[1], sizeof (db_cert->mpis[1])) == 0)
+ return GRUB_ERR_NONE;
+
+ return GRUB_ERR_UNKNOWN_COMMAND;
+}
+
+/*
+ * Verify the certificate against the certificate from platform keystore buffer's
+ * distrusted list.
+ */
+static grub_err_t
+is_distrusted_cert (const struct x509_certificate *db_cert)
+{
+ grub_err_t rc = GRUB_ERR_NONE;
+ grub_size_t i = 0;
+ struct x509_certificate *distrusted_cert = NULL;
+
+ for (i = 0; i < grub_pks_keystore.dbx_entries; i++)
+ {
+ if (grub_pks_keystore.dbx[i].data == NULL)
+ continue;
+
+ if (is_x509 (&grub_pks_keystore.dbx[i].guid) == GRUB_ERR_NONE)
+ {
+ distrusted_cert = grub_zalloc (sizeof (struct x509_certificate));
+ if (distrusted_cert == NULL)
+ return grub_error (GRUB_ERR_OUT_OF_MEMORY, "out of memory");
+
+ rc = parse_x509_certificate (grub_pks_keystore.dbx[i].data,
+ grub_pks_keystore.dbx[i].data_size, distrusted_cert);
+ if (rc != GRUB_ERR_NONE)
+ {
+ grub_free (distrusted_cert);
+ continue;
+ }
+
+ if (is_cert_match (distrusted_cert, db_cert) == GRUB_ERR_NONE)
+ {
+ grub_printf ("Warning: a trusted certificate CN='%s' is ignored "
+ "because it is on the distrusted list (dbx).\n", db_cert->subject);
+ grub_free (grub_pks_keystore.dbx[i].data);
+ grub_memset (&grub_pks_keystore.dbx[i], 0, sizeof (grub_pks_sd_t));
+ certificate_release (distrusted_cert);
+ grub_free (distrusted_cert);
+ return GRUB_ERR_ACCESS_DENIED;
+ }
+
+ certificate_release (distrusted_cert);
+ grub_free (distrusted_cert);
+ }
+ }
+
+ return GRUB_ERR_NONE;
+}
+
+/* Add the certificate into the trusted/distrusted list */
+static grub_err_t
+add_certificate (const grub_uint8_t *data, const grub_size_t data_size,
+ struct grub_database *database, const grub_size_t is_db)
+{
+ grub_err_t rc = GRUB_ERR_NONE;
+ grub_size_t key_entries = database->key_entries;
+ struct x509_certificate *cert = NULL;
+
+ if (data == NULL || data_size == 0)
+ return grub_error (GRUB_ERR_OUT_OF_RANGE, "certificate data/size is null");
+
+ cert = grub_zalloc (sizeof (struct x509_certificate));
+ if (cert == NULL)
+ return grub_error (GRUB_ERR_OUT_OF_MEMORY, "out of memory");
+
+ rc = parse_x509_certificate (data, data_size, cert);
+ if (rc != GRUB_ERR_NONE)
+ {
+ grub_dprintf ("appendedsig", "skipping %s certificate (%d)\n",
+ (is_db ? "trusted":"distrusted"), rc);
+ grub_free (cert);
+ return rc;
+ }
+
+ if (is_db)
+ {
+ rc = is_distrusted_cert (cert);
+ if (rc != GRUB_ERR_NONE)
+ {
+ certificate_release (cert);
+ grub_free (cert);
+ return rc;
+ }
+ }
+
+ grub_dprintf ("appendedsig", "add a %s certificate CN='%s'\n",
+ (is_db ? "trusted":"distrusted"), cert->subject);
+
+ key_entries++;
+ cert->next = database->keys;
+ database->keys = cert;
+ database->key_entries = key_entries;
+
+ return rc;
+}
+
static const char *
grub_env_read_sec (struct grub_env_var *var __attribute__((unused)),
const char *val __attribute__((unused)))
@@ -267,9 +487,8 @@ grub_verify_appended_signature (const grub_uint8_t *buf, grub_size_t bufsize)
struct pkcs7_signerInfo *si;
int i;
- if (!grub_trusted_key)
- return grub_error (GRUB_ERR_BAD_SIGNATURE,
- N_("No trusted keys to verify against"));
+ if (!db.key_entries)
+ return grub_error (GRUB_ERR_BAD_SIGNATURE, N_("No trusted keys to verify against"));
err = extract_appended_signature (buf, bufsize, &sig);
if (err != GRUB_ERR_NONE)
@@ -299,17 +518,16 @@ grub_verify_appended_signature (const grub_uint8_t *buf, grub_size_t bufsize)
datasize, i, hash[0], hash[1], hash[2], hash[3]);
err = GRUB_ERR_BAD_SIGNATURE;
- for (pk = grub_trusted_key; pk; pk = pk->next)
- {
- rc = grub_crypto_rsa_pad (&hashmpi, hash, si->hash, pk->mpis[0]);
- if (rc)
- {
- err = grub_error (GRUB_ERR_BAD_SIGNATURE,
- N_("Error padding hash for RSA verification: %d"),
- rc);
- grub_free (context);
- goto cleanup;
- }
+ for (pk = db.keys; pk; pk = pk->next)
+ {
+ rc = grub_crypto_rsa_pad (&hashmpi, hash, si->hash, pk->mpis[0]);
+ if (rc)
+ {
+ err = grub_error (GRUB_ERR_BAD_SIGNATURE,
+ N_("Error padding hash for RSA verification: %d"), rc);
+ grub_free (context);
+ goto cleanup;
+ }
rc = _gcry_pubkey_spec_rsa.verify (0, hashmpi, &si->sig_mpi,
pk->mpis, NULL, NULL);
@@ -402,16 +620,16 @@ grub_cmd_distrust (grub_command_t cmd __attribute__((unused)),
if (cert_num == 1)
{
- cert = grub_trusted_key;
- grub_trusted_key = cert->next;
+ cert = db.keys;
+ db.keys = cert->next;
certificate_release (cert);
grub_free (cert);
return GRUB_ERR_NONE;
}
i = 2;
- prev = grub_trusted_key;
- cert = grub_trusted_key->next;
+ prev = db.keys;
+ cert = db.keys->next;
while (cert)
{
if (i == cert_num)
@@ -464,8 +682,8 @@ grub_cmd_trust (grub_command_t cmd __attribute__((unused)),
grub_dprintf ("appendedsig", "Loaded certificate with CN: %s\n",
cert->subject);
- cert->next = grub_trusted_key;
- grub_trusted_key = cert;
+ cert->next = db.keys;
+ db.keys = cert;
return GRUB_ERR_NONE;
}
@@ -479,7 +697,7 @@ grub_cmd_list (grub_command_t cmd __attribute__((unused)),
int cert_num = 1;
grub_size_t i;
- for (cert = grub_trusted_key; cert; cert = cert->next)
+ for (cert = db.keys; cert; cert = cert->next)
{
grub_printf (N_("Certificate %d:\n"), cert_num);
@@ -579,6 +797,274 @@ static struct grub_fs pseudo_fs = {
static grub_command_t cmd_verify, cmd_list, cmd_distrust, cmd_trust;
+/*
+ * Verify the trusted certificate against the certificate hashes from platform keystore buffer's
+ * distrusted list.
+ */
+static grub_err_t
+is_distrusted_cert_hash (const grub_uint8_t *data, const grub_size_t data_size)
+{
+ grub_err_t rc = GRUB_ERR_NONE;
+ grub_size_t i = 0, cert_hash_size = 0;
+ grub_uint8_t cert_hash[GRUB_MAX_HASH_SIZE] = { 0 };
+
+ if (data == NULL || data_size == 0)
+ return grub_error (GRUB_ERR_OUT_OF_RANGE, "trusted certificate data/size is null");
+
+ for (i = 0; i < grub_pks_keystore.dbx_entries; i++)
+ {
+ if (grub_pks_keystore.dbx[i].data == NULL ||
+ grub_pks_keystore.dbx[i].data_size == 0)
+ continue;
+
+ rc = get_hash (&grub_pks_keystore.dbx[i].guid, data, data_size,
+ cert_hash, &cert_hash_size);
+ if (rc != GRUB_ERR_NONE)
+ continue;
+
+ if (cert_hash_size == grub_pks_keystore.dbx[i].data_size &&
+ grub_memcmp (grub_pks_keystore.dbx[i].data, cert_hash, cert_hash_size) == 0)
+ {
+ grub_printf ("Warning: a trusted certificate (%02x%02x%02x%02x) is ignored "
+ "because this certificate hash is on the distrusted list (dbx).\n",
+ cert_hash[0], cert_hash[1], cert_hash[2], cert_hash[3]);
+ grub_free (grub_pks_keystore.dbx[i].data);
+ grub_memset (&grub_pks_keystore.dbx[i], 0, sizeof (grub_pks_keystore.dbx[i]));
+ return GRUB_ERR_BAD_SIGNATURE;
+ }
+ }
+
+ return GRUB_ERR_NONE;
+}
+
+/*
+ * Verify the trusted binary hash against the platform keystore buffer's
+ * distrusted list.
+ */
+static grub_err_t
+is_distrusted_binary_hash (const grub_uint8_t *binary_hash,
+ const grub_size_t binary_hash_size)
+{
+ grub_size_t i = 0;
+
+ for (i = 0; i < grub_pks_keystore.dbx_entries; i++)
+ {
+ if (grub_pks_keystore.dbx[i].data == NULL ||
+ grub_pks_keystore.dbx[i].data_size == 0)
+ continue;
+
+ if (binary_hash_size == grub_pks_keystore.dbx[i].data_size &&
+ grub_memcmp (grub_pks_keystore.dbx[i].data, binary_hash, binary_hash_size) == 0)
+ {
+ grub_printf ("Warning: a trusted binary hash (%02x%02x%02x%02x) is ignored"
+ " because it is on the distrusted list (dbx).\n",
+ binary_hash[0], binary_hash[1], binary_hash[2], binary_hash[3]);
+ grub_free (grub_pks_keystore.dbx[i].data);
+ grub_memset (&grub_pks_keystore.dbx[i], 0, sizeof(grub_pks_keystore.dbx[i]));
+ return GRUB_ERR_BAD_SIGNATURE;
+ }
+ }
+
+ return GRUB_ERR_NONE;
+}
+
+/*
+ * Extract the binary hashes from the platform keystore buffer,
+ * and add it to the trusted list if it does not exist in the distrusted list.
+ */
+static grub_err_t
+add_trusted_binary_hash (const grub_uint8_t **data, const grub_size_t data_size)
+{
+ grub_err_t rc = GRUB_ERR_NONE;
+
+ if (*data == NULL || data_size == 0)
+ return grub_error (GRUB_ERR_OUT_OF_RANGE, "trusted binary hash data/size is null");
+
+ rc = is_distrusted_binary_hash (*data, data_size);
+ if (rc != GRUB_ERR_NONE)
+ return rc;
+
+ rc = add_hash (data, data_size, &db.signatures, &db.signature_size,
+ &db.signature_entries);
+ return rc;
+}
+
+static int
+is_hash (const grub_uuid_t *guid)
+{
+ /* GUID type of the binary hash */
+ if (grub_memcmp (guid, &GRUB_PKS_CERT_SHA256_GUID, GRUB_UUID_SIZE) == 0 ||
+ grub_memcmp (guid, &GRUB_PKS_CERT_SHA384_GUID, GRUB_UUID_SIZE) == 0 ||
+ grub_memcmp (guid, &GRUB_PKS_CERT_SHA512_GUID, GRUB_UUID_SIZE) == 0)
+ return GRUB_ERR_NONE;
+
+ /* GUID type of the certificate hash */
+ if (grub_memcmp (guid, &GRUB_PKS_CERT_X509_SHA256_GUID, GRUB_UUID_SIZE) == 0 ||
+ grub_memcmp (guid, &GRUB_PKS_CERT_X509_SHA384_GUID, GRUB_UUID_SIZE) == 0 ||
+ grub_memcmp (guid, &GRUB_PKS_CERT_X509_SHA512_GUID, GRUB_UUID_SIZE) == 0)
+ return GRUB_ERR_NONE;
+
+ return GRUB_ERR_UNKNOWN_COMMAND;
+}
+
+/*
+ * Extract the x509 certificates/binary hashes from the platform keystore buffer,
+ * parse it, and add it to the trusted list.
+ */
+static grub_err_t
+create_trusted_list (void)
+{
+ grub_err_t rc = GRUB_ERR_NONE;
+ grub_size_t i = 0;
+
+ for (i = 0; i < grub_pks_keystore.db_entries; i++)
+ {
+ if (is_hash (&grub_pks_keystore.db[i].guid) == GRUB_ERR_NONE)
+ {
+ rc = add_trusted_binary_hash ((const grub_uint8_t **)
+ &grub_pks_keystore.db[i].data,
+ grub_pks_keystore.db[i].data_size);
+ if (rc == GRUB_ERR_OUT_OF_MEMORY)
+ return rc;
+ }
+ else if (is_x509 (&grub_pks_keystore.db[i].guid) == GRUB_ERR_NONE)
+ {
+ rc = is_distrusted_cert_hash (grub_pks_keystore.db[i].data,
+ grub_pks_keystore.db[i].data_size);
+ if (rc != GRUB_ERR_NONE)
+ continue;
+
+ rc = add_certificate (grub_pks_keystore.db[i].data,
+ grub_pks_keystore.db[i].data_size, &db, 1);
+ if (rc == GRUB_ERR_OUT_OF_MEMORY)
+ return rc;
+ else if (rc != GRUB_ERR_NONE)
+ continue;
+ }
+ else
+ grub_dprintf ("appendedsig", "unsupported signature data type and "
+ "skipping trusted data (%" PRIuGRUB_SIZE ")\n", i + 1);
+ }
+
+ return GRUB_ERR_NONE;
+}
+
+/*
+ * Extract the certificates, certificate/binary hashes out of the platform keystore buffer,
+ * and add it to the distrusted list.
+ */
+static grub_err_t
+create_distrusted_list (void)
+{
+ grub_err_t rc = GRUB_ERR_NONE;
+ grub_size_t i = 0;
+
+ for (i = 0; i < grub_pks_keystore.dbx_entries; i++)
+ {
+ if (grub_pks_keystore.dbx[i].data != NULL ||
+ grub_pks_keystore.dbx[i].data_size > 0)
+ {
+ if (is_x509 (&grub_pks_keystore.dbx[i].guid) == GRUB_ERR_NONE)
+ {
+ rc = add_certificate (grub_pks_keystore.dbx[i].data,
+ grub_pks_keystore.dbx[i].data_size, &dbx, 0);
+ if (rc == GRUB_ERR_OUT_OF_MEMORY)
+ return rc;
+ }
+ else if (is_hash (&grub_pks_keystore.dbx[i].guid) == GRUB_ERR_NONE)
+ {
+ rc = add_hash ((const grub_uint8_t **) &grub_pks_keystore.dbx[i].data,
+ grub_pks_keystore.dbx[i].data_size,
+ &dbx.signatures, &dbx.signature_size,
+ &dbx.signature_entries);
+ if (rc != GRUB_ERR_NONE)
+ return rc;
+ }
+ else
+ grub_dprintf ("appendedsig", "unsupported signature data type and "
+ "skipping distrusted data (%" PRIuGRUB_SIZE ")\n", i + 1);
+ }
+ }
+
+ return rc;
+}
+
+/*
+ * Extract the x509 certificates from the ELF note header,
+ * parse it, and add it to the trusted list.
+ */
+static grub_err_t
+build_static_trusted_list (const struct grub_module_header *header)
+{
+ grub_err_t err = GRUB_ERR_NONE;
+ struct grub_file pseudo_file;
+ grub_uint8_t *cert_data = NULL;
+ grub_ssize_t cert_data_size = 0;
+
+ grub_memset (&pseudo_file, 0, sizeof (pseudo_file));
+ pseudo_file.fs = &pseudo_fs;
+ pseudo_file.size = header->size - sizeof (struct grub_module_header);
+ pseudo_file.data = (char *) header + sizeof (struct grub_module_header);
+
+ grub_dprintf ("appendedsig", "found an x509 key, size=%" PRIuGRUB_UINT64_T "\n",
+ pseudo_file.size);
+
+ err = grub_read_file (&pseudo_file, &cert_data, &cert_data_size);
+ if (err != GRUB_ERR_NONE)
+ return err;
+
+ err = add_certificate (cert_data, cert_data_size, &db, 1);
+ grub_free (cert_data);
+
+ return err;
+}
+
+/* releasing memory */
+static void
+free_trusted_list (void)
+{
+ struct x509_certificate *cert;
+ grub_size_t i = 0;
+
+ while (db.keys != NULL)
+ {
+ cert = db.keys;
+ db.keys = db.keys->next;
+ certificate_release (cert);
+ grub_free (cert);
+ }
+
+ for (i = 0; i < db.signature_entries; i++)
+ grub_free (db.signatures[i]);
+
+ grub_free (db.signatures);
+ grub_free (db.signature_size);
+ grub_memset (&db, 0, sizeof (db));
+}
+
+/* releasing memory */
+static void
+free_distrusted_list (void)
+{
+ struct x509_certificate *cert;
+ grub_size_t i = 0;
+
+ while (dbx.keys != NULL)
+ {
+ cert = dbx.keys;
+ dbx.keys = dbx.keys->next;
+ certificate_release (cert);
+ grub_free (cert);
+ }
+
+ for (i = 0; i < dbx.signature_entries; i++)
+ grub_free (dbx.signatures[i]);
+
+ grub_free (dbx.signatures);
+ grub_free (dbx.signature_size);
+ grub_memset (&dbx, 0, sizeof (dbx));
+}
+
GRUB_MOD_INIT (appendedsig)
{
int rc;
@@ -588,10 +1074,7 @@ GRUB_MOD_INIT (appendedsig)
if (grub_is_lockdown () == GRUB_LOCKDOWN_ENABLED)
check_sigs = check_sigs_forced;
- grub_trusted_key = NULL;
-
- grub_register_variable_hook ("check_appended_signatures",
- grub_env_read_sec, grub_env_write_sec);
+ grub_register_variable_hook ("check_appended_signatures", grub_env_read_sec, grub_env_write_sec);
grub_env_export ("check_appended_signatures");
rc = asn1_init ();
@@ -599,40 +1082,50 @@ GRUB_MOD_INIT (appendedsig)
grub_fatal ("Error initing ASN.1 data structures: %d: %s\n", rc,
asn1_strerror (rc));
- FOR_MODULES (header)
- {
- struct grub_file pseudo_file;
- struct x509_certificate *pk = NULL;
- grub_err_t err;
-
- /* Not an ELF module, skip. */
- if (header->type != OBJ_TYPE_X509_PUBKEY)
- continue;
-
- grub_memset (&pseudo_file, 0, sizeof (pseudo_file));
- pseudo_file.fs = &pseudo_fs;
- pseudo_file.size = header->size - sizeof (struct grub_module_header);
- pseudo_file.data = (char *) header + sizeof (struct grub_module_header);
-
- grub_dprintf ("appendedsig",
- "Found an x509 key, size=%" PRIuGRUB_UINT64_T "\n",
- pseudo_file.size);
-
- pk = grub_zalloc (sizeof (struct x509_certificate));
- if (!pk)
- {
- grub_fatal ("Out of memory loading initial certificates");
- }
-
- err = read_cert_from_file (&pseudo_file, pk);
- if (err != GRUB_ERR_NONE)
- grub_fatal ("Error loading initial key: %s", grub_errmsg);
-
- grub_dprintf ("appendedsig", "loaded certificate CN='%s'\n", pk->subject);
-
- pk->next = grub_trusted_key;
- grub_trusted_key = pk;
- }
+ if (!grub_pks_use_keystore && check_sigs == check_sigs_forced)
+ {
+ FOR_MODULES (header)
+ {
+ /* Not an ELF module, skip. */
+ if (header->type != OBJ_TYPE_X509_PUBKEY)
+ continue;
+
+ rc = build_static_trusted_list (header);
+ if (rc != GRUB_ERR_NONE)
+ {
+ free_trusted_list ();
+ grub_error (rc, "static trusted list creation failed");
+ }
+ else
+ grub_printf ("appendedsig: the trusted list now has %" PRIuGRUB_SIZE " static keys\n",
+ db.key_entries);
+ }
+ }
+ else if (grub_pks_use_keystore && check_sigs == check_sigs_forced)
+ {
+ rc = create_trusted_list ();
+ if (rc != GRUB_ERR_NONE)
+ {
+ free_trusted_list ();
+ grub_error (rc, "trusted list creation failed");
+ }
+ else
+ {
+ rc = create_distrusted_list ();
+ if (rc != GRUB_ERR_NONE)
+ {
+ free_trusted_list ();
+ free_distrusted_list ();
+ grub_error (rc, "distrusted list creation failed");
+ }
+ else
+ grub_printf ("appendedsig: the trusted list now has %" PRIuGRUB_SIZE " keys.\n"
+ "appendedsig: the distrusted list now has %" PRIuGRUB_SIZE " keys.\n",
+ db.signature_entries + db.key_entries, dbx.signature_entries);
+ }
+
+ grub_pks_free_keystore ();
+ }
cmd_trust =
grub_register_command ("trust_certificate", grub_cmd_trust,
diff --git a/grub-core/kern/file.c b/grub-core/kern/file.c
index 6e7efe89ab..7217a6ea7f 100644
--- a/grub-core/kern/file.c
+++ b/grub-core/kern/file.c
@@ -231,3 +231,37 @@ grub_file_seek (grub_file_t file, grub_off_t offset)
return old;
}
+
+grub_err_t
+grub_read_file (const grub_file_t file, grub_uint8_t **data, grub_ssize_t *data_size)
+{
+ grub_uint8_t *buffer = NULL;
+ grub_ssize_t read_size = 0;
+ grub_off_t total_read_size = 0;
+ grub_off_t file_size = grub_file_size (file);
+
+ if (file_size == GRUB_FILE_SIZE_UNKNOWN)
+ return grub_error (GRUB_ERR_BAD_ARGUMENT,
+ N_("could not determine the size of the file."));
+
+ buffer = grub_zalloc (file_size);
+ if (buffer == NULL)
+ return grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("out of memory"));
+
+ while (total_read_size < file_size)
+ {
+ read_size = grub_file_read (file, &buffer[total_read_size], file_size - total_read_size);
+ if (read_size < 0)
+ {
+ grub_free (buffer);
+ return grub_error (GRUB_ERR_READ_ERROR, N_("unable to read the file"));
+ }
+
+ total_read_size += read_size;
+ }
+
+ *data = buffer;
+ *data_size = total_read_size;
+
+ return GRUB_ERR_NONE;
+}
diff --git a/include/grub/file.h b/include/grub/file.h
index f9484f8d69..804d512231 100644
--- a/include/grub/file.h
+++ b/include/grub/file.h
@@ -219,6 +219,7 @@ grub_ssize_t EXPORT_FUNC(grub_file_read) (grub_file_t file, void *buf,
grub_size_t len);
grub_off_t EXPORT_FUNC(grub_file_seek) (grub_file_t file, grub_off_t offset);
grub_err_t EXPORT_FUNC(grub_file_close) (grub_file_t file);
+grub_err_t EXPORT_FUNC(grub_read_file) (const grub_file_t file, grub_uint8_t **data, grub_ssize_t *data_size);
/* Return value of grub_file_size() in case file size is unknown. */
#define GRUB_FILE_SIZE_UNKNOWN 0xffffffffffffffffULL
--
2.48.1

View File

@@ -79,7 +79,7 @@ Signed-off-by: Michael Chang <mchang@suse.com>
--- a/grub-core/kern/efi/mm.c
+++ b/grub-core/kern/efi/mm.c
@@ -155,6 +155,7 @@
@@ -153,6 +153,7 @@
{
grub_efi_status_t status;
grub_efi_boot_services_t *b;
@@ -87,7 +87,7 @@ Signed-off-by: Michael Chang <mchang@suse.com>
/* Limit the memory access to less than 4GB for 32-bit platforms. */
if (address > GRUB_EFI_MAX_USABLE_ADDRESS)
@@ -171,19 +172,22 @@
@@ -169,19 +170,22 @@
}
b = grub_efi_system_table->boot_services;
@@ -111,10 +111,10 @@ Signed-off-by: Michael Chang <mchang@suse.com>
- status = b->allocate_pages (alloctype, memtype, pages, &address);
+ ret = address;
+ status = b->allocate_pages (alloctype, memtype, pages, &ret);
b->free_pages (0, pages);
grub_efi_free_pages (0, pages);
if (status != GRUB_EFI_SUCCESS)
{
@@ -192,9 +196,9 @@
@@ -190,9 +194,9 @@
}
}
@@ -126,7 +126,7 @@ Signed-off-by: Michael Chang <mchang@suse.com>
}
void *
@@ -719,8 +723,21 @@
@@ -711,8 +715,21 @@
for (desc = memory_map, *base_addr = GRUB_EFI_MAX_USABLE_ADDRESS;
(grub_addr_t) desc < ((grub_addr_t) memory_map + memory_map_size);
desc = NEXT_MEMORY_DESCRIPTOR (desc, desc_size))

View File

@@ -0,0 +1,30 @@
From 2fccb958910afaaf03cbec1a6b98ad197d088ad4 Mon Sep 17 00:00:00 2001
From: Robbie Harwood <rharwood@redhat.com>
Date: Thu, 25 Aug 2022 17:57:55 -0400
Subject: [PATCH 4/9] blscfg: Don't root device in emu builds
Otherwise, we end up looking for kernel/initrd in /boot/boot which
doesn't work at all. Non-emu builds need to be looking in
($root)/boot/, which is what this is for.
Signed-off-by: Robbie Harwood <rharwood@redhat.com>
---
grub-core/commands/blscfg.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/grub-core/commands/blscfg.c b/grub-core/commands/blscfg.c
index 7132555df..150ca96f4 100644
--- a/grub-core/commands/blscfg.c
+++ b/grub-core/commands/blscfg.c
@@ -41,7 +41,7 @@ GRUB_MOD_LICENSE ("GPLv3+");
#define GRUB_BLS_CONFIG_PATH "/loader/entries/"
#ifdef GRUB_MACHINE_EMU
-#define GRUB_BOOT_DEVICE "/boot"
+#define GRUB_BOOT_DEVICE ""
#else
#define GRUB_BOOT_DEVICE "($root)"
#endif
--
2.44.0

View File

@@ -0,0 +1,70 @@
From 13ae8a054a4a0b871ce3fd8ddaaff7a4f2ba2478 Mon Sep 17 00:00:00 2001
From: Maxim Suhanov <dfirblog@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 <dfirblog@gmail.com>
Reviewed-by: Daniel Kiper <daniel.kiper@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

View File

@@ -0,0 +1,356 @@
From 7ce7b7889ce73174a0d8091978254ecf2d2e205f Mon Sep 17 00:00:00 2001
From: Hernan Gatta <hegatta@linux.microsoft.com>
Date: Tue, 1 Feb 2022 05:02:56 -0800
Subject: [PATCH 4/5] cryptodisk: Support key protectors
Add a new parameter to cryptomount to support the key protectors framework: -P.
The parameter is used to automatically retrieve a key from specified key
protectors. The parameter may be repeated to specify any number of key
protectors. These are tried in order until one provides a usable key for any
given disk.
Signed-off-by: Hernan Gatta <hegatta@linux.microsoft.com>
Signed-off-by: Michael Chang <mchang@suse.com>
Signed-off-by: Gary Lin <glin@suse.com>
Reviewed-by: Glenn Washburn <development@efficientek.com>
Reviewed-by: Stefan Berger <stefanb@linux.ibm.com>
---
Makefile.util.def | 1 +
grub-core/disk/cryptodisk.c | 172 +++++++++++++++++++++++++++++-------
include/grub/cryptodisk.h | 16 ++++
3 files changed, 158 insertions(+), 31 deletions(-)
diff --git a/Makefile.util.def b/Makefile.util.def
index 3b9435307..252d70af2 100644
--- a/Makefile.util.def
+++ b/Makefile.util.def
@@ -40,6 +40,7 @@ library = {
common = grub-core/disk/luks.c;
common = grub-core/disk/luks2.c;
common = grub-core/disk/geli.c;
+ common = grub-core/disk/key_protector.c;
common = grub-core/disk/cryptodisk.c;
common = grub-core/disk/AFSplitter.c;
common = grub-core/lib/pbkdf2.c;
diff --git a/grub-core/disk/cryptodisk.c b/grub-core/disk/cryptodisk.c
index 2246af51b..b7648ffb7 100644
--- a/grub-core/disk/cryptodisk.c
+++ b/grub-core/disk/cryptodisk.c
@@ -26,6 +26,7 @@
#include <grub/file.h>
#include <grub/procfs.h>
#include <grub/partition.h>
+#include <grub/key_protector.h>
#ifdef GRUB_UTIL
#include <grub/emu/hostdisk.h>
@@ -44,7 +45,8 @@ enum
OPTION_KEYFILE,
OPTION_KEYFILE_OFFSET,
OPTION_KEYFILE_SIZE,
- OPTION_HEADER
+ OPTION_HEADER,
+ OPTION_PROTECTOR
};
static const struct grub_arg_option options[] =
@@ -58,6 +60,8 @@ static const struct grub_arg_option options[] =
{"keyfile-offset", 'O', 0, N_("Key file offset (bytes)"), 0, ARG_TYPE_INT},
{"keyfile-size", 'S', 0, N_("Key file data size (bytes)"), 0, ARG_TYPE_INT},
{"header", 'H', 0, N_("Read header from file"), 0, ARG_TYPE_STRING},
+ {"protector", 'P', GRUB_ARG_OPTION_REPEATABLE,
+ N_("Unlock volume(s) using key protector(s)."), 0, ARG_TYPE_STRING},
{0, 0, 0, 0, 0, 0}
};
@@ -1061,6 +1065,7 @@ grub_cryptodisk_scan_device_real (const char *name,
grub_err_t ret = GRUB_ERR_NONE;
grub_cryptodisk_t dev;
grub_cryptodisk_dev_t cr;
+ int i;
struct cryptodisk_read_hook_ctx read_hook_data = {0};
int askpass = 0;
char *part = NULL;
@@ -1113,41 +1118,112 @@ grub_cryptodisk_scan_device_real (const char *name,
goto error_no_close;
if (!dev)
continue;
+ break;
+ }
- if (!cargs->key_len)
- {
- /* Get the passphrase from the user, if no key data. */
- askpass = 1;
- part = grub_partition_get_name (source->partition);
- grub_printf_ (N_("Enter passphrase for %s%s%s (%s): "), source->name,
- source->partition != NULL ? "," : "",
- part != NULL ? part : N_("UNKNOWN"),
- dev->uuid);
- grub_free (part);
-
- cargs->key_data = grub_malloc (GRUB_CRYPTODISK_MAX_PASSPHRASE);
- if (cargs->key_data == NULL)
- goto error_no_close;
-
- if (!grub_password_get ((char *) cargs->key_data, GRUB_CRYPTODISK_MAX_PASSPHRASE))
- {
- grub_error (GRUB_ERR_BAD_ARGUMENT, "passphrase not supplied");
- goto error;
- }
- cargs->key_len = grub_strlen ((char *) cargs->key_data);
- }
+ if (dev == NULL)
+ {
+ grub_error (GRUB_ERR_BAD_MODULE,
+ "no cryptodisk module can handle this device");
+ goto error_no_close;
+ }
- ret = cr->recover_key (source, dev, cargs);
- if (ret != GRUB_ERR_NONE)
- goto error;
+ if (cargs->protectors)
+ {
+ for (i = 0; cargs->protectors[i]; i++)
+ {
+ if (cargs->key_cache[i].invalid)
+ continue;
+
+ if (cargs->key_cache[i].key == NULL)
+ {
+ ret = grub_key_protector_recover_key (cargs->protectors[i],
+ &cargs->key_cache[i].key,
+ &cargs->key_cache[i].key_len);
+ if (ret != GRUB_ERR_NONE)
+ {
+ if (grub_errno)
+ {
+ grub_print_error ();
+ grub_errno = GRUB_ERR_NONE;
+ }
+
+ grub_dprintf ("cryptodisk",
+ "failed to recover a key from key protector "
+ "%s, will not try it again for any other "
+ "disks, if any, during this invocation of "
+ "cryptomount\n",
+ cargs->protectors[i]);
+
+ cargs->key_cache[i].invalid = 1;
+ continue;
+ }
+ }
+
+ cargs->key_data = cargs->key_cache[i].key;
+ cargs->key_len = cargs->key_cache[i].key_len;
+
+ ret = cr->recover_key (source, dev, cargs);
+ if (ret != GRUB_ERR_NONE)
+ {
+ part = grub_partition_get_name (source->partition);
+ grub_dprintf ("cryptodisk",
+ "recovered a key from key protector %s but it "
+ "failed to unlock %s%s%s (%s)\n",
+ cargs->protectors[i], source->name,
+ source->partition != NULL ? "," : "",
+ part != NULL ? part : N_("UNKNOWN"), dev->uuid);
+ grub_free (part);
+ continue;
+ }
+ else
+ {
+ ret = grub_cryptodisk_insert (dev, name, source);
+ if (ret != GRUB_ERR_NONE)
+ goto error;
+ goto cleanup;
+ }
+ }
- ret = grub_cryptodisk_insert (dev, name, source);
- if (ret != GRUB_ERR_NONE)
+ part = grub_partition_get_name (source->partition);
+ grub_error (GRUB_ERR_ACCESS_DENIED,
+ N_("no key protector provided a usable key for %s%s%s (%s)"),
+ source->name, source->partition != NULL ? "," : "",
+ part != NULL ? part : N_("UNKNOWN"), dev->uuid);
+ grub_free (part);
goto error;
+ }
+
+ if (!cargs->key_len)
+ {
+ /* Get the passphrase from the user, if no key data. */
+ askpass = 1;
+ part = grub_partition_get_name (source->partition);
+ grub_printf_ (N_("Enter passphrase for %s%s%s (%s): "), source->name,
+ source->partition != NULL ? "," : "",
+ part != NULL ? part : N_("UNKNOWN"), dev->uuid);
+ grub_free (part);
+
+ cargs->key_data = grub_malloc (GRUB_CRYPTODISK_MAX_PASSPHRASE);
+ if (cargs->key_data == NULL)
+ goto error;
+
+ if (!grub_password_get ((char *) cargs->key_data, GRUB_CRYPTODISK_MAX_PASSPHRASE))
+ {
+ grub_error (GRUB_ERR_BAD_ARGUMENT, "passphrase not supplied");
+ goto error;
+ }
+ cargs->key_len = grub_strlen ((char *) cargs->key_data);
+ }
+
+ ret = cr->recover_key (source, dev, cargs);
+ if (ret != GRUB_ERR_NONE)
+ goto error;
+
+ ret = grub_cryptodisk_insert (dev, name, source);
+ if (ret != GRUB_ERR_NONE)
+ goto error;
- goto cleanup;
- }
- grub_error (GRUB_ERR_BAD_MODULE, "no cryptodisk module can handle this device");
goto cleanup;
error:
@@ -1259,6 +1335,20 @@ grub_cryptodisk_scan_device (const char *name,
return ret;
}
+static void
+grub_cryptodisk_clear_key_cache (struct grub_cryptomount_args *cargs)
+{
+ int i;
+
+ if (cargs->key_cache == NULL || cargs->protectors == NULL)
+ return;
+
+ for (i = 0; cargs->protectors[i]; i++)
+ grub_free (cargs->key_cache[i].key);
+
+ grub_free (cargs->key_cache);
+}
+
static grub_err_t
grub_cmd_cryptomount (grub_extcmd_context_t ctxt, int argc, char **args)
{
@@ -1271,6 +1361,10 @@ grub_cmd_cryptomount (grub_extcmd_context_t ctxt, int argc, char **args)
if (grub_cryptodisk_list == NULL)
return grub_error (GRUB_ERR_BAD_MODULE, "no cryptodisk modules loaded");
+ if (state[OPTION_PASSWORD].set && state[OPTION_PROTECTOR].set) /* password and key protector */
+ return grub_error (GRUB_ERR_BAD_ARGUMENT,
+ "a password and a key protector cannot both be set");
+
if (state[OPTION_PASSWORD].set) /* password */
{
cargs.key_data = (grub_uint8_t *) state[OPTION_PASSWORD].arg;
@@ -1363,6 +1457,15 @@ grub_cmd_cryptomount (grub_extcmd_context_t ctxt, int argc, char **args)
return grub_errno;
}
+ if (state[OPTION_PROTECTOR].set) /* key protector(s) */
+ {
+ cargs.key_cache = grub_zalloc (state[OPTION_PROTECTOR].set * sizeof (*cargs.key_cache));
+ if (cargs.key_cache == NULL)
+ return grub_error (GRUB_ERR_OUT_OF_MEMORY,
+ "no memory for key protector key cache");
+ cargs.protectors = state[OPTION_PROTECTOR].args;
+ }
+
if (state[OPTION_UUID].set) /* uuid */
{
int found_uuid;
@@ -1371,6 +1474,7 @@ grub_cmd_cryptomount (grub_extcmd_context_t ctxt, int argc, char **args)
dev = grub_cryptodisk_get_by_uuid (args[0]);
if (dev)
{
+ grub_cryptodisk_clear_key_cache (&cargs);
grub_dprintf ("cryptodisk",
"already mounted as crypto%lu\n", dev->id);
return GRUB_ERR_NONE;
@@ -1379,6 +1483,7 @@ grub_cmd_cryptomount (grub_extcmd_context_t ctxt, int argc, char **args)
cargs.check_boot = state[OPTION_BOOT].set;
cargs.search_uuid = args[0];
found_uuid = grub_device_iterate (&grub_cryptodisk_scan_device, &cargs);
+ grub_cryptodisk_clear_key_cache (&cargs);
if (found_uuid)
return GRUB_ERR_NONE;
@@ -1398,6 +1503,7 @@ grub_cmd_cryptomount (grub_extcmd_context_t ctxt, int argc, char **args)
{
cargs.check_boot = state[OPTION_BOOT].set;
grub_device_iterate (&grub_cryptodisk_scan_device, &cargs);
+ grub_cryptodisk_clear_key_cache (&cargs);
return GRUB_ERR_NONE;
}
else
@@ -1421,6 +1527,7 @@ grub_cmd_cryptomount (grub_extcmd_context_t ctxt, int argc, char **args)
disk = grub_disk_open (diskname);
if (!disk)
{
+ grub_cryptodisk_clear_key_cache (&cargs);
if (disklast)
*disklast = ')';
return grub_errno;
@@ -1431,12 +1538,14 @@ grub_cmd_cryptomount (grub_extcmd_context_t ctxt, int argc, char **args)
{
grub_dprintf ("cryptodisk", "already mounted as crypto%lu\n", dev->id);
grub_disk_close (disk);
+ grub_cryptodisk_clear_key_cache (&cargs);
if (disklast)
*disklast = ')';
return GRUB_ERR_NONE;
}
dev = grub_cryptodisk_scan_device_real (diskname, disk, &cargs);
+ grub_cryptodisk_clear_key_cache (&cargs);
grub_disk_close (disk);
if (disklast)
@@ -1590,6 +1699,7 @@ GRUB_MOD_INIT (cryptodisk)
cmd = grub_register_extcmd ("cryptomount", grub_cmd_cryptomount, 0,
N_("[ [-p password] | [-k keyfile"
" [-O keyoffset] [-S keysize] ] ] [-H file]"
+ " [-P protector [-P protector ...]]"
" <SOURCE|-u UUID|-a|-b>"),
N_("Mount a crypto device."), options);
grub_procfs_register ("luks_script", &luks_script);
diff --git a/include/grub/cryptodisk.h b/include/grub/cryptodisk.h
index d94df68b6..0b41e249e 100644
--- a/include/grub/cryptodisk.h
+++ b/include/grub/cryptodisk.h
@@ -70,6 +70,18 @@ typedef gcry_err_code_t
(*grub_cryptodisk_rekey_func_t) (struct grub_cryptodisk *dev,
grub_uint64_t zoneno);
+struct grub_cryptomount_cached_key
+{
+ grub_uint8_t *key;
+ grub_size_t key_len;
+
+ /*
+ * The key protector associated with this cache entry failed, so avoid it
+ * even if the cached entry (an instance of this structure) is empty.
+ */
+ int invalid;
+};
+
struct grub_cryptomount_args
{
/* scan: Flag to indicate that only bootable volumes should be decrypted */
@@ -81,6 +93,10 @@ struct grub_cryptomount_args
/* recover_key: Length of key_data */
grub_size_t key_len;
grub_file_t hdr_file;
+ /* recover_key: Names of the key protectors to use (NULL-terminated) */
+ char **protectors;
+ /* recover_key: Key cache to avoid invoking the same key protector twice */
+ struct grub_cryptomount_cached_key *key_cache;
};
typedef struct grub_cryptomount_args *grub_cryptomount_args_t;
--
2.35.3

View File

@@ -0,0 +1,91 @@
From 91a99dffbe78b91a0c18b32ebecf755ba9d74032 Mon Sep 17 00:00:00 2001
From: Gary Lin <glin@suse.com>
Date: Thu, 10 Aug 2023 10:19:29 +0800
Subject: [PATCH 4/4] diskfilter: look up cryptodisk devices first
When using disk auto-unlocking with TPM 2.0, the typical grub.cfg may
look like this:
tpm2_key_protector_init --tpm2key=(hd0,gpt1)/boot/grub2/sealed.tpm
cryptomount -u <PART-UUID> -P tpm2
search --fs-uuid --set=root <FS-UUID>
Since the disk search order is based on the order of module loading, the
attacker could insert a malicious disk with the same FS-UUID root to
trick grub2 to boot into the malicious root and further dump memory to
steal the unsealed key.
Do defend against such an attack, we can specify the hint provided by
'grub-probe' to search the encrypted partition first:
search --fs-uuid --set=root --hint='cryptouuid/<PART-UUID>' <FS-UUID>
However, for LVM on an encrypted partition, the search hint provided by
'grub-probe' is:
--hint='lvmid/<VG-UUID>/<LV-UUID>'
It doesn't guarantee to look up the logical volume from the encrypted
partition, so the attacker may have the chance to fool grub2 to boot
into the malicious disk.
To minimize the attack surface, this commit tweaks the disk device search
in diskfilter to look up cryptodisk devices first and then others, so
that the auto-unlocked disk will be found first, not the attacker's disk.
Cc: Fabian Vogt <fvogt@suse.com>
Signed-off-by: Gary Lin <glin@suse.com>
Reviewed-by: Stefan Berger <stefanb@linux.ibm.com>
---
grub-core/disk/diskfilter.c | 35 ++++++++++++++++++++++++++---------
1 file changed, 26 insertions(+), 9 deletions(-)
diff --git a/grub-core/disk/diskfilter.c b/grub-core/disk/diskfilter.c
index 41e177549..c45bef1ca 100644
--- a/grub-core/disk/diskfilter.c
+++ b/grub-core/disk/diskfilter.c
@@ -322,15 +322,32 @@ scan_devices (const char *arname)
int need_rescan;
for (pull = 0; pull < GRUB_DISK_PULL_MAX; pull++)
- for (p = grub_disk_dev_list; p; p = p->next)
- if (p->id != GRUB_DISK_DEVICE_DISKFILTER_ID
- && p->disk_iterate)
- {
- if ((p->disk_iterate) (scan_disk_hook, NULL, pull))
- return;
- if (arname && is_lv_readable (find_lv (arname), 1))
- return;
- }
+ {
+ /* look up the crytodisk devices first */
+ for (p = grub_disk_dev_list; p; p = p->next)
+ if (p->id == GRUB_DISK_DEVICE_CRYPTODISK_ID
+ && p->disk_iterate)
+ {
+ if ((p->disk_iterate) (scan_disk_hook, NULL, pull))
+ return;
+ if (arname && is_lv_readable (find_lv (arname), 1))
+ return;
+ break;
+ }
+
+ /* check the devices other than crytodisk */
+ for (p = grub_disk_dev_list; p; p = p->next)
+ if (p->id == GRUB_DISK_DEVICE_CRYPTODISK_ID)
+ continue;
+ else if (p->id != GRUB_DISK_DEVICE_DISKFILTER_ID
+ && p->disk_iterate)
+ {
+ if ((p->disk_iterate) (scan_disk_hook, NULL, pull))
+ return;
+ if (arname && is_lv_readable (find_lv (arname), 1))
+ return;
+ }
+ }
scan_depth = 0;
need_rescan = 1;
--
2.35.3

View File

@@ -1,97 +0,0 @@
From e2a6f238920ab547d216ce96283bca6faf36378b Mon Sep 17 00:00:00 2001
From: Michael Chang <mchang@suse.com>
Date: Wed, 30 Apr 2025 21:16:50 +0800
Subject: [PATCH 4/4] efi/chainloader: fix missing file_path in loaded_image
The file_path field in the loaded_image protocol may be unset for
chainloaded target images. When this occurs, populate the file_path to
ensure the target image can use the loaded_image protocol for location
dependent operations, such as reading configuration files from its
directory. Without this, the chainloaded image may fail to start due to
an inability to reconfigure itself properly.
Signed-off-by: Michael Chang <mchang@suse.com>
---
grub-core/loader/efi/chainloader.c | 52 +++++++++++++++++-------------
1 file changed, 29 insertions(+), 23 deletions(-)
diff --git a/grub-core/loader/efi/chainloader.c b/grub-core/loader/efi/chainloader.c
index 7e2847217..9b70e1e61 100644
--- a/grub-core/loader/efi/chainloader.c
+++ b/grub-core/loader/efi/chainloader.c
@@ -222,6 +222,29 @@ make_file_path (grub_efi_device_path_t *dp, const char *filename)
return file_path;
}
+static grub_efi_device_path_t *
+grub_efi_get_media_file_path (grub_efi_device_path_t *dp)
+{
+ while (1)
+ {
+ grub_efi_uint8_t type;
+ grub_efi_uint8_t subtype;
+
+ if (GRUB_EFI_END_ENTIRE_DEVICE_PATH (dp))
+ break;
+
+ type = GRUB_EFI_DEVICE_PATH_TYPE (dp);
+ subtype = GRUB_EFI_DEVICE_PATH_SUBTYPE (dp);
+
+ if (type == GRUB_EFI_MEDIA_DEVICE_PATH_TYPE && subtype == GRUB_EFI_FILE_PATH_DEVICE_PATH_SUBTYPE)
+ return dp;
+
+ dp = GRUB_EFI_NEXT_DEVICE_PATH (dp);
+ }
+
+ return NULL;
+}
+
#ifdef SUPPORT_SECURE_BOOT
#define SHIM_LOCK_GUID \
{ 0x605dab50, 0xe046, 0x4300, {0xab, 0xb6, 0x3d, 0xd8, 0x10, 0xdd, 0x8b, 0x23} }
@@ -461,29 +484,6 @@ relocate_coff (pe_coff_loader_image_context_t *context, void *data)
return GRUB_EFI_SUCCESS;
}
-static grub_efi_device_path_t *
-grub_efi_get_media_file_path (grub_efi_device_path_t *dp)
-{
- while (1)
- {
- grub_efi_uint8_t type;
- grub_efi_uint8_t subtype;
-
- if (GRUB_EFI_END_ENTIRE_DEVICE_PATH (dp))
- break;
-
- type = GRUB_EFI_DEVICE_PATH_TYPE (dp);
- subtype = GRUB_EFI_DEVICE_PATH_SUBTYPE (dp);
-
- if (type == GRUB_EFI_MEDIA_DEVICE_PATH_TYPE && subtype == GRUB_EFI_FILE_PATH_DEVICE_PATH_SUBTYPE)
- return dp;
-
- dp = GRUB_EFI_NEXT_DEVICE_PATH (dp);
- }
-
- return NULL;
-}
-
static grub_efi_boolean_t
handle_image (struct grub_secureboot_chainloader_context *load_context)
{
@@ -881,6 +881,12 @@ grub_cmd_chainloader (grub_command_t cmd __attribute__ ((unused)),
}
loaded_image->device_handle = dev_handle;
+ if (! loaded_image->file_path)
+ {
+ grub_dprintf ("chain", "bailout file_path\n");
+ loaded_image->file_path = grub_efi_get_media_file_path (file_path);
+ }
+
/* Build load options with arguments from chainloader command line. */
if (cmdline)
{
--
2.50.1

View File

@@ -0,0 +1,92 @@
From 8f99c43384b9122eedeab1411ab5076ca5878ef9 Mon Sep 17 00:00:00 2001
From: Lidong Chen <lidong.chen@oracle.com>
Date: Fri, 22 Nov 2024 06:27:58 +0000
Subject: [PATCH 04/20] fs/tar: Integer overflow leads to heap OOB write
Both namesize and linksize are derived from hd.size, a 12-digit octal
number parsed by read_number(). Later direct arithmetic calculation like
"namesize + 1" and "linksize + 1" may exceed the maximum value of
grub_size_t leading to heap OOB write. This patch fixes the issue by
using grub_add() and checking for an overflow.
Fixes: CVE-2024-45780
Reported-by: Nils Langius <nils@langius.de>
Signed-off-by: Lidong Chen <lidong.chen@oracle.com>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
Reviewed-by: Alec Brown <alec.r.brown@oracle.com>
---
grub-core/fs/tar.c | 23 ++++++++++++++++++-----
1 file changed, 18 insertions(+), 5 deletions(-)
diff --git a/grub-core/fs/tar.c b/grub-core/fs/tar.c
index c551ed6b52..a9e39b0eb6 100644
--- a/grub-core/fs/tar.c
+++ b/grub-core/fs/tar.c
@@ -25,6 +25,7 @@
#include <grub/mm.h>
#include <grub/dl.h>
#include <grub/i18n.h>
+#include <grub/safemath.h>
GRUB_MOD_LICENSE ("GPLv3+");
@@ -76,6 +77,7 @@ grub_cpio_find_file (struct grub_archelp_data *data, char **name,
{
struct head hd;
int reread = 0, have_longname = 0, have_longlink = 0;
+ grub_size_t sz;
data->hofs = data->next_hofs;
@@ -97,7 +99,11 @@ grub_cpio_find_file (struct grub_archelp_data *data, char **name,
{
grub_err_t err;
grub_size_t namesize = read_number (hd.size, sizeof (hd.size));
- *name = grub_malloc (namesize + 1);
+
+ if (grub_add (namesize, 1, &sz))
+ return grub_error (GRUB_ERR_BAD_FS, N_("name size overflow"));
+
+ *name = grub_malloc (sz);
if (*name == NULL)
return grub_errno;
err = grub_disk_read (data->disk, 0,
@@ -117,15 +123,19 @@ grub_cpio_find_file (struct grub_archelp_data *data, char **name,
{
grub_err_t err;
grub_size_t linksize = read_number (hd.size, sizeof (hd.size));
- if (data->linkname_alloc < linksize + 1)
+
+ if (grub_add (linksize, 1, &sz))
+ return grub_error (GRUB_ERR_BAD_FS, N_("link size overflow"));
+
+ if (data->linkname_alloc < sz)
{
char *n;
- n = grub_calloc (2, linksize + 1);
+ n = grub_calloc (2, sz);
if (!n)
return grub_errno;
grub_free (data->linkname);
data->linkname = n;
- data->linkname_alloc = 2 * (linksize + 1);
+ data->linkname_alloc = 2 * (sz);
}
err = grub_disk_read (data->disk, 0,
@@ -148,7 +158,10 @@ grub_cpio_find_file (struct grub_archelp_data *data, char **name,
while (extra_size < sizeof (hd.prefix)
&& hd.prefix[extra_size])
extra_size++;
- *name = grub_malloc (sizeof (hd.name) + extra_size + 2);
+
+ if (grub_add (sizeof (hd.name) + 2, extra_size, &sz))
+ return grub_error (GRUB_ERR_BAD_FS, N_("long name size overflow"));
+ *name = grub_malloc (sz);
if (*name == NULL)
return grub_errno;
if (hd.prefix[0])
--
2.48.1

View File

@@ -0,0 +1,218 @@
From 8c0b5f200352603e53b799fca7b63f845a978f19 Mon Sep 17 00:00:00 2001
From: Stefan Berger <stefanb@linux.ibm.com>
Date: Tue, 26 Nov 2024 15:39:43 -0500
Subject: [PATCH 4/7] ieee1275/ibmvpm: Move TPM initialization functions to own
file
Move common initialization functions from the ibmvtpm driver module into
tcg2.c that will be moved into the new TCG2 driver in a subsequent patch.
Make the functions available to the ibmvtpm driver as public functions
and variables.
Signed-off-by: Stefan Berger <stefanb@linux.ibm.com>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
---
grub-core/Makefile.core.def | 1 +
grub-core/commands/ieee1275/ibmvtpm.c | 44 ++-----------------
grub-core/lib/ieee1275/tcg2.c | 61 +++++++++++++++++++++++++++
include/grub/ieee1275/tpm.h | 31 ++++++++++++++
4 files changed, 97 insertions(+), 40 deletions(-)
create mode 100644 grub-core/lib/ieee1275/tcg2.c
create mode 100644 include/grub/ieee1275/tpm.h
diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def
index 40427165e..c5fd796d4 100644
--- a/grub-core/Makefile.core.def
+++ b/grub-core/Makefile.core.def
@@ -1155,6 +1155,7 @@ module = {
name = tpm;
common = commands/tpm.c;
ieee1275 = commands/ieee1275/ibmvtpm.c;
+ ieee1275 = lib/ieee1275/tcg2.c;
enable = powerpc_ieee1275;
};
diff --git a/grub-core/commands/ieee1275/ibmvtpm.c b/grub-core/commands/ieee1275/ibmvtpm.c
index dd30c7432..284673217 100644
--- a/grub-core/commands/ieee1275/ibmvtpm.c
+++ b/grub-core/commands/ieee1275/ibmvtpm.c
@@ -23,46 +23,10 @@
#include <grub/types.h>
#include <grub/tpm.h>
#include <grub/ieee1275/ieee1275.h>
+#include <grub/ieee1275/tpm.h>
#include <grub/mm.h>
#include <grub/misc.h>
-static grub_ieee1275_ihandle_t tpm_ihandle;
-static grub_uint8_t tpm_version;
-
-static void
-tpm_get_tpm_version (void)
-{
- grub_ieee1275_phandle_t vtpm;
- char buffer[20];
-
- if (!grub_ieee1275_finddevice ("/vdevice/vtpm", &vtpm) &&
- !grub_ieee1275_get_property (vtpm, "compatible", buffer,
- sizeof (buffer), NULL) &&
- !grub_strcmp (buffer, "IBM,vtpm20"))
- tpm_version = 2;
-}
-
-static grub_err_t
-tpm_init (void)
-{
- static int init_success = 0;
-
- if (!init_success)
- {
- if (grub_ieee1275_open ("/vdevice/vtpm", &tpm_ihandle) < 0)
- {
- tpm_ihandle = GRUB_IEEE1275_IHANDLE_INVALID;
- return GRUB_ERR_UNKNOWN_DEVICE;
- }
-
- init_success = 1;
-
- tpm_get_tpm_version ();
- }
-
- return GRUB_ERR_NONE;
-}
-
static int
ibmvtpm_2hash_ext_log (grub_uint8_t pcrindex,
grub_uint32_t eventtype,
@@ -88,7 +52,7 @@ ibmvtpm_2hash_ext_log (grub_uint8_t pcrindex,
INIT_IEEE1275_COMMON (&args.common, "call-method", 8, 2);
args.method = (grub_ieee1275_cell_t) "2hash-ext-log";
- args.ihandle = tpm_ihandle;
+ args.ihandle = grub_ieee1275_tpm_ihandle;
args.pcrindex = pcrindex;
args.eventtype = eventtype;
args.description = (grub_ieee1275_cell_t) description;
@@ -136,7 +100,7 @@ grub_tpm_measure (unsigned char *buf, grub_size_t size, grub_uint8_t pcr,
grub_dprintf ("tpm", "log_event, pcr = %d, size = 0x%" PRIxGRUB_SIZE ", %s\n",
pcr, size, description);
- if (tpm_version == 2)
+ if (grub_ieee1275_tpm_version == 2)
return tpm2_log_event (buf, size, pcr, description);
return GRUB_ERR_NONE;
@@ -149,5 +113,5 @@ grub_tpm_present (void)
* Call tpm_init() "late" rather than from GRUB_MOD_INIT() so that device nodes
* can be found.
*/
- return tpm_init() == GRUB_ERR_NONE;
+ return grub_ieee1275_tpm_init() == GRUB_ERR_NONE;
}
diff --git a/grub-core/lib/ieee1275/tcg2.c b/grub-core/lib/ieee1275/tcg2.c
new file mode 100644
index 000000000..1819d1447
--- /dev/null
+++ b/grub-core/lib/ieee1275/tcg2.c
@@ -0,0 +1,61 @@
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2024 IBM Corporation
+ * Copyright (C) 2024 Free Software Foundation, Inc.
+ *
+ * GRUB is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GRUB is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GRUB. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <grub/types.h>
+#include <grub/tpm.h>
+#include <grub/ieee1275/tpm.h>
+#include <grub/mm.h>
+#include <grub/misc.h>
+
+grub_ieee1275_ihandle_t grub_ieee1275_tpm_ihandle;
+grub_uint8_t grub_ieee1275_tpm_version;
+
+static void
+tpm_get_tpm_version (void)
+{
+ grub_ieee1275_phandle_t vtpm;
+ char buffer[20];
+
+ if (!grub_ieee1275_finddevice ("/vdevice/vtpm", &vtpm) &&
+ !grub_ieee1275_get_property (vtpm, "compatible", buffer,
+ sizeof (buffer), NULL) &&
+ !grub_strcmp (buffer, "IBM,vtpm20"))
+ grub_ieee1275_tpm_version = 2;
+}
+
+grub_err_t
+grub_ieee1275_tpm_init (void)
+{
+ static int init_success = 0;
+
+ if (!init_success)
+ {
+ if (grub_ieee1275_open ("/vdevice/vtpm", &grub_ieee1275_tpm_ihandle) < 0)
+ {
+ grub_ieee1275_tpm_ihandle = GRUB_IEEE1275_IHANDLE_INVALID;
+ return GRUB_ERR_UNKNOWN_DEVICE;
+ }
+
+ init_success = 1;
+
+ tpm_get_tpm_version ();
+ }
+
+ return GRUB_ERR_NONE;
+}
diff --git a/include/grub/ieee1275/tpm.h b/include/grub/ieee1275/tpm.h
new file mode 100644
index 000000000..9575c1c68
--- /dev/null
+++ b/include/grub/ieee1275/tpm.h
@@ -0,0 +1,31 @@
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2024 Free Software Foundation, Inc.
+ *
+ * GRUB is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GRUB is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GRUB. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef GRUB_IEEE1275_TPM_HEADER
+#define GRUB_IEEE1275_TPM_HEADER 1
+
+#include <grub/err.h>
+#include <grub/types.h>
+#include <grub/ieee1275/ieee1275.h>
+
+extern grub_ieee1275_ihandle_t grub_ieee1275_tpm_ihandle;
+extern grub_uint8_t grub_ieee1275_tpm_version;
+
+extern grub_err_t grub_ieee1275_tpm_init (void);
+
+#endif
--
2.43.0

View File

@@ -0,0 +1,58 @@
From 41330d7fafe122d79d7a9ec28884c0771eb4fdf3 Mon Sep 17 00:00:00 2001
From: Alec Brown <alec.r.brown@oracle.com>
Date: Thu, 21 Aug 2025 21:14:07 +0000
Subject: [PATCH 4/7] normal/main: Unregister commands on module unload
When the normal module is loaded, the normal and normal_exit commands
are registered but aren't unregistered when the module is unloaded. We
need to add calls to grub_unregister_command() when unloading the module
for these commands.
Fixes: CVE-2025-61663
Fixes: CVE-2025-61664
Reported-by: Alec Brown <alec.r.brown@oracle.com>
Signed-off-by: Alec Brown <alec.r.brown@oracle.com>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
---
grub-core/normal/main.c | 12 +++++++-----
1 file changed, 7 insertions(+), 5 deletions(-)
diff --git a/grub-core/normal/main.c b/grub-core/normal/main.c
index 398169299..b77d55eb3 100644
--- a/grub-core/normal/main.c
+++ b/grub-core/normal/main.c
@@ -639,7 +639,7 @@ grub_mini_cmd_clear (struct grub_command *cmd __attribute__ ((unused)),
return 0;
}
-static grub_command_t cmd_clear;
+static grub_command_t cmd_clear, cmd_normal, cmd_normal_exit;
static void (*grub_xputs_saved) (const char *str);
static const char *features[] = {
@@ -682,10 +682,10 @@ GRUB_MOD_INIT(normal)
grub_env_export ("pager");
/* Register a command "normal" for the rescue mode. */
- grub_register_command ("normal", grub_cmd_normal,
- 0, N_("Enter normal mode."));
- grub_register_command ("normal_exit", grub_cmd_normal_exit,
- 0, N_("Exit from normal mode."));
+ cmd_normal = grub_register_command ("normal", grub_cmd_normal,
+ 0, N_("Enter normal mode."));
+ cmd_normal_exit = grub_register_command ("normal_exit", grub_cmd_normal_exit,
+ 0, N_("Exit from normal mode."));
/* Reload terminal colors when these variables are written to. */
grub_register_variable_hook ("color_normal", NULL, grub_env_write_color_normal);
@@ -727,4 +727,6 @@ GRUB_MOD_FINI(normal)
grub_register_variable_hook ("color_highlight", NULL, NULL);
grub_fs_autoload_hook = 0;
grub_unregister_command (cmd_clear);
+ grub_unregister_command (cmd_normal);
+ grub_unregister_command (cmd_normal_exit);
}
--
2.51.1

View File

@@ -0,0 +1,413 @@
From 75c480885ab00fb9bc046fe214df60007116aef2 Mon Sep 17 00:00:00 2001
From: Gary Lin <glin@suse.com>
Date: Mon, 7 Apr 2025 16:29:18 +0800
Subject: [PATCH 4/7] tss2: Add TPM 2.0 NV index commands
The following TPM 2.0 commands are introduced to tss2 to access the
TPM non-volatile memory associated with the NV index handles:
- TPM2_NV_DefineSpace,
- TPM2_NV_UndefineSpace,
- TPM2_NV_ReadPublic,
- TPM2_NV_Read,
- TPM2_NV_Write.
The related marshal/unmarshal functions are also introduced.
Signed-off-by: Gary Lin <glin@suse.com>
Reviewed-by: Stefan Berger <stefanb@linux.ibm.com>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
---
grub-core/lib/tss2/tpm2_cmd.c | 201 ++++++++++++++++++++++++++++++++
grub-core/lib/tss2/tpm2_cmd.h | 32 +++++
grub-core/lib/tss2/tss2_mu.c | 39 +++++++
grub-core/lib/tss2/tss2_mu.h | 12 ++
grub-core/lib/tss2/tss2_types.h | 6 +
5 files changed, 290 insertions(+)
diff --git a/grub-core/lib/tss2/tpm2_cmd.c b/grub-core/lib/tss2/tpm2_cmd.c
index 211d807d5..6d25db1ab 100644
--- a/grub-core/lib/tss2/tpm2_cmd.c
+++ b/grub-core/lib/tss2/tpm2_cmd.c
@@ -1045,3 +1045,204 @@ grub_tpm2_testparms (const TPMT_PUBLIC_PARMS_t *parms,
return TPM_RC_SUCCESS;
}
+
+TPM_RC_t
+grub_tpm2_nv_definespace (const TPMI_RH_PROVISION_t authHandle,
+ const TPMS_AUTH_COMMAND_t *authCommand,
+ const TPM2B_AUTH_t *auth,
+ const TPM2B_NV_PUBLIC_t *publicInfo)
+{
+ TPM_RC_t rc;
+ struct grub_tpm2_buffer in;
+ struct grub_tpm2_buffer out;
+ TPMI_ST_COMMAND_TAG_t tag = authCommand ? TPM_ST_SESSIONS : TPM_ST_NO_SESSIONS;
+ TPM_RC_t responseCode;
+
+ if (publicInfo == NULL)
+ return TPM_RC_VALUE;
+
+ /* Marshal */
+ grub_tpm2_buffer_init (&in);
+ grub_tpm2_buffer_pack_u32 (&in, authHandle);
+ if (authCommand != NULL)
+ grub_Tss2_MU_TPMS_AUTH_COMMAND_Marshal (&in, authCommand);
+ if (auth != NULL)
+ grub_Tss2_MU_TPM2B_Marshal (&in, auth->size, auth->buffer);
+ else
+ grub_tpm2_buffer_pack_u16 (&in, 0);
+ grub_Tss2_MU_TPM2B_NV_PUBLIC_Marshal (&in, publicInfo);
+ if (in.error != 0)
+ return TPM_RC_FAILURE;
+
+ /* Submit */
+ grub_tpm2_buffer_init (&out);
+ rc = tpm2_submit_command (tag, TPM_CC_NV_DefineSpace, &responseCode, &in, &out);
+ if (rc != TPM_RC_SUCCESS)
+ return rc;
+ if (responseCode != TPM_RC_SUCCESS)
+ return responseCode;
+
+ /* Unmarshal */
+ if (out.error != 0)
+ return TPM_RC_FAILURE;
+
+ return TPM_RC_SUCCESS;
+}
+
+TPM_RC_t
+grub_tpm2_nv_undefinespace (const TPMI_RH_PROVISION_t authHandle,
+ const TPMI_RH_NV_INDEX_t nvIndex,
+ const TPMS_AUTH_COMMAND_t *authCommand)
+{
+ TPM_RC_t rc;
+ struct grub_tpm2_buffer in;
+ struct grub_tpm2_buffer out;
+ TPMI_ST_COMMAND_TAG_t tag = authCommand ? TPM_ST_SESSIONS : TPM_ST_NO_SESSIONS;
+ TPM_RC_t responseCode;
+
+ /* Marshal */
+ grub_tpm2_buffer_init (&in);
+ grub_tpm2_buffer_pack_u32 (&in, authHandle);
+ grub_tpm2_buffer_pack_u32 (&in, nvIndex);
+ if (authCommand != NULL)
+ grub_Tss2_MU_TPMS_AUTH_COMMAND_Marshal (&in, authCommand);
+ if (in.error != 0)
+ return TPM_RC_FAILURE;
+
+ /* Submit */
+ grub_tpm2_buffer_init (&out);
+ rc = tpm2_submit_command (tag, TPM_CC_NV_UndefineSpace, &responseCode, &in, &out);
+ if (rc != TPM_RC_SUCCESS)
+ return rc;
+ if (responseCode != TPM_RC_SUCCESS)
+ return responseCode;
+
+ /* Unmarshal */
+ if (out.error != 0)
+ return TPM_RC_FAILURE;
+
+ return TPM_RC_SUCCESS;
+}
+
+TPM_RC_t
+grub_tpm2_nv_readpublic (const TPMI_RH_NV_INDEX_t nvIndex,
+ const TPMS_AUTH_COMMAND_t *authCommand,
+ TPM2B_NV_PUBLIC_t *nvPublic,
+ TPM2B_NAME_t *nvName)
+{
+ TPM_RC_t rc;
+ struct grub_tpm2_buffer in;
+ struct grub_tpm2_buffer out;
+ TPMI_ST_COMMAND_TAG_t tag = authCommand ? TPM_ST_SESSIONS : TPM_ST_NO_SESSIONS;
+ TPM_RC_t responseCode;
+ grub_uint32_t param_size;
+
+ /* Marshal */
+ grub_tpm2_buffer_init (&in);
+ grub_tpm2_buffer_pack_u32 (&in, nvIndex);
+ if (authCommand != NULL)
+ grub_Tss2_MU_TPMS_AUTH_COMMAND_Marshal (&in, authCommand);
+ if (in.error != 0)
+ return TPM_RC_FAILURE;
+
+ /* Submit */
+ grub_tpm2_buffer_init (&out);
+ rc = tpm2_submit_command (tag, TPM_CC_NV_ReadPublic, &responseCode, &in, &out);
+ if (rc != TPM_RC_SUCCESS)
+ return rc;
+ if (responseCode != TPM_RC_SUCCESS)
+ return responseCode;
+
+ /* Unmarshal */
+ if (tag == TPM_ST_SESSIONS)
+ grub_tpm2_buffer_unpack_u32 (&out, &param_size);
+ grub_Tss2_MU_TPM2B_NV_PUBLIC_Unmarshal (&out, nvPublic);
+ grub_Tss2_MU_TPM2B_NAME_Unmarshal (&out, nvName);
+ if (out.error != 0)
+ return TPM_RC_FAILURE;
+
+ return TPM_RC_SUCCESS;
+}
+
+TPM_RC_t
+grub_tpm2_nv_read (const TPMI_RH_NV_AUTH_t authHandle,
+ const TPMI_RH_NV_INDEX_t nvIndex,
+ const TPMS_AUTH_COMMAND_t *authCommand,
+ const grub_uint16_t size,
+ const grub_uint16_t offset,
+ TPM2B_MAX_NV_BUFFER_t *data)
+{
+ TPM_RC_t rc;
+ struct grub_tpm2_buffer in;
+ struct grub_tpm2_buffer out;
+ TPMI_ST_COMMAND_TAG_t tag = authCommand ? TPM_ST_SESSIONS : TPM_ST_NO_SESSIONS;
+ TPM_RC_t responseCode;
+ grub_uint32_t param_size;
+
+ /* Marshal */
+ grub_tpm2_buffer_init (&in);
+ grub_tpm2_buffer_pack_u32 (&in, authHandle);
+ grub_tpm2_buffer_pack_u32 (&in, nvIndex);
+ if (authCommand != NULL)
+ grub_Tss2_MU_TPMS_AUTH_COMMAND_Marshal (&in, authCommand);
+ grub_tpm2_buffer_pack_u16 (&in, size);
+ grub_tpm2_buffer_pack_u16 (&in, offset);
+ if (in.error != 0)
+ return TPM_RC_FAILURE;
+
+ /* Submit */
+ grub_tpm2_buffer_init (&out);
+ rc = tpm2_submit_command (tag, TPM_CC_NV_Read, &responseCode, &in, &out);
+ if (rc != TPM_RC_SUCCESS)
+ return rc;
+ if (responseCode != TPM_RC_SUCCESS)
+ return responseCode;
+
+ /* Unmarshal */
+ if (tag == TPM_ST_SESSIONS)
+ grub_tpm2_buffer_unpack_u32 (&out, &param_size);
+ grub_Tss2_MU_TPM2B_NAX_NV_BUFFER_Unmarshal (&out, data);
+ if (out.error != 0)
+ return TPM_RC_FAILURE;
+
+ return TPM_RC_SUCCESS;
+}
+
+TPM_RC_t
+grub_tpm2_nv_write (const TPMI_RH_NV_AUTH_t authHandle,
+ const TPMI_RH_NV_INDEX_t nvIndex,
+ const TPMS_AUTH_COMMAND_t *authCommand,
+ const TPM2B_MAX_NV_BUFFER_t *data,
+ const grub_uint16_t offset)
+{
+ TPM_RC_t rc;
+ struct grub_tpm2_buffer in;
+ struct grub_tpm2_buffer out;
+ TPMI_ST_COMMAND_TAG_t tag = authCommand ? TPM_ST_SESSIONS : TPM_ST_NO_SESSIONS;
+ TPM_RC_t responseCode;
+
+ /* Marshal */
+ grub_tpm2_buffer_init (&in);
+ grub_tpm2_buffer_pack_u32 (&in, authHandle);
+ grub_tpm2_buffer_pack_u32 (&in, nvIndex);
+ if (authCommand != NULL)
+ grub_Tss2_MU_TPMS_AUTH_COMMAND_Marshal (&in, authCommand);
+ grub_Tss2_MU_TPM2B_Marshal (&in, data->size, data->buffer);
+ grub_tpm2_buffer_pack_u16 (&in, offset);
+ if (in.error != 0)
+ return TPM_RC_FAILURE;
+
+ /* Submit */
+ grub_tpm2_buffer_init (&out);
+ rc = tpm2_submit_command (tag, TPM_CC_NV_Write, &responseCode, &in, &out);
+ if (rc != TPM_RC_SUCCESS)
+ return rc;
+ if (responseCode != TPM_RC_SUCCESS)
+ return responseCode;
+
+ /* Unmarshal */
+ if (out.error != 0)
+ return TPM_RC_FAILURE;
+
+ return TPM_RC_SUCCESS;
+}
diff --git a/grub-core/lib/tss2/tpm2_cmd.h b/grub-core/lib/tss2/tpm2_cmd.h
index d313cba00..90b42efec 100644
--- a/grub-core/lib/tss2/tpm2_cmd.h
+++ b/grub-core/lib/tss2/tpm2_cmd.h
@@ -154,4 +154,36 @@ extern TPM_RC_t
grub_tpm2_testparms (const TPMT_PUBLIC_PARMS_t *parms,
const TPMS_AUTH_COMMAND_t *authCommand);
+extern TPM_RC_t
+grub_tpm2_nv_definespace (const TPMI_RH_PROVISION_t authHandle,
+ const TPMS_AUTH_COMMAND_t *authCommand,
+ const TPM2B_AUTH_t *auth,
+ const TPM2B_NV_PUBLIC_t *publicInfo);
+
+extern TPM_RC_t
+grub_tpm2_nv_undefinespace (const TPMI_RH_PROVISION_t authHandle,
+ const TPMI_RH_NV_INDEX_t nvIndex,
+ const TPMS_AUTH_COMMAND_t *authCommand);
+
+extern TPM_RC_t
+grub_tpm2_nv_readpublic (const TPMI_RH_NV_INDEX_t nvIndex,
+ const TPMS_AUTH_COMMAND_t *authCommand,
+ TPM2B_NV_PUBLIC_t *nvPublic,
+ TPM2B_NAME_t *nvName);
+
+extern TPM_RC_t
+grub_tpm2_nv_read (const TPMI_RH_NV_AUTH_t authHandle,
+ const TPMI_RH_NV_INDEX_t nvIndex,
+ const TPMS_AUTH_COMMAND_t *authCommand,
+ const grub_uint16_t size,
+ const grub_uint16_t offset,
+ TPM2B_MAX_NV_BUFFER_t *data);
+
+extern TPM_RC_t
+grub_tpm2_nv_write (const TPMI_RH_NV_AUTH_t authHandle,
+ const TPMI_RH_NV_INDEX_t nvIndex,
+ const TPMS_AUTH_COMMAND_t *authCommand,
+ const TPM2B_MAX_NV_BUFFER_t *data,
+ const grub_uint16_t offset);
+
#endif /* ! GRUB_TPM2_COMMANDS_HEADER */
diff --git a/grub-core/lib/tss2/tss2_mu.c b/grub-core/lib/tss2/tss2_mu.c
index 86134cc0a..816e5b37f 100644
--- a/grub-core/lib/tss2/tss2_mu.c
+++ b/grub-core/lib/tss2/tss2_mu.c
@@ -17,6 +17,7 @@
* along with GRUB. If not, see <http://www.gnu.org/licenses/>.
*/
+#include <grub/mm.h>
#include <grub/misc.h>
#include <tss2_mu.h>
@@ -572,6 +573,37 @@ grub_Tss2_MU_TPMT_TK_VERIFIED_Marshal (grub_tpm2_buffer_t buffer,
grub_Tss2_MU_TPM2B_Marshal (buffer, p->digest.size, p->digest.buffer);
}
+void
+grub_Tss2_MU_TPMS_NV_PUBLIC_Marshal (grub_tpm2_buffer_t buffer,
+ const TPMS_NV_PUBLIC_t *p)
+{
+ grub_tpm2_buffer_pack_u32 (buffer, p->nvIndex);
+ grub_tpm2_buffer_pack_u16 (buffer, p->nameAlg);
+ grub_tpm2_buffer_pack_u32 (buffer, p->attributes);
+ grub_Tss2_MU_TPM2B_Marshal (buffer, p->authPolicy.size, p->authPolicy.buffer);
+ grub_tpm2_buffer_pack_u16 (buffer, p->dataSize);
+}
+
+void
+grub_Tss2_MU_TPM2B_NV_PUBLIC_Marshal (grub_tpm2_buffer_t buffer,
+ const TPM2B_NV_PUBLIC_t *p)
+{
+ grub_uint32_t start;
+ grub_uint16_t size;
+
+ if (p != NULL)
+ {
+ grub_tpm2_buffer_pack_u16 (buffer, p->size);
+
+ start = buffer->size;
+ grub_Tss2_MU_TPMS_NV_PUBLIC_Marshal (buffer, &p->nvPublic);
+ size = grub_cpu_to_be16 (buffer->size - start);
+ grub_memcpy (&buffer->data[start - sizeof (grub_uint16_t)], &size, sizeof (size));
+ }
+ else
+ grub_tpm2_buffer_pack_u16 (buffer, 0);
+}
+
static void
__Tss2_MU_TPM2B_BUFFER_Unmarshal (grub_tpm2_buffer_t buffer,
TPM2B_t *p, grub_uint16_t bound)
@@ -982,6 +1014,13 @@ grub_Tss2_MU_TPM2B_NV_PUBLIC_Unmarshal (grub_tpm2_buffer_t buffer,
grub_Tss2_MU_TPMS_NV_PUBLIC_Unmarshal (buffer, &p->nvPublic);
}
+void
+grub_Tss2_MU_TPM2B_NAX_NV_BUFFER_Unmarshal (grub_tpm2_buffer_t buffer,
+ TPM2B_MAX_NV_BUFFER_t *p)
+{
+ TPM2B_BUFFER_UNMARSHAL (buffer, TPM2B_MAX_NV_BUFFER_t, p);
+}
+
void
grub_Tss2_MU_TPM2B_NAME_Unmarshal (grub_tpm2_buffer_t buffer,
TPM2B_NAME_t *n)
diff --git a/grub-core/lib/tss2/tss2_mu.h b/grub-core/lib/tss2/tss2_mu.h
index 8f82126e1..6440de57c 100644
--- a/grub-core/lib/tss2/tss2_mu.h
+++ b/grub-core/lib/tss2/tss2_mu.h
@@ -193,6 +193,14 @@ extern void
grub_Tss2_MU_TPMT_TK_VERIFIED_Marshal (grub_tpm2_buffer_t buffer,
const TPMT_TK_VERIFIED_t *p);
+extern void
+grub_Tss2_MU_TPMS_NV_PUBLIC_Marshal (grub_tpm2_buffer_t buffer,
+ const TPMS_NV_PUBLIC_t *p);
+
+extern void
+grub_Tss2_MU_TPM2B_NV_PUBLIC_Marshal (grub_tpm2_buffer_t buffer,
+ const TPM2B_NV_PUBLIC_t *p);
+
extern void
grub_Tss2_MU_TPMS_AUTH_RESPONSE_Unmarshal (grub_tpm2_buffer_t buffer,
TPMS_AUTH_RESPONSE_t *p);
@@ -336,6 +344,10 @@ extern void
grub_Tss2_MU_TPM2B_NV_PUBLIC_Unmarshal (grub_tpm2_buffer_t buffer,
TPM2B_NV_PUBLIC_t *p);
+extern void
+grub_Tss2_MU_TPM2B_NAX_NV_BUFFER_Unmarshal (grub_tpm2_buffer_t buffer,
+ TPM2B_MAX_NV_BUFFER_t *p);
+
extern void
grub_Tss2_MU_TPM2B_NAME_Unmarshal (grub_tpm2_buffer_t buffer,
TPM2B_NAME_t *n);
diff --git a/grub-core/lib/tss2/tss2_types.h b/grub-core/lib/tss2/tss2_types.h
index 5b1a7947d..bddde7191 100644
--- a/grub-core/lib/tss2/tss2_types.h
+++ b/grub-core/lib/tss2/tss2_types.h
@@ -270,6 +270,7 @@ typedef TPM_HANDLE_t TPMI_RH_NV_INDEX_t;
/* TPM_HT_t Constants */
typedef grub_uint8_t TPM_HT_t;
+#define TPM_HT_NV_INDEX ((TPM_HT_t) 0x01)
#define TPM_HT_PERMANENT ((TPM_HT_t) 0x40)
#define TPM_HT_PERSISTENT ((TPM_HT_t) 0x81)
@@ -300,6 +301,7 @@ typedef TPM_HANDLE_t TPM_HC_t;
#define TPM_HR_HANDLE_MASK ((TPM_HC_t) 0x00FFFFFF)
#define TPM_HR_RANGE_MASK ((TPM_HC_t) 0xFF000000)
#define TPM_HR_SHIFT ((TPM_HC_t) 24)
+#define TPM_HR_NV_INDEX ((TPM_HC_t) (TPM_HT_NV_INDEX << TPM_HR_SHIFT))
#define TPM_HR_PERSISTENT ((TPM_HC_t) (TPM_HT_PERSISTENT << TPM_HR_SHIFT))
#define TPM_HR_PERMANENT ((TPM_HC_t) (TPM_HT_PERMANENT << TPM_HR_SHIFT))
#define TPM_PERSISTENT_FIRST ((TPM_HC_t) (TPM_HR_PERSISTENT + 0))
@@ -308,6 +310,7 @@ typedef TPM_HANDLE_t TPM_HC_t;
#define TPM_PERMANENT_LAST ((TPM_HC_t) TPM_RH_LAST)
/* TPM Handle Type Checks */
+#define TPM_HT_IS_NVINDEX(HANDLE) (((HANDLE) >> TPM_HR_SHIFT) == TPM_HT_NV_INDEX)
#define TPM_HT_IS_PERMANENT(HANDLE) (((HANDLE) >> TPM_HR_SHIFT) == TPM_HT_PERMANENT)
#define TPM_HT_IS_PERSISTENT(HANDLE) (((HANDLE) >> TPM_HR_SHIFT) == TPM_HT_PERSISTENT)
@@ -334,8 +337,11 @@ typedef grub_uint32_t TPM_CC_t;
#define TPM_CC_ReadPublic ((TPM_CC_t) 0x00000173)
#define TPM_CC_StartAuthSession ((TPM_CC_t) 0x00000176)
#define TPM_CC_PolicyPCR ((TPM_CC_t) 0x0000017f)
+#define TPM_CC_NV_DefineSpace ((TPM_CC_t) 0x0000012a)
#define TPM_CC_NV_Read ((TPM_CC_t) 0x0000014e)
#define TPM_CC_NV_ReadPublic ((TPM_CC_t) 0x00000169)
+#define TPM_CC_NV_Write ((TPM_CC_t) 0x00000137)
+#define TPM_CC_NV_UndefineSpace ((TPM_CC_t) 0x00000122)
#define TPM_CC_GetCapability ((TPM_CC_t) 0x0000017a)
#define TPM_CC_PCR_Read ((TPM_CC_t) 0x0000017e)
#define TPM_CC_Load ((TPM_CC_t) 0x00000157)
--
2.43.0

View File

@@ -0,0 +1,255 @@
From bd776f35de3afbbe818c0531be9c9754797f2c08 Mon Sep 17 00:00:00 2001
From: Sudhakar Kuppusamy <sudhakar@linux.ibm.com>
Date: Tue, 25 Feb 2025 01:18:35 +0530
Subject: [PATCH 5/9] appendedsig: While verifying the kernel, use trusted and
distrusted lists
To verify the kernel's signature: verify the kernel binary against lists of binary hashes
that are either distrusted or trusted. If it is not list in either trusted or distrusted hashes list
then the trusted keys from the trusted key list are used to verify the signature.
Signed-off-by: Sudhakar Kuppusamy <sudhakar@linux.ibm.com>
Reviewed-by: Stefan Berger <stefanb@linux.ibm.com>
Reviewed-by: Avnish Chouhan <avnish@linux.ibm.com>
---
grub-core/commands/appendedsig/appendedsig.c | 199 +++++++++++++------
1 file changed, 139 insertions(+), 60 deletions(-)
diff --git a/grub-core/commands/appendedsig/appendedsig.c b/grub-core/commands/appendedsig/appendedsig.c
index 3df950c00b..b6daccd3d7 100644
--- a/grub-core/commands/appendedsig/appendedsig.c
+++ b/grub-core/commands/appendedsig/appendedsig.c
@@ -473,6 +473,83 @@ extract_appended_signature (const grub_uint8_t *buf, grub_size_t bufsize,
return GRUB_ERR_NONE;
}
+static grub_err_t
+get_binary_hash (const grub_size_t binary_hash_size, const grub_uint8_t *data,
+ const grub_size_t data_size, grub_uint8_t *hash, grub_size_t *hash_size)
+{
+ grub_uuid_t guid = { 0 };
+
+ /* support SHA256, SHA384 and SHA512 for binary hash */
+ if (binary_hash_size == 32)
+ grub_memcpy (&guid, &GRUB_PKS_CERT_SHA256_GUID, GRUB_UUID_SIZE);
+ else if (binary_hash_size == 48)
+ grub_memcpy (&guid, &GRUB_PKS_CERT_SHA384_GUID, GRUB_UUID_SIZE);
+ else if (binary_hash_size == 64)
+ grub_memcpy (&guid, &GRUB_PKS_CERT_SHA512_GUID, GRUB_UUID_SIZE);
+ else
+ {
+ grub_dprintf ("appendedsig", "unsupported hash type (%" PRIuGRUB_SIZE ") and skipping binary hash\n",
+ binary_hash_size);
+ return GRUB_ERR_UNKNOWN_COMMAND;
+ }
+
+ return get_hash (&guid, data, data_size, hash, hash_size);
+}
+
+/*
+ * Verify binary hash against the list of binary hashes that are distrusted
+ * and trusted.
+ * The following errors can occur:
+ * - GRUB_ERR_BAD_SIGNATURE: indicates that the hash is distrusted.
+ * - GRUB_ERR_NONE: the hash is trusted, since it was found in the trusted hashes list
+ * - GRUB_ERR_EOF: the hash could not be found in the hashes list
+ */
+static grub_err_t
+verify_binary_hash (const grub_uint8_t *data, const grub_size_t data_size)
+{
+ grub_err_t rc = GRUB_ERR_NONE;
+ grub_size_t i = 0, hash_size = 0;
+ grub_uint8_t hash[GRUB_MAX_HASH_SIZE] = { 0 };
+
+ for (i = 0; i < dbx.signature_entries; i++)
+ {
+ rc = get_binary_hash (dbx.signature_size[i], data, data_size, hash, &hash_size);
+ if (rc != GRUB_ERR_NONE)
+ continue;
+
+ if (hash_size == dbx.signature_size[i] &&
+ grub_memcmp (dbx.signatures[i], hash, hash_size) == 0)
+ {
+ grub_dprintf ("appendedsig", "the binary hash (%02x%02x%02x%02x) was listed as distrusted\n",
+ hash[0], hash[1], hash[2], hash[3]);
+ return GRUB_ERR_BAD_SIGNATURE;
+ }
+ }
+
+ for (i = 0; i < db.signature_entries; i++)
+ {
+ rc = get_binary_hash (db.signature_size[i], data, data_size, hash, &hash_size);
+ if (rc != GRUB_ERR_NONE)
+ continue;
+
+ if (hash_size == db.signature_size[i] &&
+ grub_memcmp (db.signatures[i], hash, hash_size) == 0)
+ {
+ grub_dprintf ("appendedsig", "verified with a trusted binary hash (%02x%02x%02x%02x)\n",
+ hash[0], hash[1], hash[2], hash[3]);
+ return GRUB_ERR_NONE;
+ }
+ }
+
+ return GRUB_ERR_EOF;
+}
+
+
+/*
+ * Verify the kernel's integrity, the trusted key will be used from
+ * the trusted key list. If it fails, verify it against the list of binary hashes
+ * that are distrusted and trusted.
+ */
static grub_err_t
grub_verify_appended_signature (const grub_uint8_t *buf, grub_size_t bufsize)
{
@@ -482,12 +559,12 @@ grub_verify_appended_signature (const grub_uint8_t *buf, grub_size_t bufsize)
unsigned char *hash;
gcry_mpi_t hashmpi;
gcry_err_code_t rc;
- struct x509_certificate *pk;
+ struct x509_certificate *cert;
struct grub_appended_signature sig;
struct pkcs7_signerInfo *si;
int i;
- if (!db.key_entries)
+ if (!db.key_entries && !db.signature_entries)
return grub_error (GRUB_ERR_BAD_SIGNATURE, N_("No trusted keys to verify against"));
err = extract_appended_signature (buf, bufsize, &sig);
@@ -495,71 +572,73 @@ grub_verify_appended_signature (const grub_uint8_t *buf, grub_size_t bufsize)
return err;
datasize = bufsize - sig.signature_len;
-
- for (i = 0; i < sig.pkcs7.signerInfo_count; i++)
+ err = verify_binary_hash (buf, datasize);
+ if (err != GRUB_ERR_EOF && err != GRUB_ERR_NONE)
+ {
+ err = grub_error (err, N_("failed to verify binary-hash/signature with any trusted binary-hash/key\n"));
+ return err;
+ }
+ else if (err == GRUB_ERR_EOF)
{
- /* This could be optimised in a couple of ways:
- - we could only compute hashes once per hash type
- - we could track signer information and only verify where IDs match
- For now we do the naive O(trusted keys * pkcs7 signers) approach.
- */
- si = &sig.pkcs7.signerInfos[i];
- context = grub_zalloc (si->hash->contextsize);
- if (!context)
- return grub_errno;
-
- si->hash->init (context);
- si->hash->write (context, buf, datasize);
- si->hash->final (context);
- hash = si->hash->read (context);
-
- grub_dprintf ("appendedsig",
- "data size %" PRIxGRUB_SIZE ", signer %d hash %02x%02x%02x%02x...\n",
- datasize, i, hash[0], hash[1], hash[2], hash[3]);
-
- err = GRUB_ERR_BAD_SIGNATURE;
- for (pk = db.keys; pk; pk = pk->next)
+ /* Binary hash was not found in trusted and distrusted list: check signature now */
+ for (i = 0; i < sig.pkcs7.signerInfo_count; i++)
{
- rc = grub_crypto_rsa_pad (&hashmpi, hash, si->hash, pk->mpis[0]);
- if (rc)
+ /*
+ * This could be optimised in a couple of ways:
+ * - we could only compute hashes once per hash type
+ * - we could track signer information and only verify where IDs match
+ * For now we do the naive O(db.keys * pkcs7 signers) approach.
+ */
+ si = &sig.pkcs7.signerInfos[i];
+ context = grub_zalloc (si->hash->contextsize);
+ if (context == NULL)
+ return grub_errno;
+
+ si->hash->init (context);
+ si->hash->write (context, buf, datasize);
+ si->hash->final (context);
+ hash = si->hash->read (context);
+
+ grub_dprintf ("appendedsig",
+ "data size %" PRIxGRUB_SIZE ", signer %d hash %02x%02x%02x%02x...\n",
+ datasize, i, hash[0], hash[1], hash[2], hash[3]);
+
+ err = GRUB_ERR_BAD_SIGNATURE;
+ for (cert = db.keys; cert; cert = cert->next)
{
- err = grub_error (GRUB_ERR_BAD_SIGNATURE,
- N_("Error padding hash for RSA verification: %d"), rc);
- grub_free (context);
- goto cleanup;
+ rc = grub_crypto_rsa_pad (&hashmpi, hash, si->hash, cert->mpis[0]);
+ if (rc != 0)
+ {
+ err = grub_error (GRUB_ERR_BAD_SIGNATURE,
+ N_("Error padding hash for RSA verification: %d"), rc);
+ grub_free (context);
+ pkcs7_signedData_release (&sig.pkcs7);
+ return err;
+ }
+
+ rc = _gcry_pubkey_spec_rsa.verify (0, hashmpi, &si->sig_mpi, cert->mpis, NULL, NULL);
+ gcry_mpi_release (hashmpi);
+ if (rc == 0)
+ {
+ grub_dprintf ("appendedsig", "verify signer %d with key '%s' succeeded\n",
+ i, cert->subject);
+ err = GRUB_ERR_NONE;
+ break;
+ }
+
+ grub_dprintf ("appendedsig", "verify signer %d with key '%s' failed with %d\n",
+ i, cert->subject, rc);
}
-
- rc = _gcry_pubkey_spec_rsa.verify (0, hashmpi, &si->sig_mpi,
- pk->mpis, NULL, NULL);
- gcry_mpi_release (hashmpi);
-
- if (rc == 0)
- {
- grub_dprintf ("appendedsig",
- "verify signer %d with key '%s' succeeded\n", i,
- pk->subject);
- err = GRUB_ERR_NONE;
- break;
- }
-
- grub_dprintf ("appendedsig",
- "verify signer %d with key '%s' failed with %d\n", i,
- pk->subject, rc);
- }
-
- grub_free (context);
-
- if (err == GRUB_ERR_NONE)
- break;
+ grub_free (context);
+ if (err == GRUB_ERR_NONE)
+ break;
+ }
}
- /* If we didn't verify, provide a neat message */
if (err != GRUB_ERR_NONE)
- err = grub_error (GRUB_ERR_BAD_SIGNATURE,
- N_("Failed to verify signature against a trusted key"));
-
-cleanup:
- pkcs7_signedData_release (&sig.pkcs7);
+ err = grub_error (err, N_("failed to verify signature with any trusted key\n"));
+ else
+ grub_printf ("appendedsig: successfully verified the signature with a trusted key\n");
return err;
}
--
2.48.1

View File

@@ -0,0 +1,121 @@
From 6d33393fd3c538aaead2698777c02d6d6d0221c9 Mon Sep 17 00:00:00 2001
From: Robbie Harwood <rharwood@redhat.com>
Date: Tue, 7 Mar 2023 18:59:40 -0500
Subject: [PATCH 5/9] blscfg: check for mounted /boot in emu
Irritatingly, BLS defines paths relatives to the mountpoint of the
filesystem which contains its snippets, not / or any other fixed
location. So grub2-emu needs to know whether /boot is a separate
filesysem from / and conditionally prepend a path.
Signed-off-by: Robbie Harwood <rharwood@redhat.com>
---
grub-core/commands/blscfg.c | 54 +++++++++++++++++++++++++++++++++----
1 file changed, 49 insertions(+), 5 deletions(-)
diff --git a/grub-core/commands/blscfg.c b/grub-core/commands/blscfg.c
index 150ca96f4..6495891b9 100644
--- a/grub-core/commands/blscfg.c
+++ b/grub-core/commands/blscfg.c
@@ -40,8 +40,9 @@ GRUB_MOD_LICENSE ("GPLv3+");
#include "loadenv.h"
#define GRUB_BLS_CONFIG_PATH "/loader/entries/"
+
#ifdef GRUB_MACHINE_EMU
-#define GRUB_BOOT_DEVICE ""
+#define GRUB_BOOT_DEVICE "/boot"
#else
#define GRUB_BOOT_DEVICE "($root)"
#endif
@@ -54,8 +55,50 @@ struct keyval
static struct bls_entry *entries = NULL;
+/* Cache probing in frob_boot_device(). Used for linux entry also.
+ * Always true in non-emu, meaning to prefix things with GRUB_BOOT_DEVICE. */
+static int separate_boot = -1;
+
#define FOR_BLS_ENTRIES(var) FOR_LIST_ELEMENTS (var, entries)
+/* BLS appears to make paths relative to the filesystem that snippets are
+ * on, not /. Attempt to cope. */
+static char *frob_boot_device(char *tmp)
+{
+#ifdef GRUB_MACHINE_EMU
+ grub_file_t f;
+ char *line = NULL;
+
+ if (separate_boot != -1)
+ goto probed;
+
+ separate_boot = 0;
+
+ f = grub_file_open ("/proc/mounts", GRUB_FILE_TYPE_CONFIG);
+ if (f == NULL)
+ goto probed;
+
+ while ((line = grub_file_getline (f)))
+ {
+ if (grub_strstr (line, " " GRUB_BOOT_DEVICE " "))
+ {
+ separate_boot = 1;
+ grub_free (line);
+ break;
+ }
+
+ grub_free(line);
+ }
+
+ grub_file_close (f);
+ probed:
+ if (!separate_boot)
+ return grub_stpcpy (tmp, " ");
+#endif
+
+ return grub_stpcpy (tmp, " " GRUB_BOOT_DEVICE);
+}
+
static int bls_add_keyval(struct bls_entry *entry, char *key, char *val)
{
char *k, *v;
@@ -842,7 +885,7 @@ static void create_entry (struct bls_entry *entry)
for (i = 0; early_initrds != NULL && early_initrds[i] != NULL; i++)
{
grub_dprintf ("blscfg", "adding early initrd %s\n", early_initrds[i]);
- tmp = grub_stpcpy (tmp, " " GRUB_BOOT_DEVICE);
+ tmp = frob_boot_device (tmp);
tmp = grub_stpcpy (tmp, initrd_prefix);
tmp = grub_stpcpy (tmp, early_initrds[i]);
grub_free(early_initrds[i]);
@@ -851,7 +894,7 @@ static void create_entry (struct bls_entry *entry)
for (i = 0; initrds != NULL && initrds[i] != NULL; i++)
{
grub_dprintf ("blscfg", "adding initrd %s\n", initrds[i]);
- tmp = grub_stpcpy (tmp, " " GRUB_BOOT_DEVICE);
+ tmp = frob_boot_device (tmp);
tmp = grub_stpcpy (tmp, initrds[i]);
}
tmp = grub_stpcpy (tmp, "\n");
@@ -888,7 +931,7 @@ static void create_entry (struct bls_entry *entry)
}
char *tmp = dt;
tmp = grub_stpcpy (dt, "devicetree");
- tmp = grub_stpcpy (tmp, " " GRUB_BOOT_DEVICE);
+ tmp = frob_boot_device (tmp);
if (add_dt_prefix)
tmp = grub_stpcpy (tmp, prefix);
tmp = grub_stpcpy (tmp, devicetree);
@@ -907,7 +950,8 @@ static void create_entry (struct bls_entry *entry)
"linux %s%s%s%s\n"
"%s%s",
savedefault ? "savedefault\n" : "",
- GRUB_BOOT_DEVICE, clinux, options ? " " : "", options ? options : "",
+ separate_boot ? GRUB_BOOT_DEVICE : "",
+ clinux, options ? " " : "", options ? options : "",
initrd ? initrd : "", dt ? dt : "");
grub_normal_add_menu_entry (argc, argv, classes, id, users, hotkey, NULL, src, 0, 0, &index, entry);
--
2.44.0

View File

@@ -0,0 +1,71 @@
From 45fffe05e9c33582258a88b4a722a5a561dbfa6e Mon Sep 17 00:00:00 2001
From: Maxim Suhanov <dfirblog@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 <dfirblog@gmail.com>
Reviewed-by: Daniel Kiper <daniel.kiper@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

View File

@@ -0,0 +1,59 @@
From f7b9580133cf346d77f345d175fa5cb8a591be16 Mon Sep 17 00:00:00 2001
From: Daniel Axtens <dja@axtens.net>
Date: Sat, 15 Aug 2020 02:00:57 +1000
Subject: [PATCH 05/23] docs/grub: Document signing grub under UEFI
Before adding information about how grub is signed with an appended
signature scheme, it's worth adding some information about how it
can currently be signed for UEFI.
Signed-off-by: Daniel Axtens <dja@axtens.net>
---
docs/grub.texi | 22 +++++++++++++++++++++-
1 file changed, 21 insertions(+), 1 deletion(-)
--- a/docs/grub.texi
+++ b/docs/grub.texi
@@ -6345,6 +6345,7 @@
* Secure Boot Advanced Targeting:: Embedded information for generation number based revocation
* Measured Boot:: Measuring boot components
* Lockdown:: Lockdown when booting on a secure setup
+* Signing GRUB itself:: Ensuring the integrity of the GRUB core image
@end menu
@node Authentication and authorisation
@@ -6423,7 +6424,7 @@
GRUB's @file{core.img} can optionally provide enforcement that all files
subsequently read from disk are covered by a valid digital signature.
-This document does @strong{not} cover how to ensure that your
+This section does @strong{not} cover how to ensure that your
platform's firmware (e.g., Coreboot) validates @file{core.img}.
If environment variable @code{check_signatures}
@@ -6586,6 +6587,25 @@
The @samp{lockdown} variable is set to @samp{y} when the GRUB is locked down.
Otherwise it does not exit.
+@node Signing GRUB itself
+@section Signing GRUB itself
+
+To ensure a complete secure-boot chain, there must be a way for the code that
+loads GRUB to verify the integrity of the core image.
+
+This is ultimately platform-specific and individual platforms can define their
+own mechanisms. However, there are general-purpose mechanisms that can be used
+with GRUB.
+
+@section Signing GRUB for UEFI secure boot
+
+On UEFI platforms, @file{core.img} is a PE binary. Therefore, it can be signed
+with a tool such as @command{pesign} or @command{sbsign}. Refer to the
+suggestions in @pxref{UEFI secure boot and shim} to ensure that the final
+image works under UEFI secure boot and can maintain the secure-boot chain. It
+will also be necessary to enrol the public key used into a relevant firmware
+key database.
+
@node Platform limitations
@chapter Platform limitations

View File

@@ -0,0 +1,38 @@
From 3f1980191c693670380aa9aa5a949c5574a3bd04 Mon Sep 17 00:00:00 2001
From: B Horn <b@horn.uk>
Date: Sun, 12 May 2024 06:22:51 +0100
Subject: [PATCH 05/20] fs/hfsplus: Set a grub_errno if mount fails
It was possible for mount to fail but not set grub_errno. This led to
a possible double decrement of the module reference count if the NULL
page was mapped.
Fixing in general as a similar bug was fixed in commit 61b13c187
(fs/hfsplus: Set grub_errno to prevent NULL pointer access) and there
are likely more variants around.
Fixes: CVE-2024-45783
Reported-by: B Horn <b@horn.uk>
Signed-off-by: B Horn <b@horn.uk>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
---
grub-core/fs/hfsplus.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/grub-core/fs/hfsplus.c b/grub-core/fs/hfsplus.c
index 295822f694..de71fd486b 100644
--- a/grub-core/fs/hfsplus.c
+++ b/grub-core/fs/hfsplus.c
@@ -405,7 +405,7 @@ grub_hfsplus_mount (grub_disk_t disk)
fail:
- if (grub_errno == GRUB_ERR_OUT_OF_RANGE)
+ if (grub_errno == GRUB_ERR_OUT_OF_RANGE || grub_errno == GRUB_ERR_NONE)
grub_error (GRUB_ERR_BAD_FS, "not a HFS+ filesystem");
grub_free (data);
--
2.48.1

View File

@@ -0,0 +1,109 @@
From 72092a8641958af95402fa0e3e74cc57c36feefa Mon Sep 17 00:00:00 2001
From: Stefan Berger <stefanb@linux.ibm.com>
Date: Tue, 26 Nov 2024 15:39:44 -0500
Subject: [PATCH 5/7] ieee1275/tcg2: Refactor grub_ieee1275_tpm_init()
Move tpm_get_tpm_version() into grub_ieee1275_tpm_init() and invalidate
grub_ieee1275_tpm_ihandle in case no TPM 2 could be detected. Try the
initialization only once so that grub_tpm_present() will always return
the same result. Use the grub_ieee1275_tpm_ihandle as indicator for an
available TPM instead of grub_ieee1275_tpm_version, which can now be
removed.
Signed-off-by: Stefan Berger <stefanb@linux.ibm.com>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
---
grub-core/commands/ieee1275/ibmvtpm.c | 2 +-
grub-core/lib/ieee1275/tcg2.c | 40 ++++++++++++---------------
include/grub/ieee1275/tpm.h | 1 -
3 files changed, 18 insertions(+), 25 deletions(-)
diff --git a/grub-core/commands/ieee1275/ibmvtpm.c b/grub-core/commands/ieee1275/ibmvtpm.c
index 284673217..4958b04a9 100644
--- a/grub-core/commands/ieee1275/ibmvtpm.c
+++ b/grub-core/commands/ieee1275/ibmvtpm.c
@@ -100,7 +100,7 @@ grub_tpm_measure (unsigned char *buf, grub_size_t size, grub_uint8_t pcr,
grub_dprintf ("tpm", "log_event, pcr = %d, size = 0x%" PRIxGRUB_SIZE ", %s\n",
pcr, size, description);
- if (grub_ieee1275_tpm_version == 2)
+ if (grub_ieee1275_tpm_ihandle != GRUB_IEEE1275_IHANDLE_INVALID)
return tpm2_log_event (buf, size, pcr, description);
return GRUB_ERR_NONE;
diff --git a/grub-core/lib/ieee1275/tcg2.c b/grub-core/lib/ieee1275/tcg2.c
index 1819d1447..ea01a30eb 100644
--- a/grub-core/lib/ieee1275/tcg2.c
+++ b/grub-core/lib/ieee1275/tcg2.c
@@ -23,39 +23,33 @@
#include <grub/mm.h>
#include <grub/misc.h>
-grub_ieee1275_ihandle_t grub_ieee1275_tpm_ihandle;
-grub_uint8_t grub_ieee1275_tpm_version;
-
-static void
-tpm_get_tpm_version (void)
-{
- grub_ieee1275_phandle_t vtpm;
- char buffer[20];
-
- if (!grub_ieee1275_finddevice ("/vdevice/vtpm", &vtpm) &&
- !grub_ieee1275_get_property (vtpm, "compatible", buffer,
- sizeof (buffer), NULL) &&
- !grub_strcmp (buffer, "IBM,vtpm20"))
- grub_ieee1275_tpm_version = 2;
-}
+grub_ieee1275_ihandle_t grub_ieee1275_tpm_ihandle = GRUB_IEEE1275_IHANDLE_INVALID;
grub_err_t
grub_ieee1275_tpm_init (void)
{
- static int init_success = 0;
+ static bool init_tried = false;
+ grub_ieee1275_phandle_t vtpm;
+ char buffer[20];
- if (!init_success)
+ if (init_tried == false)
{
- if (grub_ieee1275_open ("/vdevice/vtpm", &grub_ieee1275_tpm_ihandle) < 0)
+ init_tried = true;
+
+ if (grub_ieee1275_open ("/vdevice/vtpm", &grub_ieee1275_tpm_ihandle) < 0 ||
+ grub_ieee1275_finddevice ("/vdevice/vtpm", &vtpm) ||
+ grub_ieee1275_get_property (vtpm, "compatible", buffer, sizeof (buffer), NULL) ||
+ grub_strcmp (buffer, "IBM,vtpm20"))
{
+ if (grub_ieee1275_tpm_ihandle != GRUB_IEEE1275_IHANDLE_INVALID)
+ grub_ieee1275_close (grub_ieee1275_tpm_ihandle);
+
grub_ieee1275_tpm_ihandle = GRUB_IEEE1275_IHANDLE_INVALID;
- return GRUB_ERR_UNKNOWN_DEVICE;
}
-
- init_success = 1;
-
- tpm_get_tpm_version ();
}
+ if (grub_ieee1275_tpm_ihandle == GRUB_IEEE1275_IHANDLE_INVALID)
+ return GRUB_ERR_UNKNOWN_DEVICE;
+
return GRUB_ERR_NONE;
}
diff --git a/include/grub/ieee1275/tpm.h b/include/grub/ieee1275/tpm.h
index 9575c1c68..fe5cb4713 100644
--- a/include/grub/ieee1275/tpm.h
+++ b/include/grub/ieee1275/tpm.h
@@ -24,7 +24,6 @@
#include <grub/ieee1275/ieee1275.h>
extern grub_ieee1275_ihandle_t grub_ieee1275_tpm_ihandle;
-extern grub_uint8_t grub_ieee1275_tpm_version;
extern grub_err_t grub_ieee1275_tpm_init (void);
--
2.43.0

View File

@@ -0,0 +1,47 @@
From 0289adccc2127a1179fea9da0c787fab04a831f7 Mon Sep 17 00:00:00 2001
From: Alec Brown <alec.r.brown@oracle.com>
Date: Thu, 21 Aug 2025 21:14:08 +0000
Subject: [PATCH 5/7] tests/lib/functional_test: Unregister commands on module
unload
When the functional_test module is loaded, both the functional_test and
all_functional_test commands are registered but only the all_functional_test
command is being unregistered since it was the last to set the cmd variable
that gets unregistered when the module is unloaded. To unregister both
commands, we need to create an additional grub_extcmd_t variable.
Signed-off-by: Alec Brown <alec.r.brown@oracle.com>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
---
grub-core/tests/lib/functional_test.c | 7 ++++---
1 file changed, 4 insertions(+), 3 deletions(-)
diff --git a/grub-core/tests/lib/functional_test.c b/grub-core/tests/lib/functional_test.c
index 403fa5c78..31b6b5dab 100644
--- a/grub-core/tests/lib/functional_test.c
+++ b/grub-core/tests/lib/functional_test.c
@@ -90,17 +90,18 @@ grub_functional_all_tests (grub_extcmd_context_t ctxt __attribute__ ((unused)),
return GRUB_ERR_NONE;
}
-static grub_extcmd_t cmd;
+static grub_extcmd_t cmd, cmd_all;
GRUB_MOD_INIT (functional_test)
{
cmd = grub_register_extcmd ("functional_test", grub_functional_test, 0, 0,
"Run all loaded functional tests.", 0);
- cmd = grub_register_extcmd ("all_functional_test", grub_functional_all_tests, 0, 0,
- "Run all functional tests.", 0);
+ cmd_all = grub_register_extcmd ("all_functional_test", grub_functional_all_tests, 0, 0,
+ "Run all functional tests.", 0);
}
GRUB_MOD_FINI (functional_test)
{
grub_unregister_extcmd (cmd);
+ grub_unregister_extcmd (cmd_all);
}
--
2.51.1

View File

@@ -0,0 +1,200 @@
From fa69deac565e5d5015ca396b017239cd96900673 Mon Sep 17 00:00:00 2001
From: Gary Lin <glin@suse.com>
Date: Mon, 7 Apr 2025 16:29:19 +0800
Subject: [PATCH 5/7] tpm2_key_protector: Unseal key from a buffer
Extract the logic to handle the file buffer from the SRK recover
function to prepare to load the sealed key from the NV index handle,
so the NV index mode can share the same code path in the later patch.
The SRK recover function now only reads the file and sends the file
buffer to the new function.
Besides this, to avoid introducing more options for the NV index mode,
the file format is detected automatically before unmarshaling the data,
so there is no need to use the command option to specify the file format
anymore. In other words, "-T" and "-k" are the same now.
Also update grub.text to address the change.
Signed-off-by: Gary Lin <glin@suse.com>
Reviewed-by: Stefan Berger <stefanb@linux.ibm.com>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
---
docs/grub.texi | 13 +-
.../commands/tpm2_key_protector/module.c | 122 +++++++++++++-----
2 files changed, 96 insertions(+), 39 deletions(-)
Index: grub-2.12/grub-core/commands/tpm2_key_protector/module.c
===================================================================
--- grub-2.12.orig/grub-core/commands/tpm2_key_protector/module.c
+++ grub-2.12/grub-core/commands/tpm2_key_protector/module.c
@@ -218,10 +218,51 @@ tpm2_protector_srk_read_file (const char
return err;
}
+/* Check if the data is in TPM 2.0 Key File format */
+static bool
+tpm2_protector_is_tpm2key (grub_uint8_t *buffer, grub_size_t buffer_size)
+{
+ /* id-sealedkey OID (2.23.133.10.1.5) in DER */
+ const grub_uint8_t sealed_key_oid[] = {0x06, 0x06, 0x67, 0x81, 0x05, 0x0a};
+ grub_size_t skip = 0;
+
+ /* Need at least the first two bytes to check the tag and the length */
+ if (buffer_size < 2)
+ return false;
+
+ /* The first byte is always 0x30 (SEQUENCE). */
+ if (buffer[0] != 0x30)
+ return false;
+
+ /*
+ * Get the bytes of the length
+ *
+ * If the bit 8 of the second byte is 0, it is in the short form, so the second byte
+ * alone represents the length. Thus, the first two bytes are skipped.
+ *
+ * Otherwise, it is in the long form, and bits 1~7 indicate how many more bytes are in
+ * the length field, so we skip the first two bytes plus the bytes for the length.
+ */
+ if ((buffer[1] & 0x80) == 0)
+ skip = 2;
+ else
+ skip = (buffer[1] & 0x7F) + 2;
+
+ /* Make sure the buffer is large enough to contain id-sealedkey OID */
+ if (buffer_size < skip + sizeof (sealed_key_oid))
+ return false;
+
+ /* Check id-sealedkey OID */
+ if (grub_memcmp (buffer + skip, sealed_key_oid, sizeof (sealed_key_oid)) != 0)
+ return false;
+
+ return true;
+}
+
static grub_err_t
-tpm2_protector_srk_unmarshal_keyfile (void *sealed_key,
- grub_size_t sealed_key_size,
- tpm2_sealed_key_t *sk)
+tpm2_protector_unmarshal_raw (void *sealed_key,
+ grub_size_t sealed_key_size,
+ tpm2_sealed_key_t *sk)
{
struct grub_tpm2_buffer buf;
@@ -242,13 +283,13 @@ tpm2_protector_srk_unmarshal_keyfile (vo
}
static grub_err_t
-tpm2_protector_srk_unmarshal_tpm2key (void *sealed_key,
- grub_size_t sealed_key_size,
- tpm2key_policy_t *policy_seq,
- tpm2key_authpolicy_t *authpol_seq,
- grub_uint8_t *rsaparent,
- grub_uint32_t *parent,
- tpm2_sealed_key_t *sk)
+tpm2_protector_unmarshal_tpm2key (void *sealed_key,
+ grub_size_t sealed_key_size,
+ tpm2key_policy_t *policy_seq,
+ tpm2key_authpolicy_t *authpol_seq,
+ grub_uint8_t *rsaparent,
+ grub_uint32_t *parent,
+ tpm2_sealed_key_t *sk)
{
asn1_node tpm2key = NULL;
grub_uint8_t rsaparent_tmp;
@@ -954,12 +995,11 @@ tpm2_protector_dump_pcr (const TPM_ALG_I
}
static grub_err_t
-tpm2_protector_srk_recover (const tpm2_protector_context_t *ctx,
- grub_uint8_t **key, grub_size_t *key_size)
+tpm2_protector_key_from_buffer (const tpm2_protector_context_t *ctx,
+ void *buffer, grub_size_t buf_size,
+ grub_uint8_t **key, grub_size_t *key_size)
{
tpm2_sealed_key_t sealed_key = {0};
- void *file_bytes = NULL;
- grub_size_t file_size = 0;
grub_uint8_t rsaparent = 0;
TPM_HANDLE_t parent_handle = 0;
TPM_HANDLE_t srk_handle = 0;
@@ -972,22 +1012,17 @@ tpm2_protector_srk_recover (const tpm2_p
/*
* Retrieve sealed key, parent handle, policy sequence, and authpolicy
- * sequence from the key file
+ * sequence from the buffer
*/
- if (ctx->tpm2key != NULL)
+ if (tpm2_protector_is_tpm2key (buffer, buf_size) == true)
{
- err = tpm2_protector_srk_read_file (ctx->tpm2key, &file_bytes,
- &file_size);
- if (err != GRUB_ERR_NONE)
- return err;
-
- err = tpm2_protector_srk_unmarshal_tpm2key (file_bytes,
- file_size,
- &policy_seq,
- &authpol_seq,
- &rsaparent,
- &parent_handle,
- &sealed_key);
+ err = tpm2_protector_unmarshal_tpm2key (buffer,
+ buf_size,
+ &policy_seq,
+ &authpol_seq,
+ &rsaparent,
+ &parent_handle,
+ &sealed_key);
if (err != GRUB_ERR_NONE)
goto exit1;
@@ -1003,12 +1038,8 @@ tpm2_protector_srk_recover (const tpm2_p
}
else
{
- err = tpm2_protector_srk_read_file (ctx->keyfile, &file_bytes, &file_size);
- if (err != GRUB_ERR_NONE)
- return err;
-
parent_handle = TPM_RH_OWNER;
- err = tpm2_protector_srk_unmarshal_keyfile (file_bytes, file_size, &sealed_key);
+ err = tpm2_protector_unmarshal_raw (buffer, buf_size, &sealed_key);
if (err != GRUB_ERR_NONE)
goto exit1;
}
@@ -1084,6 +1115,31 @@ tpm2_protector_srk_recover (const tpm2_p
exit1:
grub_tpm2key_free_policy_seq (policy_seq);
grub_tpm2key_free_authpolicy_seq (authpol_seq);
+ return err;
+}
+
+static grub_err_t
+tpm2_protector_srk_recover (const tpm2_protector_context_t *ctx,
+ grub_uint8_t **key, grub_size_t *key_size)
+{
+ const char *filepath;
+ void *file_bytes = NULL;
+ grub_size_t file_size = 0;
+ grub_err_t err;
+
+ if (ctx->tpm2key != NULL)
+ filepath = ctx->tpm2key;
+ else if (ctx->keyfile != NULL)
+ filepath = ctx->keyfile;
+ else
+ return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("key file not specified"));
+
+ err = tpm2_protector_srk_read_file (filepath, &file_bytes, &file_size);
+ if (err != GRUB_ERR_NONE)
+ return err;
+
+ err = tpm2_protector_key_from_buffer (ctx, file_bytes, file_size, key, key_size);
+
grub_free (file_bytes);
return err;
}

View File

@@ -0,0 +1,168 @@
From 6523d493b0772316a3fbb249eb070ada5d266a98 Mon Sep 17 00:00:00 2001
From: Michael Chang <mchang@suse.com>
Date: Wed, 28 Jun 2023 14:32:40 +0800
Subject: [PATCH 6/9] Follow the device where blscfg is discovered
Previously, the code assumed that GRUB_BOOT_DEVICE "($root)" was always
the correct device for the discovered bls menu. However, this assumption
could lead to inaccuracies when attempting to load bls for devices other
than $root.
This patch introduces a more robust approach by utilizing the `struct
find_entry_info *info->devid` parameter, representing the device used to
discover the bls directory. This change ensures consistency in
subsequent translations to native GRUB commands, eliminating potential
discrepancies in device identification during the blscfg process.
Signed-off-by: Michael Chang <mchang@suse.com>
---
grub-core/commands/blscfg.c | 40 +++++++++++++++++++++++++------------
include/grub/menu.h | 1 +
2 files changed, 28 insertions(+), 13 deletions(-)
diff --git a/grub-core/commands/blscfg.c b/grub-core/commands/blscfg.c
index 6495891b9..c872bcef0 100644
--- a/grub-core/commands/blscfg.c
+++ b/grub-core/commands/blscfg.c
@@ -55,15 +55,18 @@ struct keyval
static struct bls_entry *entries = NULL;
-/* Cache probing in frob_boot_device(). Used for linux entry also.
- * Always true in non-emu, meaning to prefix things with GRUB_BOOT_DEVICE. */
-static int separate_boot = -1;
-
#define FOR_BLS_ENTRIES(var) FOR_LIST_ELEMENTS (var, entries)
/* BLS appears to make paths relative to the filesystem that snippets are
* on, not /. Attempt to cope. */
-static char *frob_boot_device(char *tmp)
+#ifdef GRUB_MACHINE_EMU
+/* Cache probing in frob_boot_device(). Used for linux entry also.
+ * Unused in non-emu, meaning to prefix things with device of parent blsdir. */
+static int separate_boot = -1;
+static char *frob_boot_device(char *tmp, const char *bootdev UNUSED)
+#else
+static char *frob_boot_device(char *tmp, const char *bootdev)
+#endif
{
#ifdef GRUB_MACHINE_EMU
grub_file_t f;
@@ -94,9 +97,11 @@ static char *frob_boot_device(char *tmp)
probed:
if (!separate_boot)
return grub_stpcpy (tmp, " ");
-#endif
-
return grub_stpcpy (tmp, " " GRUB_BOOT_DEVICE);
+#else
+ tmp = grub_stpcpy (tmp, " ");
+ return grub_stpcpy (tmp, bootdev);
+#endif
}
static int bls_add_keyval(struct bls_entry *entry, char *key, char *val)
@@ -568,6 +573,9 @@ static int read_entry (
if (rc < 0)
break;
}
+
+ if (info->devid)
+ entry->devid = grub_strdup(info->devid);
if (!rc)
bls_add_entry(entry);
@@ -772,6 +780,7 @@ static void create_entry (struct bls_entry *entry)
char *id = entry->filename;
char *dotconf = id;
char *hotkey = NULL;
+ char *bootdev = entry->devid ? grub_xasprintf("(%s)", entry->devid) : grub_strdup (GRUB_BOOT_DEVICE);
char *users = NULL;
char **classes = NULL;
@@ -865,12 +874,12 @@ static void create_entry (struct bls_entry *entry)
char *tmp;
for (i = 0; early_initrds != NULL && early_initrds[i] != NULL; i++)
- initrd_size += sizeof (" " GRUB_BOOT_DEVICE) \
+ initrd_size += sizeof (" ") + grub_strlen (bootdev) \
+ grub_strlen(initrd_prefix) \
+ grub_strlen (early_initrds[i]) + 1;
for (i = 0; initrds != NULL && initrds[i] != NULL; i++)
- initrd_size += sizeof (" " GRUB_BOOT_DEVICE) \
+ initrd_size += sizeof (" ") + grub_strlen (bootdev) \
+ grub_strlen (initrds[i]) + 1;
initrd_size += 1;
@@ -885,7 +894,7 @@ static void create_entry (struct bls_entry *entry)
for (i = 0; early_initrds != NULL && early_initrds[i] != NULL; i++)
{
grub_dprintf ("blscfg", "adding early initrd %s\n", early_initrds[i]);
- tmp = frob_boot_device (tmp);
+ tmp = frob_boot_device (tmp, bootdev);
tmp = grub_stpcpy (tmp, initrd_prefix);
tmp = grub_stpcpy (tmp, early_initrds[i]);
grub_free(early_initrds[i]);
@@ -894,7 +903,7 @@ static void create_entry (struct bls_entry *entry)
for (i = 0; initrds != NULL && initrds[i] != NULL; i++)
{
grub_dprintf ("blscfg", "adding initrd %s\n", initrds[i]);
- tmp = frob_boot_device (tmp);
+ tmp = frob_boot_device (tmp, bootdev);
tmp = grub_stpcpy (tmp, initrds[i]);
}
tmp = grub_stpcpy (tmp, "\n");
@@ -916,7 +925,7 @@ static void create_entry (struct bls_entry *entry)
}
}
- dt_size = sizeof("devicetree " GRUB_BOOT_DEVICE) + grub_strlen(devicetree) + 1;
+ dt_size = sizeof("devicetree ") + grub_strlen(bootdev) + grub_strlen(devicetree) + 1;
if (add_dt_prefix)
{
@@ -931,7 +940,7 @@ static void create_entry (struct bls_entry *entry)
}
char *tmp = dt;
tmp = grub_stpcpy (dt, "devicetree");
- tmp = frob_boot_device (tmp);
+ tmp = frob_boot_device (tmp, bootdev);
if (add_dt_prefix)
tmp = grub_stpcpy (tmp, prefix);
tmp = grub_stpcpy (tmp, devicetree);
@@ -950,7 +959,11 @@ static void create_entry (struct bls_entry *entry)
"linux %s%s%s%s\n"
"%s%s",
savedefault ? "savedefault\n" : "",
+#ifdef GRUB_MACHINE_EMU
separate_boot ? GRUB_BOOT_DEVICE : "",
+#else
+ bootdev,
+#endif
clinux, options ? " " : "", options ? options : "",
initrd ? initrd : "", dt ? dt : "");
@@ -969,6 +982,7 @@ finish:
grub_free (args);
grub_free (argv);
grub_free (src);
+ grub_free (bootdev);
}
struct find_entry_info {
diff --git a/include/grub/menu.h b/include/grub/menu.h
index 43080828c..76b191c33 100644
--- a/include/grub/menu.h
+++ b/include/grub/menu.h
@@ -28,6 +28,7 @@ struct bls_entry
int nkeyvals;
char *filename;
int visible;
+ const char *devid;
};
struct grub_menu_entry_class
--
2.44.0

View File

@@ -0,0 +1,34 @@
From 8dd7026738fb445abd811bb6bd98ff297676329e Mon Sep 17 00:00:00 2001
From: Jamie <volticks@gmail.com>
Date: Mon, 14 Jul 2025 09:52:59 +0100
Subject: [PATCH 6/7] commands/usbtest: Use correct string length field
An incorrect length field is used for buffer allocation. This leads to
grub_utf16_to_utf8() receiving an incorrect/different length and possibly
causing OOB write. This makes sure to use the correct length.
Fixes: CVE-2025-61661
Reported-by: Jamie <volticks@gmail.com>
Signed-off-by: Jamie <volticks@gmail.com>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
---
grub-core/commands/usbtest.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/grub-core/commands/usbtest.c b/grub-core/commands/usbtest.c
index 2c6d93fe6..8ef187a9a 100644
--- a/grub-core/commands/usbtest.c
+++ b/grub-core/commands/usbtest.c
@@ -99,7 +99,7 @@ grub_usb_get_string (grub_usb_device_t dev, grub_uint8_t index, int langid,
return GRUB_USB_ERR_NONE;
}
- *string = grub_malloc (descstr.length * 2 + 1);
+ *string = grub_malloc (descstrp->length * 2 + 1);
if (! *string)
{
grub_free (descstrp);
--
2.51.1

View File

@@ -0,0 +1,150 @@
From 0a11bc48ea60f7611df2c5b640cecc325c7c4fd9 Mon Sep 17 00:00:00 2001
From: Maxim Suhanov <dfirblog@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 <dfirblog@gmail.com>
Reviewed-by: Daniel Kiper <daniel.kiper@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

View File

@@ -0,0 +1,66 @@
From ac539a315495792cd75fe8ab1c474f26e0a78852 Mon Sep 17 00:00:00 2001
From: Daniel Axtens <dja@axtens.net>
Date: Sat, 15 Aug 2020 02:19:36 +1000
Subject: [PATCH 06/23] docs/grub: Document signing grub with an appended
signature
Signing grub for firmware that verifies an appended signature is a
bit fiddly. I don't want people to have to figure it out from scratch
so document it here.
Signed-off-by: Daniel Axtens <dja@axtens.net>
---
docs/grub.texi | 42 ++++++++++++++++++++++++++++++++++++++++++
1 file changed, 42 insertions(+)
--- a/docs/grub.texi
+++ b/docs/grub.texi
@@ -6606,6 +6606,48 @@
will also be necessary to enrol the public key used into a relevant firmware
key database.
+@section Signing GRUB with an appended signature
+
+The @file{core.img} itself can be signed with a Linux kernel module-style
+appended signature.
+
+To support IEEE1275 platforms where the boot image is often loaded directly
+from a disk partition rather than from a file system, the @file{core.img}
+can specify the size and location of the appended signature with an ELF
+note added by @command{grub-install}.
+
+An image can be signed this way using the @command{sign-file} command from
+the Linux kernel:
+
+@example
+@group
+# grub.key is your private key and certificate.der is your public key
+
+# Determine the size of the appended signature. It depends on the signing
+# certificate and the hash algorithm
+touch empty
+sign-file SHA256 grub.key certificate.der empty empty.sig
+SIG_SIZE=`stat -c '%s' empty.sig`
+rm empty empty.sig
+
+# Build a grub image with $SIG_SIZE reserved for the signature
+grub-install --appended-signature-size $SIG_SIZE --modules="..." ...
+
+# Replace the reserved size with a signature:
+# cut off the last $SIG_SIZE bytes with truncate's minus modifier
+truncate -s -$SIG_SIZE /boot/grub/powerpc-ieee1275/core.elf core.elf.unsigned
+# sign the trimmed file with an appended signature, restoring the correct size
+sign-file SHA256 grub.key certificate.der core.elf.unsigned core.elf.signed
+
+# Don't forget to install the signed image as required
+# (e.g. on powerpc-ieee1275, to the PReP partition)
+@end group
+@end example
+
+As with UEFI secure boot, it is necessary to build in the required modules,
+or sign them separately.
+
+
@node Platform limitations
@chapter Platform limitations

Some files were not shown because too many files have changed in this diff Show More