Accepting request 1004537 from home:gary_lin:branches:Base:System

- Add safety measure to pcr snapshot by checking platform and tpm status
  * safe_tpm_pcr_snapshot.patch

- Fix installation failure due to unavailable nvram device on
  ppc64le (bsc#1201361)
  * 0001-grub-install-set-point-of-no-return-for-powerpc-ieee1275.patch

- Add patches to dynamically allocate additional memory regions for
  EFI systems (bsc#1202438)
  * 0001-mm-Allow-dynamically-requesting-additional-memory-re.patch
  * 0002-kern-efi-mm-Always-request-a-fixed-number-of-pages-o.patch
  * 0003-kern-efi-mm-Extract-function-to-add-memory-regions.patch
  * 0004-kern-efi-mm-Pass-up-errors-from-add_memory_regions.patch
  * 0005-kern-efi-mm-Implement-runtime-addition-of-pages.patch
- Enlarge the default heap size and defer the disk cache
  invalidation (bsc#1202438)
  * 0001-kern-efi-mm-Enlarge-the-default-heap-size.patch
  * 0002-mm-Defer-the-disk-cache-invalidation.patch

- Add patches for ALP FDE support
  * 0001-devmapper-getroot-Have-devmapper-recognize-LUKS2.patch
  * 0002-devmapper-getroot-Set-up-cheated-LUKS2-cryptodisk-mo.patch
  * 0003-disk-cryptodisk-When-cheatmounting-use-the-sector-in.patch
  * 0004-normal-menu-Don-t-show-Booting-s-msg-when-auto-booti.patch
  * 0005-EFI-suppress-the-Welcome-to-GRUB-message-in-EFI-buil.patch
  * 0006-EFI-console-Do-not-set-colorstate-until-the-first-te.patch
  * 0007-EFI-console-Do-not-set-cursor-until-the-first-text-o.patch
  * 0008-linuxefi-Use-common-grub_initrd_load.patch
  * 0009-Add-crypttab_entry-to-obviate-the-need-to-input-pass.patch
  * 0010-templates-import-etc-crypttab-to-grub.cfg.patch

OBS-URL: https://build.opensuse.org/request/show/1004537
OBS-URL: https://build.opensuse.org/package/show/Base:System/grub2?expand=0&rev=419
This commit is contained in:
Michael Chang 2022-09-19 06:10:23 +00:00 committed by Git OBS Bridge
parent 761268d847
commit 3e026f665c
29 changed files with 2631 additions and 1 deletions

View File

@ -0,0 +1,53 @@
From ebe4ac49e800b18b539564169593ab1c6f163378 Mon Sep 17 00:00:00 2001
From: Josselin Poiret via Grub-devel <grub-devel@gnu.org>
Date: Tue, 14 Jun 2022 15:47:29 +0200
Subject: [PATCH 01/10] devmapper/getroot: Have devmapper recognize LUKS2
Changes UUID comparisons so that LUKS1 and LUKS2 are both recognized
as being LUKS cryptodisks.
---
grub-core/osdep/devmapper/getroot.c | 11 +++++++----
1 file changed, 7 insertions(+), 4 deletions(-)
diff --git a/grub-core/osdep/devmapper/getroot.c b/grub-core/osdep/devmapper/getroot.c
index 9ba5c98655..2bf4264cf0 100644
--- a/grub-core/osdep/devmapper/getroot.c
+++ b/grub-core/osdep/devmapper/getroot.c
@@ -138,7 +138,8 @@ grub_util_get_dm_abstraction (const char *os_dev)
grub_free (uuid);
return GRUB_DEV_ABSTRACTION_LVM;
}
- if (strncmp (uuid, "CRYPT-LUKS1-", 12) == 0)
+ if (strncmp (uuid, "CRYPT-LUKS1-", sizeof ("CRYPT-LUKS1-") - 1) == 0
+ || strncmp (uuid, "CRYPT-LUKS2-", sizeof ("CRYPT-LUKS2-") - 1) == 0)
{
grub_free (uuid);
return GRUB_DEV_ABSTRACTION_LUKS;
@@ -179,7 +180,9 @@ grub_util_pull_devmapper (const char *os_dev)
grub_util_pull_device (subdev);
}
}
- if (uuid && strncmp (uuid, "CRYPT-LUKS1-", sizeof ("CRYPT-LUKS1-") - 1) == 0
+ if (uuid
+ && (strncmp (uuid, "CRYPT-LUKS1-", sizeof ("CRYPT-LUKS1-") - 1) == 0
+ || strncmp (uuid, "CRYPT-LUKS2-", sizeof ("CRYPT-LUKS2-") - 1) == 0)
&& lastsubdev)
{
char *grdev = grub_util_get_grub_dev (lastsubdev);
@@ -253,11 +256,11 @@ grub_util_get_devmapper_grub_dev (const char *os_dev)
{
char *dash;
- dash = grub_strchr (uuid + sizeof ("CRYPT-LUKS1-") - 1, '-');
+ dash = grub_strchr (uuid + sizeof ("CRYPT-LUKS*-") - 1, '-');
if (dash)
*dash = 0;
grub_dev = grub_xasprintf ("cryptouuid/%s",
- uuid + sizeof ("CRYPT-LUKS1-") - 1);
+ uuid + sizeof ("CRYPT-LUKS*-") - 1);
grub_free (uuid);
return grub_dev;
}
--
2.34.1

View File

@ -0,0 +1,32 @@
From grub-devel-bounces@gnu.org Thu Aug 25 08:11:08 2022
From: Michael Chang <mchang@suse.com>
Date: Thu, 25 Aug 2022 14:05:01 +0800
Subject: [PATCH] grub-install: set point of no return for powerpc-ieee1275
install
The point of no return is used to define a point where no change should
be reverted in a wake of fatal error that consequently aborts the
process. The powerpc-ieee1275 install apparently missed this point of no
return defintion that newly installed modules could be inadvertently
reverted after successful image embedding so that boot failure is
incurred due to inconsistent state.
Signed-off-by: Michael Chang <mchang@suse.com>
[iluceno@suse.de: Backported to SLES-15-SP4]
Signed-off-by: Ismael Luceno <iluceno@suse.de>
---
util/grub-install.c | 1 +
1 file changed, 1 insertion(+)
Index: grub-2.06/util/grub-install.c
===================================================================
--- grub-2.06.orig/util/grub-install.c
+++ grub-2.06/util/grub-install.c
@@ -2160,6 +2160,7 @@ main (int argc, char *argv[])
{
grub_util_error ("%s", _("failed to copy Grub to the PReP partition"));
}
+ grub_set_install_backup_ponr ();
if ((signed_grub_mode >= SIGNED_GRUB_FORCE) || ((signed_grub_mode == SIGNED_GRUB_AUTO) && (ppc_sb_state > 0)))
{

View File

@ -0,0 +1,32 @@
From 3e08d9afd273b5dade84fec5f7f17113c47b6b75 Mon Sep 17 00:00:00 2001
From: Gary Lin <glin@suse.com>
Date: Fri, 2 Sep 2022 11:26:39 +0800
Subject: [PATCH 1/2] kern/efi/mm: Enlarge the default heap size
The default heap size (0x100000, 1MB) is not enough for the
openSUSE/SUSE theme, and the additional dynamical allocation of memory
regions significantly slows down the loading of the grub2 menu theme.
This commit increases the default heap size to 0x2000000, 32MB, and this
should be enough to cover the theme files.
Signed-off-by: Gary Lin <glin@suse.com>
---
grub-core/kern/efi/mm.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/grub-core/kern/efi/mm.c b/grub-core/kern/efi/mm.c
index 48380d3..70d3e3d 100644
--- a/grub-core/kern/efi/mm.c
+++ b/grub-core/kern/efi/mm.c
@@ -39,7 +39,7 @@
#define MEMORY_MAP_SIZE 0x3000
/* The default heap size for GRUB itself in bytes. */
-#define DEFAULT_HEAP_SIZE 0x100000
+#define DEFAULT_HEAP_SIZE 0x2000000
static void *finish_mmap_buf = 0;
static grub_efi_uintn_t finish_mmap_size = 0;
--
2.35.3

View File

@ -0,0 +1,133 @@
From 23bca58a68264657f176885c3564d07c9938b7f6 Mon Sep 17 00:00:00 2001
From: Patrick Steinhardt <ps@pks.im>
Date: Thu, 21 Apr 2022 15:24:18 +1000
Subject: [PATCH 1/5] mm: Allow dynamically requesting additional memory
regions
Currently, all platforms will set up their heap on initialization of the
platform code. While this works mostly fine, it poses some limitations
on memory management on us. Most notably, allocating big chunks of
memory in the gigabyte range would require us to pre-request this many
bytes from the firmware and add it to the heap from the beginning on
some platforms like EFI. As this isn't needed for most configurations,
it is inefficient and may even negatively impact some usecases when,
e.g., chainloading. Nonetheless, allocating big chunks of memory is
required sometimes, where one example is the upcoming support for the
Argon2 key derival function in LUKS2.
In order to avoid pre-allocating big chunks of memory, this commit
implements a runtime mechanism to add more pages to the system. When
a given allocation cannot be currently satisfied, we'll call a given
callback set up by the platform's own memory management subsystem,
asking it to add a memory area with at least "n" bytes. If this
succeeds, we retry searching for a valid memory region, which should
now succeed.
If this fails, we try asking for "n" bytes, possibly spread across
multiple regions, in hopes that region merging means that we end up
with enough memory for things to work out.
Signed-off-by: Patrick Steinhardt <ps@pks.im>
Signed-off-by: Daniel Axtens <dja@axtens.net>
Tested-by: Stefan Berger <stefanb@linux.ibm.com>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
Tested-by: Patrick Steinhardt <ps@pks.im>
---
grub-core/kern/mm.c | 30 ++++++++++++++++++++++++++++++
include/grub/mm.h | 18 ++++++++++++++++++
2 files changed, 48 insertions(+)
diff --git a/grub-core/kern/mm.c b/grub-core/kern/mm.c
index 5c0a624..0bd9f75 100644
--- a/grub-core/kern/mm.c
+++ b/grub-core/kern/mm.c
@@ -28,6 +28,9 @@
- multiple regions may be used as free space. They may not be
contiguous.
+ - if existing regions are insufficient to satisfy an allocation, a new
+ region can be requested from firmware.
+
Regions are managed by a singly linked list, and the meta information is
stored in the beginning of each region. Space after the meta information
is used to allocate memory.
@@ -77,6 +80,7 @@
grub_mm_region_t grub_mm_base;
+grub_mm_add_region_func_t grub_mm_add_region_fn;
/* Get a header from the pointer PTR, and set *P and *R to a pointer
to the header and a pointer to its region, respectively. PTR must
@@ -364,6 +368,32 @@ grub_memalign (grub_size_t align, grub_size_t size)
goto again;
#endif
+ case 1:
+ /* Request additional pages, contiguous */
+ count++;
+
+ if (grub_mm_add_region_fn != NULL &&
+ grub_mm_add_region_fn (size, GRUB_MM_ADD_REGION_CONSECUTIVE) == GRUB_ERR_NONE)
+ goto again;
+
+ /* fallthrough */
+
+ case 2:
+ /* Request additional pages, anything at all */
+ count++;
+
+ if (grub_mm_add_region_fn != NULL)
+ {
+ /*
+ * Try again even if this fails, in case it was able to partially
+ * satisfy the request
+ */
+ grub_mm_add_region_fn (size, GRUB_MM_ADD_REGION_NONE);
+ goto again;
+ }
+
+ /* fallthrough */
+
default:
break;
}
diff --git a/include/grub/mm.h b/include/grub/mm.h
index 1754635..67faebf 100644
--- a/include/grub/mm.h
+++ b/include/grub/mm.h
@@ -20,6 +20,7 @@
#ifndef GRUB_MM_H
#define GRUB_MM_H 1
+#include <grub/err.h>
#include <grub/types.h>
#include <grub/symbol.h>
#include <config.h>
@@ -28,6 +29,23 @@
# define NULL ((void *) 0)
#endif
+#define GRUB_MM_ADD_REGION_NONE 0
+#define GRUB_MM_ADD_REGION_CONSECUTIVE (1 << 0)
+
+/*
+ * Function used to request memory regions of `grub_size_t` bytes. The second
+ * parameter is a bitfield of `GRUB_MM_ADD_REGION` flags.
+ */
+typedef grub_err_t (*grub_mm_add_region_func_t) (grub_size_t, unsigned int);
+
+/*
+ * Set this function pointer to enable adding memory-regions at runtime in case
+ * a memory allocation cannot be satisfied with existing regions.
+ */
+#ifndef GRUB_MACHINE_EMU
+extern grub_mm_add_region_func_t EXPORT_VAR(grub_mm_add_region_fn);
+#endif
+
void grub_mm_init_region (void *addr, grub_size_t size);
void *EXPORT_FUNC(grub_malloc) (grub_size_t size);
void *EXPORT_FUNC(grub_zalloc) (grub_size_t size);
--
2.35.3

View File

@ -0,0 +1,88 @@
From 12378be5243c1c02ce28de2e5703e87197c69157 Mon Sep 17 00:00:00 2001
From: Michael Chang <mchang@suse.com>
Date: Mon, 29 Aug 2022 11:28:28 +0800
Subject: [PATCH] tpm: Disable tpm verifier if tpm is not present
This helps to prevent out of memory error when reading large files via disablig
tpm device as verifier has to read all content into memory in one chunk to
measure the hash and extend to tpm.
Signed-off-by: Michael Chang <mchang@suse.com>
---
grub-core/commands/efi/tpm.c | 37 +++++++++++++++++++++++++++++++++++++
grub-core/commands/tpm.c | 4 ++++
include/grub/tpm.h | 1 +
3 files changed, 42 insertions(+)
--- a/grub-core/commands/efi/tpm.c
+++ b/grub-core/commands/efi/tpm.c
@@ -349,3 +349,40 @@
return result;
}
+
+int
+grub_tpm_present ()
+{
+ grub_efi_handle_t tpm_handle;
+ grub_efi_uint8_t protocol_version;
+
+ if (!grub_tpm_handle_find (&tpm_handle, &protocol_version))
+ return 0;
+
+ if (protocol_version == 1)
+ {
+ grub_efi_tpm_protocol_t *tpm;
+
+ tpm = grub_efi_open_protocol (tpm_handle, &tpm_guid,
+ GRUB_EFI_OPEN_PROTOCOL_GET_PROTOCOL);
+ if (!tpm)
+ {
+ grub_dprintf ("tpm", "Cannot open TPM protocol\n");
+ return 0;
+ }
+ return grub_tpm1_present (tpm);
+ }
+ else
+ {
+ grub_efi_tpm2_protocol_t *tpm;
+
+ tpm = grub_efi_open_protocol (tpm_handle, &tpm2_guid,
+ GRUB_EFI_OPEN_PROTOCOL_GET_PROTOCOL);
+ if (!tpm)
+ {
+ grub_dprintf ("tpm", "Cannot open TPM protocol\n");
+ return 0;
+ }
+ return grub_tpm2_present (tpm);
+ }
+}
--- a/grub-core/commands/tpm.c
+++ b/grub-core/commands/tpm.c
@@ -291,6 +291,8 @@
GRUB_MOD_INIT (tpm)
{
+ if (!grub_tpm_present())
+ return;
grub_verifier_register (&grub_tpm_verifier);
cmd = grub_register_extcmd ("tpm_record_pcrs", grub_tpm_record_pcrs, 0,
@@ -301,6 +303,8 @@
GRUB_MOD_FINI (tpm)
{
+ if (!grub_tpm_present())
+ return;
grub_verifier_unregister (&grub_tpm_verifier);
grub_unregister_extcmd (cmd);
}
--- a/include/grub/tpm.h
+++ b/include/grub/tpm.h
@@ -44,5 +44,6 @@
grub_uint8_t pcr, const char *description);
struct grub_tpm_digest *grub_tpm_read_pcr (grub_uint8_t index, const char *algo);
void grub_tpm_digest_free (struct grub_tpm_digest *d);
+int grub_tpm_present (void);
#endif

View File

@ -0,0 +1,127 @@
From a25627c13b7e1e6998a14b5dd23b04b28465d737 Mon Sep 17 00:00:00 2001
From: Josselin Poiret via Grub-devel <grub-devel@gnu.org>
Date: Tue, 14 Jun 2022 15:47:30 +0200
Subject: [PATCH 02/10] devmapper/getroot: Set up cheated LUKS2 cryptodisk
mount from DM parameters
This lets a LUKS2 cryptodisk have its cipher and hash filled out,
otherwise they wouldn't be initialized if cheat mounted.
---
grub-core/osdep/devmapper/getroot.c | 91 +++++++++++++++++++++++++++++++++++-
1 file changed, 90 insertions(+), 1 deletion(-)
--- a/grub-core/osdep/devmapper/getroot.c
+++ b/grub-core/osdep/devmapper/getroot.c
@@ -51,6 +51,8 @@
#include <grub/emu/misc.h>
#include <grub/emu/hostdisk.h>
+#include <grub/cryptodisk.h>
+
static int
grub_util_open_dm (const char *os_dev, struct dm_tree **tree,
struct dm_tree_node **node)
@@ -186,7 +188,6 @@
&& lastsubdev)
{
char *grdev = grub_util_get_grub_dev (lastsubdev);
- dm_tree_free (tree);
if (grdev)
{
grub_err_t err;
@@ -194,7 +195,95 @@
if (err)
grub_util_error (_("can't mount encrypted volume `%s': %s"),
lastsubdev, grub_errmsg);
+ if (strncmp (uuid, "CRYPT-LUKS2-", sizeof ("CRYPT-LUKS2-") - 1) == 0)
+ {
+ /* set LUKS2 cipher from dm parameters, since it is not
+ * possible to determine the correct one without
+ * unlocking, as there might be multiple segments.
+ */
+ grub_disk_t source;
+ grub_cryptodisk_t cryptodisk;
+ grub_uint64_t start, length;
+ char *target_type;
+ char *params;
+ const char *name;
+ char *cipher, *cipher_mode;
+ struct dm_task *dmt;
+ char *seek_head, *c;
+ unsigned int remaining;
+
+ source = grub_disk_open (grdev);
+ cryptodisk = grub_cryptodisk_get_by_source_disk (source);
+ grub_disk_close (source);
+
+ name = dm_tree_node_get_name (node);
+
+ grub_util_info ("populating parameters of cryptomount `%s' from DM device `%s'",
+ uuid, name);
+
+ dmt = dm_task_create (DM_DEVICE_TABLE);
+ if (dmt == 0)
+ grub_util_error (_("can't create dm task DM_DEVICE_TABLE"));
+ if (dm_task_set_name (dmt, name) == 0)
+ grub_util_error (_("can't set dm task name to `%s'"), name);
+ if (dm_task_run (dmt) == 0)
+ grub_util_error (_("can't run dm task for `%s'"), name);
+ /* dm_get_next_target doesn't have any error modes, everything has
+ * been handled by dm_task_run.
+ */
+ dm_get_next_target (dmt, NULL, &start, &length,
+ &target_type, &params);
+ if (strncmp (target_type, "crypt", sizeof ("crypt")) != 0)
+ grub_util_error (_("dm target of type `%s' is not `crypt'"),
+ target_type);
+
+ /* dm target parameters for dm-crypt is
+ * <cipher> <key> <iv_offset> <device path> <offset> [<#opt_params> <opt_param1> ...]
+ */
+ c = params;
+ remaining = grub_strlen (c);
+
+ /* first, get the cipher name from the cipher */
+ if (!(seek_head = grub_memchr (c, '-', remaining)))
+ grub_util_error (_("can't get cipher from dm-crypt parameters `%s'"),
+ params);
+ cipher = grub_strndup (c, seek_head - c);
+ remaining -= seek_head - c + 1;
+ c = seek_head + 1;
+
+ /* now, the cipher mode */
+ if (!(seek_head = grub_memchr (c, ' ', remaining)))
+ grub_util_error (_("can't get cipher mode from dm-crypt parameters `%s'"),
+ params);
+ cipher_mode = grub_strndup (c, seek_head - c);
+ remaining -= seek_head - c + 1;
+ c = seek_head + 1;
+
+ err = grub_cryptodisk_setcipher (cryptodisk, cipher, cipher_mode);
+ if (err)
+ {
+ grub_util_error (_("can't set cipher of cryptodisk `%s' to `%s' with mode `%s'"),
+ uuid, cipher, cipher_mode);
+ }
+
+ grub_free (cipher);
+ grub_free (cipher_mode);
+
+ /* This is the only hash usable by PBKDF2, and we don't
+ * have Argon2 support yet, so set it by default,
+ * otherwise grub-probe would miss the required
+ * abstraction
+ */
+ cryptodisk->hash = grub_crypto_lookup_md_by_name ("sha256");
+ if (cryptodisk->hash == 0)
+ {
+ grub_util_error (_("can't lookup hash sha256 by name"));
+ }
+
+ dm_task_destroy (dmt);
+ }
}
+ dm_tree_free (tree);
grub_free (grdev);
}
else

View File

@ -0,0 +1,106 @@
From 834cb2ca9ed2d9d7a6926e598accdfe280b615da Mon Sep 17 00:00:00 2001
From: Patrick Steinhardt <ps@pks.im>
Date: Thu, 21 Apr 2022 15:24:19 +1000
Subject: [PATCH 2/5] kern/efi/mm: Always request a fixed number of pages on
init
When initializing the EFI memory subsystem, we will by default request
a quarter of the available memory, bounded by a minimum/maximum value.
Given that we're about to extend the EFI memory system to dynamically
request additional pages from the firmware as required, this scaling of
requested memory based on available memory will not make a lot of sense
anymore.
Remove this logic as a preparatory patch such that we'll instead defer
to the runtime memory allocator. Note that ideally, we'd want to change
this after dynamic requesting of pages has been implemented for the EFI
platform. But because we'll need to split up initialization of the
memory subsystem and the request of pages from the firmware, we'd have
to duplicate quite some logic at first only to remove it afterwards
again. This seems quite pointless, so we instead have patches slightly
out of order.
Signed-off-by: Patrick Steinhardt <ps@pks.im>
Signed-off-by: Daniel Axtens <dja@axtens.net>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
Tested-by: Patrick Steinhardt <ps@pks.im>
---
grub-core/kern/efi/mm.c | 35 +++--------------------------------
1 file changed, 3 insertions(+), 32 deletions(-)
diff --git a/grub-core/kern/efi/mm.c b/grub-core/kern/efi/mm.c
index 67a691d..2874522 100644
--- a/grub-core/kern/efi/mm.c
+++ b/grub-core/kern/efi/mm.c
@@ -38,9 +38,8 @@
a multiplier of 4KB. */
#define MEMORY_MAP_SIZE 0x3000
-/* The minimum and maximum heap size for GRUB itself. */
-#define MIN_HEAP_SIZE 0x100000
-#define MAX_HEAP_SIZE (1600 * 0x100000)
+/* The default heap size for GRUB itself in bytes. */
+#define DEFAULT_HEAP_SIZE 0x100000
static void *finish_mmap_buf = 0;
static grub_efi_uintn_t finish_mmap_size = 0;
@@ -514,23 +513,6 @@ filter_memory_map (grub_efi_memory_descriptor_t *memory_map,
return filtered_desc;
}
-/* Return the total number of pages. */
-static grub_efi_uint64_t
-get_total_pages (grub_efi_memory_descriptor_t *memory_map,
- grub_efi_uintn_t desc_size,
- grub_efi_memory_descriptor_t *memory_map_end)
-{
- grub_efi_memory_descriptor_t *desc;
- grub_efi_uint64_t total = 0;
-
- for (desc = memory_map;
- desc < memory_map_end;
- desc = NEXT_MEMORY_DESCRIPTOR (desc, desc_size))
- total += desc->num_pages;
-
- return total;
-}
-
/* Add memory regions. */
static void
add_memory_regions (grub_efi_memory_descriptor_t *memory_map,
@@ -619,8 +601,6 @@ grub_efi_mm_init (void)
grub_efi_memory_descriptor_t *filtered_memory_map_end;
grub_efi_uintn_t map_size;
grub_efi_uintn_t desc_size;
- grub_efi_uint64_t total_pages;
- grub_efi_uint64_t required_pages;
int mm_status;
/* Prepare a memory region to store two memory maps. */
@@ -660,22 +640,13 @@ grub_efi_mm_init (void)
filtered_memory_map_end = filter_memory_map (memory_map, filtered_memory_map,
desc_size, memory_map_end);
- /* By default, request a quarter of the available memory. */
- total_pages = get_total_pages (filtered_memory_map, desc_size,
- filtered_memory_map_end);
- required_pages = (total_pages >> 2);
- if (required_pages < BYTES_TO_PAGES (MIN_HEAP_SIZE))
- required_pages = BYTES_TO_PAGES (MIN_HEAP_SIZE);
- else if (required_pages > BYTES_TO_PAGES (MAX_HEAP_SIZE))
- required_pages = BYTES_TO_PAGES (MAX_HEAP_SIZE);
-
/* Sort the filtered descriptors, so that GRUB can allocate pages
from smaller regions. */
sort_memory_map (filtered_memory_map, desc_size, filtered_memory_map_end);
/* Allocate memory regions for GRUB's memory management. */
add_memory_regions (filtered_memory_map, desc_size,
- filtered_memory_map_end, required_pages);
+ filtered_memory_map_end, BYTES_TO_PAGES (DEFAULT_HEAP_SIZE));
#if 0
/* For debug. */
--
2.35.3

View File

@ -0,0 +1,68 @@
From 4284d40799aaf5aab11c690f232ce0a191dcfbdb Mon Sep 17 00:00:00 2001
From: Gary Lin <glin@suse.com>
Date: Fri, 16 Sep 2022 10:59:55 +0800
Subject: [PATCH 2/2] mm: Defer the disk cache invalidation
When the heap memory is used up, the memory management code invalidates
the disk caches first and then requests the additional memory regioins.
Although this could minimize the memory usage, it hurts the loading time
since the disk caches may always miss.
This patch defers the disk cache invalidation to avoid the possible
delays.
Signen-off-by: Gary Lin <glin@suse.com>
---
grub-core/kern/mm.c | 22 +++++++---------------
1 file changed, 7 insertions(+), 15 deletions(-)
diff --git a/grub-core/kern/mm.c b/grub-core/kern/mm.c
index 0bd9f75..5280e8c 100644
--- a/grub-core/kern/mm.c
+++ b/grub-core/kern/mm.c
@@ -355,20 +355,6 @@ grub_memalign (grub_size_t align, grub_size_t size)
switch (count)
{
case 0:
- /* Invalidate disk caches. */
- grub_disk_cache_invalidate_all ();
- count++;
- goto again;
-
-#if 0
- case 1:
- /* Unload unneeded modules. */
- grub_dl_unload_unneeded ();
- count++;
- goto again;
-#endif
-
- case 1:
/* Request additional pages, contiguous */
count++;
@@ -378,7 +364,7 @@ grub_memalign (grub_size_t align, grub_size_t size)
/* fallthrough */
- case 2:
+ case 1:
/* Request additional pages, anything at all */
count++;
@@ -394,6 +380,12 @@ grub_memalign (grub_size_t align, grub_size_t size)
/* fallthrough */
+ case 2:
+ /* Invalidate disk caches. */
+ grub_disk_cache_invalidate_all ();
+ count++;
+ goto again;
+
default:
break;
}
--
2.35.3

View File

@ -0,0 +1,71 @@
From 5b694a13545224c2d21afc3e94831be1bcc85770 Mon Sep 17 00:00:00 2001
From: Fabian Vogt <fvogt@suse.de>
Date: Tue, 14 Jun 2022 15:55:21 +0200
Subject: [PATCH 03/10] disk/cryptodisk: When cheatmounting, use the sector
info of the cheat device
When using grub-probe with cryptodisk, the mapped block device from the host
is used directly instead of decrypting the source device in GRUB code.
In that case, the sector size and count of the host device needs to be used.
This is especially important when using luks2, which does not assign
total_sectors and log_sector_size when scanning, but only later when the
segments in the JSON area are evaluated. With an unset log_sector_size,
grub_open_device complains.
This fixes grub-probe failing with
"error: sector sizes of 1 bytes aren't supported yet."
Signed-off-by: Fabian Vogt <fvogt@suse.de>
---
grub-core/disk/cryptodisk.c | 20 ++++++++++++++++++--
1 file changed, 18 insertions(+), 2 deletions(-)
diff --git a/grub-core/disk/cryptodisk.c b/grub-core/disk/cryptodisk.c
index 6d22bf871c..ae8790f10f 100644
--- a/grub-core/disk/cryptodisk.c
+++ b/grub-core/disk/cryptodisk.c
@@ -698,16 +698,31 @@ grub_cryptodisk_open (const char *name, grub_disk_t disk)
if (!dev)
return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "No such device");
- disk->log_sector_size = dev->log_sector_size;
-
#ifdef GRUB_UTIL
if (dev->cheat)
{
+ grub_uint64_t cheat_dev_size;
+ unsigned int cheat_log_sector_size;
+
if (!GRUB_UTIL_FD_IS_VALID (dev->cheat_fd))
dev->cheat_fd = grub_util_fd_open (dev->cheat, GRUB_UTIL_FD_O_RDONLY);
if (!GRUB_UTIL_FD_IS_VALID (dev->cheat_fd))
return grub_error (GRUB_ERR_IO, N_("cannot open `%s': %s"),
dev->cheat, grub_util_fd_strerror ());
+
+ /* Use the sector size and count of the cheat device */
+ cheat_dev_size = grub_util_get_fd_size (dev->cheat_fd, dev->cheat, &cheat_log_sector_size);
+ if (cheat_dev_size == -1)
+ {
+ const char *errmsg = grub_util_fd_strerror ();
+ grub_util_fd_close (dev->cheat_fd);
+ dev->cheat_fd = GRUB_UTIL_FD_INVALID;
+ return grub_error (GRUB_ERR_IO, N_("failed to query size of device `%s': %s"),
+ dev->cheat, errmsg);
+ }
+
+ dev->log_sector_size = cheat_log_sector_size;
+ dev->total_sectors = cheat_dev_size >> cheat_log_sector_size;
}
#endif
@@ -721,6 +736,7 @@ grub_cryptodisk_open (const char *name, grub_disk_t disk)
}
disk->data = dev;
+ disk->log_sector_size = dev->log_sector_size;
disk->total_sectors = dev->total_sectors;
disk->max_agglomerate = GRUB_DISK_MAX_MAX_AGGLOMERATE;
disk->id = dev->id;
--
2.34.1

View File

@ -0,0 +1,86 @@
From b4500ff77efe3b36256fae1e456ded65fd77cf04 Mon Sep 17 00:00:00 2001
From: Patrick Steinhardt <ps@pks.im>
Date: Thu, 21 Apr 2022 15:24:20 +1000
Subject: [PATCH 3/5] kern/efi/mm: Extract function to add memory regions
In preparation of support for runtime-allocating additional memory
region, this patch extracts the function to retrieve the EFI memory
map and add a subset of it to GRUB's own memory regions.
Signed-off-by: Patrick Steinhardt <ps@pks.im>
Signed-off-by: Daniel Axtens <dja@axtens.net>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
Tested-by: Patrick Steinhardt <ps@pks.im>
---
grub-core/kern/efi/mm.c | 21 +++++++++++++++------
1 file changed, 15 insertions(+), 6 deletions(-)
diff --git a/grub-core/kern/efi/mm.c b/grub-core/kern/efi/mm.c
index 2874522..087272f 100644
--- a/grub-core/kern/efi/mm.c
+++ b/grub-core/kern/efi/mm.c
@@ -592,8 +592,8 @@ print_memory_map (grub_efi_memory_descriptor_t *memory_map,
}
#endif
-void
-grub_efi_mm_init (void)
+static grub_err_t
+grub_efi_mm_add_regions (grub_size_t required_bytes)
{
grub_efi_memory_descriptor_t *memory_map;
grub_efi_memory_descriptor_t *memory_map_end;
@@ -606,7 +606,7 @@ grub_efi_mm_init (void)
/* Prepare a memory region to store two memory maps. */
memory_map = grub_efi_allocate_any_pages (2 * BYTES_TO_PAGES (MEMORY_MAP_SIZE));
if (! memory_map)
- grub_fatal ("cannot allocate memory");
+ return grub_error (GRUB_ERR_OUT_OF_MEMORY, "cannot allocate memory for memory map");
/* Obtain descriptors for available memory. */
map_size = MEMORY_MAP_SIZE;
@@ -624,14 +624,14 @@ grub_efi_mm_init (void)
memory_map = grub_efi_allocate_any_pages (2 * BYTES_TO_PAGES (map_size));
if (! memory_map)
- grub_fatal ("cannot allocate memory");
+ return grub_error (GRUB_ERR_OUT_OF_MEMORY, "cannot allocate memory for new memory map");
mm_status = grub_efi_get_memory_map (&map_size, memory_map, 0,
&desc_size, 0);
}
if (mm_status < 0)
- grub_fatal ("cannot get memory map");
+ return grub_error (GRUB_ERR_OUT_OF_MEMORY, "error fetching memory map from EFI");
memory_map_end = NEXT_MEMORY_DESCRIPTOR (memory_map, map_size);
@@ -646,7 +646,7 @@ grub_efi_mm_init (void)
/* Allocate memory regions for GRUB's memory management. */
add_memory_regions (filtered_memory_map, desc_size,
- filtered_memory_map_end, BYTES_TO_PAGES (DEFAULT_HEAP_SIZE));
+ filtered_memory_map_end, BYTES_TO_PAGES (required_bytes));
#if 0
/* For debug. */
@@ -664,6 +664,15 @@ grub_efi_mm_init (void)
/* Release the memory maps. */
grub_efi_free_pages ((grub_addr_t) memory_map,
2 * BYTES_TO_PAGES (MEMORY_MAP_SIZE));
+
+ return GRUB_ERR_NONE;
+}
+
+void
+grub_efi_mm_init (void)
+{
+ if (grub_efi_mm_add_regions (DEFAULT_HEAP_SIZE) != GRUB_ERR_NONE)
+ grub_fatal ("%s", grub_errmsg);
}
#if defined (__aarch64__) || defined (__arm__) || defined (__riscv)
--
2.35.3

View File

@ -0,0 +1,89 @@
From 4287786dde414d9b0517d12762904b4b2be19d2a Mon Sep 17 00:00:00 2001
From: Patrick Steinhardt <ps@pks.im>
Date: Thu, 21 Apr 2022 15:24:21 +1000
Subject: [PATCH 4/5] kern/efi/mm: Pass up errors from add_memory_regions()
The function add_memory_regions() is currently only called on system
initialization to allocate a fixed amount of pages. As such, it didn't
need to return any errors: in case it failed, we cannot proceed anyway.
This will change with the upcoming support for requesting more memory
from the firmware at runtime, where it doesn't make sense anymore to
fail hard.
Refactor the function to return an error to prepare for this. Note that
this does not change the behaviour when initializing the memory system
because grub_efi_mm_init() knows to call grub_fatal() in case
grub_efi_mm_add_regions() returns an error.
Signed-off-by: Patrick Steinhardt <ps@pks.im>
Signed-off-by: Daniel Axtens <dja@axtens.net>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
Tested-by: Patrick Steinhardt <ps@pks.im>
---
grub-core/kern/efi/mm.c | 22 +++++++++++++++-------
1 file changed, 15 insertions(+), 7 deletions(-)
diff --git a/grub-core/kern/efi/mm.c b/grub-core/kern/efi/mm.c
index 087272f..45ea6d5 100644
--- a/grub-core/kern/efi/mm.c
+++ b/grub-core/kern/efi/mm.c
@@ -514,7 +514,7 @@ filter_memory_map (grub_efi_memory_descriptor_t *memory_map,
}
/* Add memory regions. */
-static void
+static grub_err_t
add_memory_regions (grub_efi_memory_descriptor_t *memory_map,
grub_efi_uintn_t desc_size,
grub_efi_memory_descriptor_t *memory_map_end,
@@ -542,9 +542,9 @@ add_memory_regions (grub_efi_memory_descriptor_t *memory_map,
GRUB_EFI_ALLOCATE_ADDRESS,
GRUB_EFI_LOADER_CODE);
if (! addr)
- grub_fatal ("cannot allocate conventional memory %p with %u pages",
- (void *) ((grub_addr_t) start),
- (unsigned) pages);
+ return grub_error (GRUB_ERR_OUT_OF_MEMORY,
+ "Memory starting at %p (%u pages) marked as free, but EFI would not allocate",
+ (void *) ((grub_addr_t) start), (unsigned) pages);
grub_mm_init_region (addr, PAGES_TO_BYTES (pages));
@@ -554,7 +554,11 @@ add_memory_regions (grub_efi_memory_descriptor_t *memory_map,
}
if (required_pages > 0)
- grub_fatal ("too little memory");
+ return grub_error (GRUB_ERR_OUT_OF_MEMORY,
+ "could not allocate all requested memory: %" PRIuGRUB_UINT64_T " pages still required after iterating EFI memory map",
+ required_pages);
+
+ return GRUB_ERR_NONE;
}
void
@@ -601,6 +605,7 @@ grub_efi_mm_add_regions (grub_size_t required_bytes)
grub_efi_memory_descriptor_t *filtered_memory_map_end;
grub_efi_uintn_t map_size;
grub_efi_uintn_t desc_size;
+ grub_err_t err;
int mm_status;
/* Prepare a memory region to store two memory maps. */
@@ -645,8 +650,11 @@ grub_efi_mm_add_regions (grub_size_t required_bytes)
sort_memory_map (filtered_memory_map, desc_size, filtered_memory_map_end);
/* Allocate memory regions for GRUB's memory management. */
- add_memory_regions (filtered_memory_map, desc_size,
- filtered_memory_map_end, BYTES_TO_PAGES (required_bytes));
+ err = add_memory_regions (filtered_memory_map, desc_size,
+ filtered_memory_map_end,
+ BYTES_TO_PAGES (required_bytes));
+ if (err != GRUB_ERR_NONE)
+ return err;
#if 0
/* For debug. */
--
2.35.3

View File

@ -0,0 +1,93 @@
From d4eb747f831d8b011c712f4335f12b572d6f32d9 Mon Sep 17 00:00:00 2001
From: Hans de Goede <hdegoede@redhat.com>
Date: Fri, 28 Jan 2022 11:30:32 +0100
Subject: [PATCH 04/10] normal/menu: Don't show "Booting `%s'" msg when
auto-booting with TIMEOUT_STYLE_HIDDEN
When the user has asked the menu code to be hidden/quiet and the current
entry is being autobooted because the timeout has expired don't show
the "Booting `%s'" msg.
This is necessary to let flicker-free boots really be flicker free,
otherwise the "Booting `%s'" msg will kick the EFI fb into text mode
and show the msg, breaking the flicker-free experience.
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
---
grub-core/normal/menu.c | 24 ++++++++++++++++--------
1 file changed, 16 insertions(+), 8 deletions(-)
diff --git a/grub-core/normal/menu.c b/grub-core/normal/menu.c
index 47fc12551f..470bfc839b 100644
--- a/grub-core/normal/menu.c
+++ b/grub-core/normal/menu.c
@@ -651,13 +651,15 @@ workaround_snapshot_menu_default_entry (grub_menu_t menu, const char *name, int
entry to be executed is a result of an automatic default selection because
of the timeout. */
static int
-run_menu (grub_menu_t menu, int nested, int *auto_boot)
+run_menu (grub_menu_t menu, int nested, int *auto_boot, int *notify_boot)
{
grub_uint64_t saved_time;
int default_entry, current_entry;
int timeout;
enum timeout_style timeout_style;
+ *notify_boot = 1;
+
default_entry = get_entry_number (menu, "default");
workaround_snapshot_menu_default_entry (menu, "default", &default_entry);
@@ -734,6 +736,7 @@ run_menu (grub_menu_t menu, int nested, int *auto_boot)
if (timeout == 0)
{
*auto_boot = 1;
+ *notify_boot = timeout_style != TIMEOUT_STYLE_HIDDEN;
return default_entry;
}
@@ -894,12 +897,16 @@ run_menu (grub_menu_t menu, int nested, int *auto_boot)
/* Callback invoked immediately before a menu entry is executed. */
static void
-notify_booting (grub_menu_entry_t entry,
- void *userdata __attribute__((unused)))
+notify_booting (grub_menu_entry_t entry, void *userdata)
{
- grub_printf (" ");
- grub_printf_ (N_("Booting `%s'"), entry->title);
- grub_printf ("\n\n");
+ int *notify_boot = userdata;
+
+ if (*notify_boot)
+ {
+ grub_printf (" ");
+ grub_printf_ (N_("Booting `%s'"), entry->title);
+ grub_printf ("\n\n");
+ }
}
/* Callback invoked when a default menu entry executed because of a timeout
@@ -947,8 +954,9 @@ show_menu (grub_menu_t menu, int nested, int autobooted)
int boot_entry;
grub_menu_entry_t e;
int auto_boot;
+ int notify_boot;
- boot_entry = run_menu (menu, nested, &auto_boot);
+ boot_entry = run_menu (menu, nested, &auto_boot, &notify_boot);
if (boot_entry < 0)
break;
@@ -960,7 +968,7 @@ show_menu (grub_menu_t menu, int nested, int autobooted)
if (auto_boot)
grub_menu_execute_with_fallback (menu, e, autobooted,
- &execution_callback, 0);
+ &execution_callback, &notify_boot);
else
grub_menu_execute_entry (e, 0);
if (autobooted)
--
2.34.1

View File

@ -0,0 +1,45 @@
From d9c7bfe88ce7391618192401c426c218d2a17795 Mon Sep 17 00:00:00 2001
From: Hans de Goede <hdegoede@redhat.com>
Date: Fri, 28 Jan 2022 11:30:33 +0100
Subject: [PATCH 05/10] EFI: suppress the "Welcome to GRUB!" message in EFI
builds
Grub EFI builds are now often used in combination with flicker-free
boot, but this breaks with upstream grub because the "Welcome to GRUB!"
message will kick the EFI fb into text mode and show the msg,
breaking the flicker-free experience.
EFI systems are so fast, that when the menu or the countdown are enabled
the message will be immediately overwritten, so in these cases not
printing the message does not matter.
And in case when the timeout_style is set to TIMEOUT_STYLE_HIDDEN,
the user has asked grub to be quiet (for example to allow flickfree
boot) annd thus the message should not be printed.
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
---
grub-core/kern/main.c | 3 +++
1 file changed, 3 insertions(+)
diff --git a/grub-core/kern/main.c b/grub-core/kern/main.c
index 42ea96e39e..35dee404e8 100644
--- a/grub-core/kern/main.c
+++ b/grub-core/kern/main.c
@@ -272,10 +272,13 @@ grub_main (void)
grub_boot_time ("After machine init.");
+ /* This breaks flicker-free boot on EFI systems, so disable it there. */
+#ifndef GRUB_MACHINE_EFI
/* Hello. */
grub_setcolorstate (GRUB_TERM_COLOR_HIGHLIGHT);
grub_printf ("Welcome to GRUB!\n\n");
grub_setcolorstate (GRUB_TERM_COLOR_STANDARD);
+#endif
#ifndef GRUB_MACHINE_PCBIOS
/* Init verifiers API. */
--
2.34.1

View File

@ -0,0 +1,77 @@
From 3a2119e11b9c216f3b008a2c61aca52b91ad7547 Mon Sep 17 00:00:00 2001
From: Patrick Steinhardt <ps@pks.im>
Date: Thu, 21 Apr 2022 15:24:22 +1000
Subject: [PATCH 5/5] kern/efi/mm: Implement runtime addition of pages
Adjust the interface of grub_efi_mm_add_regions() to take a set of
GRUB_MM_ADD_REGION_* flags, which most notably is currently only the
GRUB_MM_ADD_REGION_CONSECUTIVE flag. This allows us to set the function
up as callback for the memory subsystem and have it call out to us in
case there's not enough pages available in the current heap.
Signed-off-by: Patrick Steinhardt <ps@pks.im>
Signed-off-by: Daniel Axtens <dja@axtens.net>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
Tested-by: Patrick Steinhardt <ps@pks.im>
---
grub-core/kern/efi/mm.c | 15 +++++++++++----
1 file changed, 11 insertions(+), 4 deletions(-)
diff --git a/grub-core/kern/efi/mm.c b/grub-core/kern/efi/mm.c
index 45ea6d5..48380d3 100644
--- a/grub-core/kern/efi/mm.c
+++ b/grub-core/kern/efi/mm.c
@@ -518,7 +518,8 @@ static grub_err_t
add_memory_regions (grub_efi_memory_descriptor_t *memory_map,
grub_efi_uintn_t desc_size,
grub_efi_memory_descriptor_t *memory_map_end,
- grub_efi_uint64_t required_pages)
+ grub_efi_uint64_t required_pages,
+ unsigned int flags)
{
grub_efi_memory_descriptor_t *desc;
@@ -532,6 +533,10 @@ add_memory_regions (grub_efi_memory_descriptor_t *memory_map,
start = desc->physical_start;
pages = desc->num_pages;
+
+ if (pages < required_pages && (flags & GRUB_MM_ADD_REGION_CONSECUTIVE))
+ continue;
+
if (pages > required_pages)
{
start += PAGES_TO_BYTES (pages - required_pages);
@@ -597,7 +602,7 @@ print_memory_map (grub_efi_memory_descriptor_t *memory_map,
#endif
static grub_err_t
-grub_efi_mm_add_regions (grub_size_t required_bytes)
+grub_efi_mm_add_regions (grub_size_t required_bytes, unsigned int flags)
{
grub_efi_memory_descriptor_t *memory_map;
grub_efi_memory_descriptor_t *memory_map_end;
@@ -652,7 +657,8 @@ grub_efi_mm_add_regions (grub_size_t required_bytes)
/* Allocate memory regions for GRUB's memory management. */
err = add_memory_regions (filtered_memory_map, desc_size,
filtered_memory_map_end,
- BYTES_TO_PAGES (required_bytes));
+ BYTES_TO_PAGES (required_bytes),
+ flags);
if (err != GRUB_ERR_NONE)
return err;
@@ -679,8 +685,9 @@ grub_efi_mm_add_regions (grub_size_t required_bytes)
void
grub_efi_mm_init (void)
{
- if (grub_efi_mm_add_regions (DEFAULT_HEAP_SIZE) != GRUB_ERR_NONE)
+ if (grub_efi_mm_add_regions (DEFAULT_HEAP_SIZE, GRUB_MM_ADD_REGION_NONE) != GRUB_ERR_NONE)
grub_fatal ("%s", grub_errmsg);
+ grub_mm_add_region_fn = grub_efi_mm_add_regions;
}
#if defined (__aarch64__) || defined (__arm__) || defined (__riscv)
--
2.35.3

View File

@ -0,0 +1,54 @@
From 81339347bc10ec609227361434f75c5e36b85b9f Mon Sep 17 00:00:00 2001
From: Hans de Goede <hdegoede@redhat.com>
Date: Fri, 28 Jan 2022 12:43:48 +0100
Subject: [PATCH 06/10] EFI: console: Do not set colorstate until the first
text output
GRUB_MOD_INIT(normal) does an unconditional:
grub_env_set ("color_normal", "light-gray/black");
which triggers a grub_term_setcolorstate() call. The original version
of the "efi/console: Do not set text-mode until we actually need it" patch:
https://lists.gnu.org/archive/html/grub-devel/2018-03/msg00125.html
Protected against this by caching the requested state in
grub_console_setcolorstate () and then only applying it when the first
text output actually happens. During refactoring to move the
grub_console_setcolorstate () up higher in the grub-core/term/efi/console.c
file the code to cache the color-state + bail early was accidentally
dropped.
Restore the cache the color-state + bail early behavior from the original.
Cc: Javier Martinez Canillas <javierm@redhat.com>
Fixes: 2d7c3abd871f ("efi/console: Do not set text-mode until we actually need it")
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
---
grub-core/term/efi/console.c | 10 ++++++++++
1 file changed, 10 insertions(+)
diff --git a/grub-core/term/efi/console.c b/grub-core/term/efi/console.c
index 2f1ae85ba7..c44b2ac318 100644
--- a/grub-core/term/efi/console.c
+++ b/grub-core/term/efi/console.c
@@ -82,6 +82,16 @@ grub_console_setcolorstate (struct grub_term_output *term
{
grub_efi_simple_text_output_interface_t *o;
+ if (grub_efi_is_finished || text_mode != GRUB_TEXT_MODE_AVAILABLE)
+ {
+ /*
+ * Cache colorstate changes before the first text-output, this avoids
+ * "color_normal" environment writes causing a switch to textmode.
+ */
+ text_colorstate = state;
+ return;
+ }
+
if (grub_efi_is_finished)
return;
--
2.34.1

View File

@ -0,0 +1,75 @@
From 9b12dc80d4254e22c41805cecf2494a8e6a50e3e Mon Sep 17 00:00:00 2001
From: Hans de Goede <hdegoede@redhat.com>
Date: Fri, 28 Jan 2022 12:43:49 +0100
Subject: [PATCH 07/10] EFI: console: Do not set cursor until the first text
output
To allow flickerfree boot the EFI console code does not call
grub_efi_set_text_mode (1) until some text is actually output.
Depending on if the output text is because of an error loading
e.g. the .cfg file; or because of showing the menu the cursor needs
to be on or off when the first text is shown.
So far the cursor was hardcoded to being on, but this is causing
drawing artifacts + slow drawing of the menu as reported here:
https://bugzilla.redhat.com/show_bug.cgi?id=1946969
Handle the cursorstate in the same way as the colorstate to fix this,
when no text has been output yet, just cache the cursorstate and
then use the last set value when the first text is output.
Fixes: 2d7c3abd871f ("efi/console: Do not set text-mode until we actually need it")
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
---
grub-core/term/efi/console.c | 19 ++++++++++++++++---
1 file changed, 16 insertions(+), 3 deletions(-)
diff --git a/grub-core/term/efi/console.c b/grub-core/term/efi/console.c
index c44b2ac318..a3622e4fe5 100644
--- a/grub-core/term/efi/console.c
+++ b/grub-core/term/efi/console.c
@@ -31,7 +31,15 @@ typedef enum {
}
grub_text_mode;
+typedef enum {
+ GRUB_CURSOR_MODE_UNDEFINED = -1,
+ GRUB_CURSOR_MODE_OFF = 0,
+ GRUB_CURSUR_MODE_ON
+}
+grub_cursor_mode;
+
static grub_text_mode text_mode = GRUB_TEXT_MODE_UNDEFINED;
+static grub_cursor_mode cursor_mode = GRUB_CURSOR_MODE_UNDEFINED;
static grub_term_color_state text_colorstate = GRUB_TERM_COLOR_UNDEFINED;
static grub_uint32_t
@@ -119,8 +127,12 @@ grub_console_setcursor (struct grub_term_output *term __attribute__ ((unused)),
{
grub_efi_simple_text_output_interface_t *o;
- if (grub_efi_is_finished)
- return;
+ if (grub_efi_is_finished || text_mode != GRUB_TEXT_MODE_AVAILABLE)
+ {
+ /* Cache cursor changes before the first text-output */
+ cursor_mode = on;
+ return;
+ }
o = grub_efi_system_table->con_out;
efi_call_2 (o->enable_cursor, o, on);
@@ -143,7 +155,8 @@ grub_prepare_for_text_output (struct grub_term_output *term)
return GRUB_ERR_BAD_DEVICE;
}
- grub_console_setcursor (term, 1);
+ if (cursor_mode != GRUB_CURSOR_MODE_UNDEFINED)
+ grub_console_setcursor (term, cursor_mode);
if (text_colorstate != GRUB_TERM_COLOR_UNDEFINED)
grub_console_setcolorstate (term, text_colorstate);
text_mode = GRUB_TEXT_MODE_AVAILABLE;
--
2.34.1

View File

@ -0,0 +1,156 @@
From adf486860fe0d395579be8b01d4fda8b93377768 Mon Sep 17 00:00:00 2001
From: Michael Chang <mchang@suse.com>
Date: Wed, 8 Jun 2022 16:04:12 +0800
Subject: [PATCH 08/10] linuxefi: Use common grub_initrd_load
By using the common initrd loading routine factored out allows to share between
features like concatenating initramfs component.
For eg.
initrdefi /initrd-5.16.15-1-default newc:grub.cfg:/grub2/grub.cfg
The file /grub2/grub.cfg read off from root disk will be available to use as
/grub.cfg in the target initramfs loaded by grub.
Signed-off-by: Michael Chang <mchang@suse.com>
---
grub-core/loader/i386/efi/linux.c | 87 ++++---------------------------
1 file changed, 10 insertions(+), 77 deletions(-)
diff --git a/grub-core/loader/i386/efi/linux.c b/grub-core/loader/i386/efi/linux.c
index 6b06a8f2ff..f93395fc62 100644
--- a/grub-core/loader/i386/efi/linux.c
+++ b/grub-core/loader/i386/efi/linux.c
@@ -30,6 +30,7 @@
#include <grub/cpu/efi/memory.h>
#include <grub/tpm.h>
#include <grub/safemath.h>
+#include <grub/linux.h>
GRUB_MOD_LICENSE ("GPLv3+");
@@ -146,44 +147,6 @@ grub_linuxefi_unload (void)
return GRUB_ERR_NONE;
}
-#define BOUNCE_BUFFER_MAX 0x1000000ull
-
-static grub_ssize_t
-read(grub_file_t file, grub_uint8_t *bufp, grub_size_t len)
-{
- grub_ssize_t bufpos = 0;
- static grub_size_t bbufsz = 0;
- static char *bbuf = NULL;
-
- if (bbufsz == 0)
- bbufsz = MIN(BOUNCE_BUFFER_MAX, len);
-
- while (!bbuf && bbufsz)
- {
- bbuf = grub_malloc(bbufsz);
- if (!bbuf)
- bbufsz >>= 1;
- }
- if (!bbuf)
- grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("cannot allocate bounce buffer"));
-
- while (bufpos < (long long)len)
- {
- grub_ssize_t sz;
-
- sz = grub_file_read (file, bbuf, MIN(bbufsz, len - bufpos));
- if (sz < 0)
- return sz;
- if (sz == 0)
- break;
-
- grub_memcpy(bufp + bufpos, bbuf, sz);
- bufpos += sz;
- }
-
- return bufpos;
-}
-
#define LOW_U32(val) ((grub_uint32_t)(((grub_addr_t)(val)) & 0xffffffffull))
#define HIGH_U32(val) ((grub_uint32_t)(((grub_addr_t)(val) >> 32) & 0xffffffffull))
@@ -191,10 +154,8 @@ static grub_err_t
grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)),
int argc, char *argv[])
{
- grub_file_t *files = 0;
- int i, nfiles = 0;
+ struct grub_linux_initrd_context initrd_ctx = { 0, 0, 0 };
grub_size_t size = 0;
- grub_uint8_t *ptr;
if (argc == 0)
{
@@ -208,24 +169,10 @@ grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)),
goto fail;
}
- files = grub_calloc (argc, sizeof (files[0]));
- if (!files)
+ if (grub_initrd_init (argc, argv, &initrd_ctx))
goto fail;
- for (i = 0; i < argc; i++)
- {
- files[i] = grub_file_open (argv[i], GRUB_FILE_TYPE_LINUX_INITRD
- | GRUB_FILE_TYPE_NO_DECOMPRESS);
- if (! files[i])
- goto fail;
- nfiles++;
- if (grub_add (size, ALIGN_UP (grub_file_size (files[i]), 4), &size))
- {
- grub_error (GRUB_ERR_OUT_OF_RANGE, N_("overflow is detected"));
- goto fail;
- }
- }
-
+ size = grub_get_initrd_size (&initrd_ctx);
initrd_mem = kernel_alloc(size, N_("can't allocate initrd"));
if (initrd_mem == NULL)
goto fail;
@@ -238,30 +185,16 @@ grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)),
params->ext_ramdisk_image = HIGH_U32(initrd_mem);
#endif
- ptr = initrd_mem;
-
- for (i = 0; i < nfiles; i++)
- {
- grub_ssize_t cursize = grub_file_size (files[i]);
- if (read (files[i], ptr, cursize) != cursize)
- {
- if (!grub_errno)
- grub_error (GRUB_ERR_FILE_READ_ERROR, N_("premature end of file %s"),
- argv[i]);
- goto fail;
- }
- ptr += cursize;
- grub_memset (ptr, 0, ALIGN_UP_OVERHEAD (cursize, 4));
- ptr += ALIGN_UP_OVERHEAD (cursize, 4);
- }
+ /* FIXME: Use bounce buffers as many UEFI machines apparently can't DMA
+ * correctly above 4GB
+ */
+ if (grub_initrd_load (&initrd_ctx, argv, initrd_mem))
+ goto fail;
params->ramdisk_size = size;
fail:
- for (i = 0; i < nfiles; i++)
- grub_file_close (files[i]);
- grub_free (files);
-
+ grub_initrd_close (&initrd_ctx);
if (initrd_mem && grub_errno)
grub_efi_free_pages((grub_efi_physical_address_t)(grub_addr_t)initrd_mem, BYTES_TO_PAGES(size));
--
2.34.1

View File

@ -0,0 +1,338 @@
From 749f7dee6f63217e536663aebb817aec72a65d5a Mon Sep 17 00:00:00 2001
From: Michael Chang <mchang@suse.com>
Date: Thu, 9 Jun 2022 21:06:00 +0800
Subject: [PATCH 09/10] Add crypttab_entry to obviate the need to input
password twice
This patch adds crypttab_entry command to hint grub where to put the key file
automatically loaded by linux cryptsetup. It's syntax is similar to
/etc/crypttab so that it is relatively straightforward to import.
crypttab_entry <volume-name> <encrypted-device> <key-file>
For eg:
crypttab_entry cr_root 5e1dd109e39343f984da57fd742d3f23 none
Please note the "encrypted-device" only accepts UUID without dashes as it is
the only identification used by grub's cryptodisk device. The crypttab_entry
can also be used multiple times to specify encrypted volumes unlocked by
"cryptomount -a".
Signed-off-by: Michael Chang <mchang@suse.com>
---
grub-core/Makefile.core.def | 5 ++
grub-core/commands/crypttab.c | 42 ++++++++++++
grub-core/disk/cryptodisk.c | 5 ++
grub-core/loader/linux.c | 126 ++++++++++++++++++++++++++++++++--
include/grub/linux.h | 3 +
5 files changed, 177 insertions(+), 4 deletions(-)
create mode 100644 grub-core/commands/crypttab.c
Index: grub-2.06/grub-core/Makefile.core.def
===================================================================
--- grub-2.06.orig/grub-core/Makefile.core.def
+++ grub-2.06/grub-core/Makefile.core.def
@@ -2643,3 +2643,8 @@ module = {
cflags = '$(CFLAGS_POSIX) $(CFLAGS_GNULIB)';
cppflags = '$(CPPFLAGS_POSIX) $(CPPFLAGS_GNULIB)';
};
+
+module = {
+ name = crypttab;
+ common = commands/crypttab.c;
+};
Index: grub-2.06/grub-core/commands/crypttab.c
===================================================================
--- /dev/null
+++ grub-2.06/grub-core/commands/crypttab.c
@@ -0,0 +1,42 @@
+
+#include <grub/dl.h>
+#include <grub/command.h>
+#include <grub/misc.h>
+#include <grub/i18n.h>
+#include <grub/linux.h>
+
+GRUB_MOD_LICENSE ("GPLv3+");
+
+static grub_err_t
+grub_cmd_crypttab_entry (grub_command_t cmd __attribute__ ((unused)),
+ int argc, char **argv)
+{
+ char buf[64];
+ const char *path = argv[2];
+
+ if (argc != 3)
+ return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("three arguments expected"));
+
+ if (grub_strcmp (argv[2], "none") == 0
+ || grub_strcmp (argv[2], "-") == 0)
+ {
+ grub_snprintf (buf, sizeof (buf), "/etc/cryptsetup-keys.d/%s.key", argv[0]);
+ path = buf;
+ }
+
+ /*FIXME: Validate UUID string*/
+ return grub_initrd_publish_key (argv[1], NULL, 0, path);
+}
+
+static grub_command_t cmd;
+
+GRUB_MOD_INIT(crypttab)
+{
+ cmd = grub_register_command ("crypttab_entry", grub_cmd_crypttab_entry,
+ N_("VOLUME-NAME ENCRYPTED-DEVICE KEY-FILE") , N_("No description"));
+}
+
+GRUB_MOD_FINI(crypttab)
+{
+ grub_unregister_command (cmd);
+}
Index: grub-2.06/grub-core/disk/cryptodisk.c
===================================================================
--- grub-2.06.orig/grub-core/disk/cryptodisk.c
+++ grub-2.06/grub-core/disk/cryptodisk.c
@@ -30,6 +30,8 @@
#ifdef GRUB_UTIL
#include <grub/emu/hostdisk.h>
+#else
+#include <grub/linux.h>
#endif
GRUB_MOD_LICENSE ("GPLv3+");
@@ -1146,6 +1148,10 @@ grub_cryptodisk_scan_device_real (const
dev = NULL;
cleanup:
+#ifndef GRUB_UTIL
+ if (cargs->key_data)
+ grub_initrd_publish_key (dev->uuid, (const char *)cargs->key_data, cargs->key_len, NULL);
+#endif
if (askpass)
{
cargs->key_len = 0;
Index: grub-2.06/grub-core/loader/linux.c
===================================================================
--- grub-2.06.orig/grub-core/loader/linux.c
+++ grub-2.06/grub-core/loader/linux.c
@@ -5,6 +5,7 @@
#include <grub/file.h>
#include <grub/mm.h>
#include <grub/safemath.h>
+#include <grub/list.h>
struct newc_head
{
@@ -27,6 +28,7 @@ struct newc_head
struct grub_linux_initrd_component
{
grub_file_t file;
+ char *buf;
char *newc_name;
grub_off_t size;
};
@@ -38,6 +40,18 @@ struct dir
struct dir *child;
};
+struct grub_key_publisher
+{
+ struct grub_key_publisher *next;
+ struct grub_key_publisher **prev;
+ char *name; /* UUID */
+ char *path;
+ char *key;
+ grub_size_t key_len;
+};
+
+static struct grub_key_publisher *kpuber;
+
static char
hex (grub_uint8_t val)
{
@@ -149,6 +163,65 @@ insert_dir (const char *name, struct dir
return GRUB_ERR_NONE;
}
+static grub_err_t
+grub_initrd_component (const char *buf, int bufsz, const char *newc_name,
+ struct grub_linux_initrd_context *initrd_ctx)
+{
+ struct dir *root = 0;
+ struct grub_linux_initrd_component *comp = initrd_ctx->components + initrd_ctx->nfiles;
+ grub_size_t dir_size, name_len;
+
+ while (*newc_name == '/')
+ newc_name++;
+
+ initrd_ctx->size = ALIGN_UP (initrd_ctx->size, 4);
+ comp->newc_name = grub_strdup (newc_name);
+ if (!comp->newc_name ||
+ insert_dir (comp->newc_name, &root, 0, &dir_size))
+ {
+ /* FIXME: Check NULL file pointer before close */
+ grub_initrd_close (initrd_ctx);
+ return grub_errno;
+ }
+ /* Should name_len count terminating null ? */
+ name_len = grub_strlen (comp->newc_name) + 1;
+ if (grub_add (initrd_ctx->size,
+ ALIGN_UP (sizeof (struct newc_head) + name_len, 4),
+ &initrd_ctx->size) ||
+ grub_add (initrd_ctx->size, dir_size, &initrd_ctx->size))
+ goto overflow;
+
+ comp->buf = grub_malloc (bufsz);
+ if (!comp->buf)
+ {
+ free_dir (root);
+ grub_initrd_close (initrd_ctx);
+ return grub_errno;
+ }
+ grub_memcpy (comp->buf, buf, bufsz);
+ initrd_ctx->nfiles++;
+ comp->size = bufsz;
+ if (grub_add (initrd_ctx->size, comp->size,
+ &initrd_ctx->size))
+ goto overflow;
+
+ initrd_ctx->size = ALIGN_UP (initrd_ctx->size, 4);
+ if (grub_add (initrd_ctx->size,
+ ALIGN_UP (sizeof (struct newc_head)
+ + sizeof ("TRAILER!!!") - 1, 4),
+ &initrd_ctx->size))
+ goto overflow;
+
+ free_dir (root);
+ root = 0;
+ return GRUB_ERR_NONE;
+
+ overflow:
+ free_dir (root);
+ grub_initrd_close (initrd_ctx);
+ return grub_error (GRUB_ERR_OUT_OF_RANGE, N_("overflow is detected"));
+}
+
grub_err_t
grub_initrd_init (int argc, char *argv[],
struct grub_linux_initrd_context *initrd_ctx)
@@ -156,11 +229,17 @@ grub_initrd_init (int argc, char *argv[]
int i;
int newc = 0;
struct dir *root = 0;
+ struct grub_key_publisher *pk;
+ int numkey = 0;
initrd_ctx->nfiles = 0;
initrd_ctx->components = 0;
- initrd_ctx->components = grub_calloc (argc, sizeof (initrd_ctx->components[0]));
+ FOR_LIST_ELEMENTS (pk, kpuber)
+ if (pk->key && pk->path)
+ numkey++;
+
+ initrd_ctx->components = grub_calloc (argc + numkey, sizeof (initrd_ctx->components[0]));
if (!initrd_ctx->components)
return grub_errno;
@@ -239,7 +318,10 @@ grub_initrd_init (int argc, char *argv[]
free_dir (root);
root = 0;
}
-
+
+ FOR_LIST_ELEMENTS (pk, kpuber)
+ if (pk->key && pk->path)
+ grub_initrd_component (pk->key, pk->key_len, pk->path, initrd_ctx);
return GRUB_ERR_NONE;
overflow:
@@ -263,7 +345,9 @@ grub_initrd_close (struct grub_linux_ini
for (i = 0; i < initrd_ctx->nfiles; i++)
{
grub_free (initrd_ctx->components[i].newc_name);
- grub_file_close (initrd_ctx->components[i].file);
+ if (initrd_ctx->components[i].file)
+ grub_file_close (initrd_ctx->components[i].file);
+ grub_free (initrd_ctx->components[i].buf);
}
grub_free (initrd_ctx->components);
initrd_ctx->components = 0;
@@ -297,7 +381,7 @@ grub_initrd_load (struct grub_linux_init
}
ptr += dir_size;
ptr = make_header (ptr, initrd_ctx->components[i].newc_name,
- grub_strlen (initrd_ctx->components[i].newc_name),
+ grub_strlen (initrd_ctx->components[i].newc_name) + 1,
0100777,
initrd_ctx->components[i].size);
newc = 1;
@@ -312,7 +396,12 @@ grub_initrd_load (struct grub_linux_init
}
cursize = initrd_ctx->components[i].size;
- if (grub_file_read (initrd_ctx->components[i].file, ptr, cursize)
+ if (initrd_ctx->components[i].buf)
+ {
+ grub_memcpy (ptr, initrd_ctx->components[i].buf, cursize);
+ newc = 1;
+ }
+ else if (grub_file_read (initrd_ctx->components[i].file, ptr, cursize)
!= cursize)
{
if (!grub_errno)
@@ -333,3 +422,41 @@ grub_initrd_load (struct grub_linux_init
root = 0;
return GRUB_ERR_NONE;
}
+
+grub_err_t
+grub_initrd_publish_key (const char *uuid, const char *key, grub_size_t key_len, const char *path)
+{
+ struct grub_key_publisher *cur = grub_named_list_find (GRUB_AS_NAMED_LIST (kpuber), uuid);
+
+ if (!cur)
+ cur = grub_zalloc (sizeof (*cur));
+ if (!cur)
+ return grub_errno;
+
+ if (key && key_len)
+ {
+ grub_free (cur->key);
+ cur->key = grub_malloc (key_len);
+ if (!cur->key)
+ {
+ grub_free (cur);
+ return grub_errno;
+ }
+ grub_memcpy (cur->key, key, key_len);
+ cur->key_len = key_len;
+ }
+
+ if (path)
+ {
+ grub_free (cur->path);
+ cur->path = grub_strdup (path);
+ }
+
+ if (!cur->name)
+ {
+ cur->name = grub_strdup (uuid);
+ grub_list_push (GRUB_AS_LIST_P (&kpuber), GRUB_AS_LIST (cur));
+ }
+
+ return GRUB_ERR_NONE;
+}
Index: grub-2.06/include/grub/linux.h
===================================================================
--- grub-2.06.orig/include/grub/linux.h
+++ grub-2.06/include/grub/linux.h
@@ -22,3 +22,6 @@ grub_initrd_close (struct grub_linux_ini
grub_err_t
grub_initrd_load (struct grub_linux_initrd_context *initrd_ctx,
char *argv[], void *target);
+
+grub_err_t
+grub_initrd_publish_key (const char *uuid, const char *key, grub_size_t key_len, const char *path);

View File

@ -0,0 +1,81 @@
From 2d3130c289b293269dcf558a26674f83f77729a6 Mon Sep 17 00:00:00 2001
From: Michael Chang <mchang@suse.com>
Date: Tue, 14 Jun 2022 17:10:01 +0800
Subject: [PATCH 10/10] templates: import /etc/crypttab to grub.cfg
The /etc/crypptab is used to setup location of encryption key files during
boot, among other things. It is useful to make use the information by grub to
determine where keys are being looked up.
This script can be used to import relevant /etc/crypptab entry to grub.cfg.
Signed-off-by: Michael Chang <mchang@suse.com>
---
Makefile.util.def | 7 +++++++
util/grub.d/05_crypttab.in | 36 ++++++++++++++++++++++++++++++++++++
2 files changed, 43 insertions(+)
create mode 100644 util/grub.d/05_crypttab.in
diff --git a/Makefile.util.def b/Makefile.util.def
index 08f681cd8b..5e0ba22f3d 100644
--- a/Makefile.util.def
+++ b/Makefile.util.def
@@ -476,6 +476,13 @@ script = {
installdir = grubconf;
};
+script = {
+ name = '05_crypttab';
+ common = util/grub.d/05_crypttab.in;
+ installdir = grubconf;
+ condition = COND_HOST_LINUX;
+};
+
script = {
name = '10_windows';
common = util/grub.d/10_windows.in;
diff --git a/util/grub.d/05_crypttab.in b/util/grub.d/05_crypttab.in
new file mode 100644
index 0000000000..c539bc061e
--- /dev/null
+++ b/util/grub.d/05_crypttab.in
@@ -0,0 +1,36 @@
+#! /bin/sh
+set -e
+
+# grub-mkconfig helper script.
+# Copyright (C) 2022 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/>.
+
+prefix="@prefix@"
+exec_prefix="@exec_prefix@"
+datarootdir="@datarootdir@"
+
+export TEXTDOMAIN=@PACKAGE@
+export TEXTDOMAINDIR="@localedir@"
+
+. "$pkgdatadir/grub-mkconfig_lib"
+
+CRYPTTAB=/etc/crypttab
+
+if [ -r "$CRYPTTAB" ]; then
+ awk '/UUID=/ { sub(/UUID=/,"",$2); \
+ gsub(/-/,"",$2); \
+ printf("crypttab_entry %s %s %s\n",$1,$2,$3) \
+ }' "$CRYPTTAB"
+fi
--
2.34.1

View File

@ -0,0 +1,51 @@
Index: grub-2.06/include/grub/efi/efi.h
===================================================================
--- grub-2.06.orig/include/grub/efi/efi.h
+++ grub-2.06/include/grub/efi/efi.h
@@ -86,6 +86,11 @@ grub_efi_status_t EXPORT_FUNC (grub_efi_
const grub_efi_guid_t *guid,
grub_size_t *datasize_out,
void **data_out);
+grub_err_t EXPORT_FUNC (grub_efi_set_variable_with_attributes) (const char *var,
+ const grub_efi_guid_t *guid,
+ grub_efi_uint32_t attributes,
+ void *data,
+ grub_size_t datasize);
grub_err_t
EXPORT_FUNC (grub_efi_set_variable) (const char *var,
const grub_efi_guid_t *guid,
Index: grub-2.06/grub-core/kern/efi/efi.c
===================================================================
--- grub-2.06.orig/grub-core/kern/efi/efi.c
+++ grub-2.06/grub-core/kern/efi/efi.c
@@ -196,6 +196,17 @@ grub_err_t
grub_efi_set_variable(const char *var, const grub_efi_guid_t *guid,
void *data, grub_size_t datasize)
{
+ return grub_efi_set_variable_with_attributes(var, guid,
+ (GRUB_EFI_VARIABLE_NON_VOLATILE
+ | GRUB_EFI_VARIABLE_BOOTSERVICE_ACCESS
+ | GRUB_EFI_VARIABLE_RUNTIME_ACCESS),
+ data, datasize);
+}
+
+grub_err_t
+grub_efi_set_variable_with_attributes(const char *var, const grub_efi_guid_t *guid, grub_efi_uint32_t attributes,
+ void *data, grub_size_t datasize)
+{
grub_efi_status_t status;
grub_efi_runtime_services_t *r;
grub_efi_char16_t *var16;
@@ -211,10 +222,8 @@ grub_efi_set_variable(const char *var, c
r = grub_efi_system_table->runtime_services;
- status = efi_call_5 (r->set_variable, var16, guid,
- (GRUB_EFI_VARIABLE_NON_VOLATILE
- | GRUB_EFI_VARIABLE_BOOTSERVICE_ACCESS
- | GRUB_EFI_VARIABLE_RUNTIME_ACCESS),
+ status = efi_call_5 (r->set_variable, var16, guid,
+ attributes,
datasize, data);
grub_free (var16);
if (status == GRUB_EFI_SUCCESS)

View File

@ -0,0 +1,18 @@
Index: grub-2.06/util/grub-install.c
===================================================================
--- grub-2.06.orig/util/grub-install.c
+++ grub-2.06/util/grub-install.c
@@ -1457,6 +1457,13 @@ main (int argc, char *argv[])
grub_util_unlink (load_cfg);
+ if (1)
+ {
+ load_cfg_f = grub_util_fopen (load_cfg, "wb");
+ have_load_cfg = 1;
+ fprintf (load_cfg_f, "tpm_record_pcrs 0-9\n");
+ }
+
if (debug_image && debug_image[0])
{
load_cfg_f = grub_util_fopen (load_cfg, "wb");

151
grub-read-pcr.patch Normal file
View File

@ -0,0 +1,151 @@
Index: grub-2.06/include/grub/tpm.h
===================================================================
--- grub-2.06.orig/include/grub/tpm.h
+++ grub-2.06/include/grub/tpm.h
@@ -34,6 +34,15 @@
#define EV_IPL 0x0d
+struct grub_tpm_digest {
+ const char * algorithm;
+ unsigned int size;
+ unsigned char value[1]; /* variable length */
+};
+
grub_err_t grub_tpm_measure (unsigned char *buf, grub_size_t size,
grub_uint8_t pcr, const char *description);
+struct grub_tpm_digest *grub_tpm_read_pcr (grub_uint8_t index, const char *algo);
+void grub_tpm_digest_free (struct grub_tpm_digest *d);
+
#endif
Index: grub-2.06/grub-core/commands/efi/tpm.c
===================================================================
--- grub-2.06.orig/grub-core/commands/efi/tpm.c
+++ grub-2.06/grub-core/commands/efi/tpm.c
@@ -23,6 +23,7 @@
#include <grub/efi/api.h>
#include <grub/efi/efi.h>
#include <grub/efi/tpm.h>
+#include <grub/tpm2/tpm2.h>
#include <grub/mm.h>
#include <grub/tpm.h>
#include <grub/term.h>
@@ -186,6 +187,91 @@ grub_tpm1_log_event (grub_efi_handle_t t
return grub_efi_log_event_status (status);
}
+static void
+grub_tpm2_select_pcr(TPML_PCR_SELECTION *o, unsigned int pcrIndex, unsigned int algo)
+{
+ TPMS_PCR_SELECTION *pcr;
+
+ pcr = &o->pcrSelections[o->count++];
+ pcr->hash = algo;
+ pcr->sizeOfSelect = 3;
+ pcr->pcrSelect[TPM2_PCR_TO_SELECT(pcrIndex)] |= TPM2_PCR_TO_BIT(pcrIndex);
+}
+
+struct grub_tpm_hash_info {
+ const char *name;
+ grub_size_t size;
+ int id;
+};
+
+static const struct grub_tpm_hash_info *
+grub_tpm2_get_digest_info (const char *algo)
+{
+ static struct grub_tpm_hash_info __hashes[] = {
+ { "sha256", 32, TPM_ALG_SHA256 }, /* first entry is the default */
+ { "sha512", 64, TPM_ALG_SHA512 },
+ { "sha1", 20, TPM_ALG_SHA1 },
+ { NULL }
+ };
+ struct grub_tpm_hash_info *h;
+
+ if (algo == NULL)
+ return &__hashes[0];
+
+ for (h = __hashes; h->name; ++h)
+ if (!grub_strcmp(h->name, algo))
+ return h;
+
+ return NULL;
+}
+
+static grub_err_t
+grub_tpm2_read_pcr (grub_int8_t pcrIndex, const char *algo, struct grub_tpm_digest **ret)
+{
+ const struct grub_tpm_hash_info *info;
+ TPML_PCR_SELECTION inSelection, outSelection;
+ grub_uint32_t pcrUpdateCounter;
+ TPML_DIGEST digests = { 0 };
+ TPM2B_DIGEST *d;
+ struct grub_tpm_digest *result;
+ int rc;
+
+ info = grub_tpm2_get_digest_info (algo);
+ if (info == NULL)
+ return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("Unknown digest algorithm %s"), algo);
+
+ grub_memset(&inSelection, 0, sizeof(inSelection));
+ grub_memset(&outSelection, 0, sizeof(outSelection));
+ grub_tpm2_select_pcr(&inSelection, pcrIndex, info->id);
+
+ rc = TPM2_PCR_Read(
+ NULL,
+ &inSelection,
+ &pcrUpdateCounter,
+ &outSelection,
+ &digests,
+ NULL
+ );
+
+ if (rc != 0)
+ return grub_error (GRUB_ERR_BAD_DEVICE, "TPM2_PCR_Read failed, status=%d", rc);
+
+ d = &digests.digests[0];
+
+ *ret = result = grub_malloc (sizeof (*result) + d->size);
+ grub_memcpy (result->value, d->buffer, d->size);
+ result->algorithm = info->name;
+ result->size = d->size;
+
+ return GRUB_ERR_NONE;
+}
+
+void
+grub_tpm_digest_free (struct grub_tpm_digest *d)
+{
+ grub_free (d);
+}
+
static grub_err_t
grub_tpm2_log_event (grub_efi_handle_t tpm_handle, unsigned char *buf,
grub_size_t size, grub_uint8_t pcr,
@@ -240,3 +326,26 @@ grub_tpm_measure (unsigned char *buf, gr
else
return grub_tpm2_log_event (tpm_handle, buf, size, pcr, description);
}
+
+struct grub_tpm_digest *
+grub_tpm_read_pcr (grub_uint8_t pcr, const char *algo)
+{
+ grub_efi_handle_t tpm_handle;
+ grub_efi_uint8_t protocol_version;
+ struct grub_tpm_digest *result = NULL;
+
+
+ if (!grub_tpm_handle_find (&tpm_handle, &protocol_version))
+ return 0;
+
+ if (protocol_version != 2)
+ {
+ grub_error (GRUB_ERR_BAD_DEVICE, N_("%s: TPM version %d not implemented"), __func__, protocol_version);
+ return NULL;
+ }
+
+ if (grub_tpm2_read_pcr (pcr, algo, &result))
+ return NULL;
+
+ return result;
+}

41
grub-unseal-debug.patch Normal file
View File

@ -0,0 +1,41 @@
Index: grub-2.06/grub-core/tpm2/module.c
===================================================================
--- grub-2.06.orig/grub-core/tpm2/module.c
+++ grub-2.06/grub-core/tpm2/module.c
@@ -22,6 +22,7 @@
#include <grub/misc.h>
#include <grub/mm.h>
#include <grub/protector.h>
+#include <grub/time.h>
#include <grub/tpm2/buffer.h>
#include <grub/tpm2/internal/args.h>
#include <grub/tpm2/mu.h>
@@ -449,6 +450,7 @@ grub_tpm2_protector_srk_recover (const s
{
grub_error (err, N_("Failed to unseal sealed key (TPM2_Unseal failed "
"with TSS/TPM error %u)"), rc);
+ grub_millisleep(500);
goto exit4;
}
@@ -461,6 +463,8 @@ grub_tpm2_protector_srk_recover (const s
goto exit4;
}
+ grub_printf("TPM2: unsealed %u bytes of key material\n", data.size);
+
if (ctx->efivar)
{
rc = grub_tpm2_protector_publish_key (data.buffer, data.size, ctx->efivar);
Index: grub-2.06/grub-core/loader/linux.c
===================================================================
--- grub-2.06.orig/grub-core/loader/linux.c
+++ grub-2.06/grub-core/loader/linux.c
@@ -171,6 +171,7 @@ grub_initrd_component (const char *buf,
struct grub_linux_initrd_component *comp = initrd_ctx->components + initrd_ctx->nfiles;
grub_size_t dir_size, name_len;
+ grub_printf("Creating initrd component \"%s\" with %u bytes\n", newc_name, bufsz);
while (*newc_name == '/')
newc_name++;

View File

@ -1,3 +1,59 @@
-------------------------------------------------------------------
Mon Sep 19 04:07:36 UTC 2022 - Michael Chang <mchang@suse.com>
- Add safety measure to pcr snapshot by checking platform and tpm status
* safe_tpm_pcr_snapshot.patch
-------------------------------------------------------------------
Fri Sep 16 03:56:14 UTC 2022 - Michael Chang <mchang@suse.com>
- Fix installation failure due to unavailable nvram device on
ppc64le (bsc#1201361)
* 0001-grub-install-set-point-of-no-return-for-powerpc-ieee1275.patch
-------------------------------------------------------------------
Fri Sep 16 03:12:36 UTC 2022 - Gary Ching-Pang Lin <glin@suse.com>
- Add patches to dynamically allocate additional memory regions for
EFI systems (bsc#1202438)
* 0001-mm-Allow-dynamically-requesting-additional-memory-re.patch
* 0002-kern-efi-mm-Always-request-a-fixed-number-of-pages-o.patch
* 0003-kern-efi-mm-Extract-function-to-add-memory-regions.patch
* 0004-kern-efi-mm-Pass-up-errors-from-add_memory_regions.patch
* 0005-kern-efi-mm-Implement-runtime-addition-of-pages.patch
- Enlarge the default heap size and defer the disk cache
invalidation (bsc#1202438)
* 0001-kern-efi-mm-Enlarge-the-default-heap-size.patch
* 0002-mm-Defer-the-disk-cache-invalidation.patch
-------------------------------------------------------------------
Thu Sep 15 09:51:07 UTC 2022 - Michael Chang <mchang@suse.com>
- Add patches for ALP FDE support
* 0001-devmapper-getroot-Have-devmapper-recognize-LUKS2.patch
* 0002-devmapper-getroot-Set-up-cheated-LUKS2-cryptodisk-mo.patch
* 0003-disk-cryptodisk-When-cheatmounting-use-the-sector-in.patch
* 0004-normal-menu-Don-t-show-Booting-s-msg-when-auto-booti.patch
* 0005-EFI-suppress-the-Welcome-to-GRUB-message-in-EFI-buil.patch
* 0006-EFI-console-Do-not-set-colorstate-until-the-first-te.patch
* 0007-EFI-console-Do-not-set-cursor-until-the-first-text-o.patch
* 0008-linuxefi-Use-common-grub_initrd_load.patch
* 0009-Add-crypttab_entry-to-obviate-the-need-to-input-pass.patch
* 0010-templates-import-etc-crypttab-to-grub.cfg.patch
* grub-read-pcr.patch
* efi-set-variable-with-attrs.patch
* tpm-record-pcrs.patch
* tpm-protector-dont-measure-sealed-key.patch
* tpm-protector-export-secret-key.patch
* grub-install-record-pcrs.patch
* grub-unseal-debug.patch
-------------------------------------------------------------------
Mon Aug 29 03:48:55 UTC 2022 - Michael Chang <mchang@suse.com>
- Fix out of memory error cannot be prevented via disabling tpm (bsc#1202438)
* 0001-tpm-Disable-tpm-verifier-if-tpm-is-not-present.patch
-------------------------------------------------------------------
Thu Aug 18 02:47:28 UTC 2022 - Michael Chang <mchang@suse.com>

View File

@ -423,6 +423,36 @@ Patch897: 0013-cryptodisk-Support-key-protectors.patch
Patch898: 0014-util-grub-protect-Add-new-tool.patch
Patch899: fix-tpm2-build.patch
Patch900: 0001-crytodisk-fix-cryptodisk-module-looking-up.patch
# fde
Patch901: 0001-devmapper-getroot-Have-devmapper-recognize-LUKS2.patch
Patch902: 0002-devmapper-getroot-Set-up-cheated-LUKS2-cryptodisk-mo.patch
Patch903: 0003-disk-cryptodisk-When-cheatmounting-use-the-sector-in.patch
Patch904: 0004-normal-menu-Don-t-show-Booting-s-msg-when-auto-booti.patch
Patch905: 0005-EFI-suppress-the-Welcome-to-GRUB-message-in-EFI-buil.patch
Patch906: 0006-EFI-console-Do-not-set-colorstate-until-the-first-te.patch
Patch907: 0007-EFI-console-Do-not-set-cursor-until-the-first-text-o.patch
Patch908: 0008-linuxefi-Use-common-grub_initrd_load.patch
Patch909: 0009-Add-crypttab_entry-to-obviate-the-need-to-input-pass.patch
Patch910: 0010-templates-import-etc-crypttab-to-grub.cfg.patch
Patch911: grub-read-pcr.patch
Patch912: efi-set-variable-with-attrs.patch
Patch913: tpm-record-pcrs.patch
Patch914: tpm-protector-dont-measure-sealed-key.patch
Patch915: tpm-protector-export-secret-key.patch
Patch916: grub-install-record-pcrs.patch
Patch917: grub-unseal-debug.patch
# efi mm
Patch918: 0001-tpm-Disable-tpm-verifier-if-tpm-is-not-present.patch
Patch919: 0001-mm-Allow-dynamically-requesting-additional-memory-re.patch
Patch920: 0002-kern-efi-mm-Always-request-a-fixed-number-of-pages-o.patch
Patch921: 0003-kern-efi-mm-Extract-function-to-add-memory-regions.patch
Patch922: 0004-kern-efi-mm-Pass-up-errors-from-add_memory_regions.patch
Patch923: 0005-kern-efi-mm-Implement-runtime-addition-of-pages.patch
Patch924: 0001-kern-efi-mm-Enlarge-the-default-heap-size.patch
Patch925: 0002-mm-Defer-the-disk-cache-invalidation.patch
# powerpc-ieee1275
Patch926: 0001-grub-install-set-point-of-no-return-for-powerpc-ieee1275.patch
Patch927: safe_tpm_pcr_snapshot.patch
Requires: gettext-runtime
%if 0%{?suse_version} >= 1140
@ -691,7 +721,7 @@ CD_MODULES="all_video boot cat configfile echo true \
password password_pbkdf2 png reboot search search_fs_uuid \
search_fs_file search_label sleep test video fat loadenv"
PXE_MODULES="tftp http"
CRYPTO_MODULES="luks luks2 gcry_rijndael gcry_sha1 gcry_sha256 gcry_sha512"
CRYPTO_MODULES="luks luks2 gcry_rijndael gcry_sha1 gcry_sha256 gcry_sha512 crypttab"
%ifarch %{efi}
CD_MODULES="${CD_MODULES} chain efifwsetup efinet read tpm tpm2"
PXE_MODULES="${PXE_MODULES} efinet"
@ -1214,6 +1244,7 @@ fi
%dir %{_sysconfdir}/grub.d
%{_sysconfdir}/grub.d/README
%config(noreplace) %{_sysconfdir}/grub.d/00_header
%config(noreplace) %{_sysconfdir}/grub.d/05_crypttab
%config(noreplace) %{_sysconfdir}/grub.d/10_linux
%config(noreplace) %{_sysconfdir}/grub.d/20_linux_xen
%config(noreplace) %{_sysconfdir}/grub.d/30_uefi-firmware

View File

@ -0,0 +1,90 @@
---
grub-core/commands/tpm.c | 28 ++++++++++++++++++++++------
util/grub-install.c | 7 +++++--
2 files changed, 27 insertions(+), 8 deletions(-)
--- a/grub-core/commands/tpm.c
+++ b/grub-core/commands/tpm.c
@@ -249,6 +249,8 @@
return GRUB_ERR_NONE;
}
+#ifdef GRUB_MACHINE_EFI
+
static grub_err_t
grub_tpm_record_pcrs (grub_extcmd_context_t ctxt, int argc, char **args)
{
@@ -259,6 +261,10 @@
grub_size_t size = 0;
int n, rv = 1;
+ /* To prevent error: unable to read PCR from TPM, if no TPM device available */
+ if (!grub_tpm_present())
+ return GRUB_ERR_NONE;
+
if (argc == 0)
pcr_bitmask = GRUB2_PCR_BITMASK_DEFAULT;
else
@@ -287,13 +293,24 @@
return rv;
}
+#else
+
+static grub_err_t
+grub_tpm_record_pcrs (grub_extcmd_context_t ctxt __attribute__((unused)),
+ int argc __attribute__((unused)),
+ char **args __attribute__((unused)))
+{
+ return GRUB_ERR_NONE;
+}
+
+#endif
+
static grub_extcmd_t cmd;
GRUB_MOD_INIT (tpm)
{
- if (!grub_tpm_present())
- return;
- grub_verifier_register (&grub_tpm_verifier);
+ if (grub_tpm_present())
+ grub_verifier_register (&grub_tpm_verifier);
cmd = grub_register_extcmd ("tpm_record_pcrs", grub_tpm_record_pcrs, 0,
N_("LIST_OF_PCRS"),
@@ -303,8 +320,7 @@
GRUB_MOD_FINI (tpm)
{
- if (!grub_tpm_present())
- return;
- grub_verifier_unregister (&grub_tpm_verifier);
+ if (grub_tpm_present())
+ grub_verifier_unregister (&grub_tpm_verifier);
grub_unregister_extcmd (cmd);
}
--- a/util/grub-install.c
+++ b/util/grub-install.c
@@ -1457,8 +1457,10 @@
grub_util_unlink (load_cfg);
- if (1)
+ /* FIXME: It seems config.is_cryptodisk_enabled is missing here */
+ if (platform == GRUB_INSTALL_PLATFORM_X86_64_EFI)
{
+ grub_install_push_module ("tpm");
load_cfg_f = grub_util_fopen (load_cfg, "wb");
have_load_cfg = 1;
fprintf (load_cfg_f, "tpm_record_pcrs 0-9\n");
@@ -1466,7 +1468,8 @@
if (debug_image && debug_image[0])
{
- load_cfg_f = grub_util_fopen (load_cfg, "wb");
+ if (!load_cfg_f)
+ load_cfg_f = grub_util_fopen (load_cfg, "wb");
have_load_cfg = 1;
fprintf (load_cfg_f, "set debug='%s'\n",
debug_image);

View File

@ -0,0 +1,15 @@
Index: grub-2.06/grub-core/tpm2/module.c
===================================================================
--- grub-2.06.orig/grub-core/tpm2/module.c
+++ grub-2.06/grub-core/tpm2/module.c
@@ -139,7 +139,9 @@ grub_tpm2_protector_srk_read_keyfile (co
void *sealed_key_buffer;
grub_off_t sealed_key_read;
- sealed_key_file = grub_file_open (filepath, GRUB_FILE_TYPE_NONE);
+ /* Using GRUB_FILE_TYPE_SIGNATURE ensures we do not hash the keyfile into PCR9
+ * otherwise we'll never be able to predict the value of PCR9 at unseal time */
+ sealed_key_file = grub_file_open (filepath, GRUB_FILE_TYPE_SIGNATURE);
if (!sealed_key_file)
{
grub_dprintf ("tpm2", "Could not open sealed key file.\n");

View File

@ -0,0 +1,138 @@
Index: grub-2.06/grub-core/tpm2/module.c
===================================================================
--- grub-2.06.orig/grub-core/tpm2/module.c
+++ grub-2.06/grub-core/tpm2/module.c
@@ -26,6 +26,7 @@
#include <grub/tpm2/internal/args.h>
#include <grub/tpm2/mu.h>
#include <grub/tpm2/tpm2.h>
+#include <grub/efi/efi.h>
GRUB_MOD_LICENSE ("GPLv3+");
@@ -46,6 +47,7 @@ struct grub_tpm2_protector_context
const char *keyfile;
TPM_HANDLE srk;
TPM_HANDLE nv;
+ const char *efivar;
};
static const struct grub_arg_option grub_tpm2_protector_init_cmd_options[] =
@@ -122,6 +124,16 @@ static const struct grub_arg_option grub
N_("Required in NV Index mode, the NV handle to read which must "
"readily exist on the TPM and which contains the key."),
},
+ /* When publishing the unsealed key to a UEFI variable */
+ {
+ .longarg = "efivar",
+ .shortarg = 'E',
+ .flags = 0,
+ .arg = NULL,
+ .type = ARG_TYPE_STRING,
+ .doc =
+ N_("Publish the unsealed key to the indicated UEFI variable."),
+ },
/* End of list */
{0, 0, 0, 0, 0, 0}
};
@@ -302,6 +314,34 @@ grub_tpm2_protector_srk_get (const struc
}
static grub_err_t
+grub_tpm2_protector_publish_key (grub_uint8_t *key, grub_size_t key_size,
+ const char *var_name)
+{
+ grub_efi_guid_t vendor_guid = { 0x58aca851, 0x8af7, 0x4738, { 0xa5, 0x42, 0x26, 0x6e, 0x21, 0xf5, 0xca, 0xd9 }};
+ grub_uint8_t *tmp_key;
+ grub_err_t err;
+
+ /* It appears that EFI's set_var function overwrites the key. */
+ tmp_key = grub_malloc (key_size);
+ if (!tmp_key)
+ {
+ grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("No memory left to allocate temporary key buffer"));
+ return GRUB_ERR_OUT_OF_MEMORY;
+ }
+
+ grub_memcpy(tmp_key, key, key_size);
+
+ err = grub_efi_set_variable_with_attributes(var_name, &vendor_guid,
+ GRUB_EFI_VARIABLE_BOOTSERVICE_ACCESS | GRUB_EFI_VARIABLE_RUNTIME_ACCESS,
+ tmp_key, key_size);
+ if (err)
+ grub_error (err, N_("Failed to export LUKS key as EFI variable %s"), var_name);
+
+ grub_free (tmp_key);
+ return err;
+}
+
+static grub_err_t
grub_tpm2_protector_srk_recover (const struct grub_tpm2_protector_context *ctx,
grub_uint8_t **key, grub_size_t *key_size)
{
@@ -421,6 +461,13 @@ grub_tpm2_protector_srk_recover (const s
goto exit4;
}
+ if (ctx->efivar)
+ {
+ rc = grub_tpm2_protector_publish_key (data.buffer, data.size, ctx->efivar);
+ if (rc)
+ goto exit4;
+ }
+
grub_memcpy (key_out, data.buffer, data.size);
*key = key_out;
@@ -549,20 +596,32 @@ grub_tpm2_protector_check_args (struct g
}
static grub_err_t
-grub_tpm2_protector_parse_keyfile (const char *value, const char **keyfile)
+grub_tpm2_protector_parse_string (const char *value, const char **var, const char *arg_name)
{
if (grub_strlen (value) == 0)
return GRUB_ERR_BAD_ARGUMENT;
- *keyfile = grub_strdup (value);
- if (!*keyfile)
+ *var = grub_strdup (value);
+ if (!*var)
return grub_error (GRUB_ERR_OUT_OF_MEMORY,
- N_("No memory to duplicate keyfile path"));
+ N_("No memory to duplicate %s argument"), arg_name);
return GRUB_ERR_NONE;
}
static grub_err_t
+grub_tpm2_protector_parse_keyfile (const char *value, const char **keyfile)
+{
+ return grub_tpm2_protector_parse_string (value, keyfile, "keyfile");
+}
+
+static grub_err_t
+grub_tpm2_protector_parse_efivar (const char *value, const char **efivar)
+{
+ return grub_tpm2_protector_parse_string (value, efivar, "efivar");
+}
+
+static grub_err_t
grub_tpm2_protector_parse_mode (const char *value,
grub_tpm2_protector_mode_t *mode)
{
@@ -650,6 +709,14 @@ grub_tpm2_protector_init_cmd_handler (gr
if (err)
return err;
}
+
+ if (state[7].set) /* efivar */
+ {
+ err = grub_tpm2_protector_parse_efivar (state[7].arg,
+ &grub_tpm2_protector_ctx.efivar);
+ if (err)
+ return err;
+ }
err = grub_tpm2_protector_check_args (&grub_tpm2_protector_ctx);

235
tpm-record-pcrs.patch Normal file
View File

@ -0,0 +1,235 @@
Index: grub-2.06/grub-core/commands/tpm.c
===================================================================
--- grub-2.06.orig/grub-core/commands/tpm.c
+++ grub-2.06/grub-core/commands/tpm.c
@@ -26,6 +26,9 @@
#include <grub/term.h>
#include <grub/verify.h>
#include <grub/dl.h>
+#include <grub/extcmd.h>
+#include <grub/tpm2/tpm2.h>
+#include <grub/efi/efi.h>
GRUB_MOD_LICENSE ("GPLv3+");
@@ -84,12 +87,220 @@ struct grub_file_verifier grub_tpm_verif
.verify_string = grub_tpm_verify_string,
};
+/*
+ * Preserve current PCR values and record them to an EFI variable
+ */
+#define GRUB2_PCR_BITMASK_DEFAULT ((1 << 16) - 1)
+#define GRUB2_PCR_BITMASK_ALL ((1 << 24) - 1)
+
+static const struct grub_arg_option grub_tpm_record_pcrs_options[] =
+ {
+ {
+ .longarg = "efivar",
+ .shortarg = 'E',
+ .flags = 0,
+ .arg = NULL,
+ .type = ARG_TYPE_STRING,
+ .doc =
+ N_("The EFI variable to publish the PCRs to (default GrubPcrSnapshot)"),
+ },
+
+ {0, 0, 0, 0, 0, 0}
+ };
+
+static grub_err_t
+grub_tpm_parse_pcr_index (const char *word, const char **end_ret, unsigned int *index)
+{
+ const char *end;
+
+ if (!grub_isdigit (word[0]))
+ return GRUB_ERR_BAD_NUMBER;
+
+ *index = grub_strtoul(word, &end, 0);
+ if (*index > 32)
+ return GRUB_ERR_BAD_NUMBER;
+
+ *end_ret = end;
+ return GRUB_ERR_NONE;
+}
+
+static grub_err_t
+grub_tpm_parse_pcr_list (const char *arg, grub_uint32_t *bitmask)
+{
+ const char *word, *end;
+ unsigned int index, last_index;
+
+ if (!grub_strcmp (arg, "all"))
+ {
+ *bitmask = GRUB2_PCR_BITMASK_ALL;
+ return GRUB_ERR_NONE;
+ }
+
+ word = arg;
+ while (1)
+ {
+ if (grub_tpm_parse_pcr_index (word, &end, &index))
+ goto bad_pcr_index;
+
+ if (*end == '-')
+ {
+ if (grub_tpm_parse_pcr_index (end + 1, &end, &last_index) || last_index < index)
+ goto bad_pcr_index;
+
+ while (index <= last_index)
+ *bitmask |= (1 << (index++));
+ }
+ else
+ *bitmask |= (1 << index);
+
+ if (*end == '\0')
+ break;
+
+ if (*end != ',')
+ goto bad_pcr_index;
+
+ word = end + 1;
+ }
+
+ return GRUB_ERR_NONE;
+
+bad_pcr_index:
+ return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("cannot parse PCR list \"%s\""), arg);
+}
+
+static inline unsigned int
+nbits(grub_uint32_t mask)
+{
+ unsigned int r = 0;
+
+ for (; mask != 0; mask >>= 1)
+ r += (mask & 1);
+ return r;
+}
+
+static grub_err_t
+grub_tpm_snapshot_pcrs (grub_uint32_t pcr_bitmask, const char *algo,
+ void **buffer_ret, grub_size_t *size_ret)
+{
+ char *buffer;
+ grub_size_t size = 65536;
+ unsigned int wpos = 0;
+ grub_uint8_t pcr;
+
+ buffer = grub_malloc (size);
+ for (pcr = 0; pcr < 32; ++pcr)
+ {
+ struct grub_tpm_digest *d;
+ unsigned int need, k;
+
+ if (!(pcr_bitmask & (1 << pcr)))
+ continue;
+
+ d = grub_tpm_read_pcr (pcr, algo);
+ if (d == NULL)
+ {
+ grub_error (GRUB_ERR_BAD_DEVICE, N_("unable to read PCR %d from TPM"), pcr);
+ continue;
+ }
+
+ /* We need room for the PCR index, 2 spaces, newline, NUL. 16 should be enough. */
+ need = 16 + grub_strlen(d->algorithm) + 2 * d->size;
+ if (wpos + need > size)
+ {
+ buffer = grub_realloc (buffer, size + need);
+ if (buffer == NULL)
+ return grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("Not enough memory when dumping PCR registers"));
+ }
+
+ grub_snprintf (buffer + wpos, size - wpos, "%02d %s ", pcr, d->algorithm);
+ wpos = grub_strlen(buffer);
+
+ for (k = 0; k < d->size; ++k)
+ {
+ grub_snprintf (buffer + wpos, size - wpos, "%02x", d->value[k]);
+ wpos += 2;
+ }
+
+ buffer[wpos++] = '\n';
+ buffer[wpos] = '\0';
+
+ grub_tpm_digest_free (d);
+ }
+
+ *buffer_ret = buffer;
+ *size_ret = wpos;
+
+ return GRUB_ERR_NONE;
+}
+
+static grub_err_t
+grub_tpm_write_pcrs_to_efi (void *data, grub_size_t size, const char *var_name)
+{
+ grub_efi_guid_t vendor_guid = { 0x7ce323f2, 0xb841, 0x4d30, { 0xa0, 0xe9, 0x54, 0x74, 0xa7, 0x6c, 0x9a, 0x3f }};
+ grub_err_t rc;
+
+ rc = grub_efi_set_variable_with_attributes(var_name, &vendor_guid,
+ GRUB_EFI_VARIABLE_BOOTSERVICE_ACCESS | GRUB_EFI_VARIABLE_RUNTIME_ACCESS,
+ data, size);
+
+ if (rc)
+ return grub_error (GRUB_ERR_BAD_DEVICE, N_("Failed to publish PCR snapshot to UEFI variable %s"), var_name);
+
+ return GRUB_ERR_NONE;
+}
+
+static grub_err_t
+grub_tpm_record_pcrs (grub_extcmd_context_t ctxt, int argc, char **args)
+{
+ struct grub_arg_list *state = ctxt->state;
+ grub_uint32_t pcr_bitmask = 0;
+ const char *efivar;
+ void *buffer = NULL;
+ grub_size_t size = 0;
+ int n, rv = 1;
+
+ if (argc == 0)
+ pcr_bitmask = GRUB2_PCR_BITMASK_DEFAULT;
+ else
+ {
+ for (n = 0; n < argc; ++n)
+ if (grub_tpm_parse_pcr_list (args[n], &pcr_bitmask))
+ return 1;
+ }
+
+ if (grub_tpm_snapshot_pcrs (pcr_bitmask, NULL, &buffer, &size))
+ goto out;
+
+ if (state[0].set)
+ efivar = state[0].arg;
+ else
+ efivar = "GrubPcrSnapshot";
+
+ if (grub_tpm_write_pcrs_to_efi (buffer, size, efivar))
+ goto out;
+
+ rv = 0;
+
+out:
+ if (buffer)
+ grub_free (buffer);
+ return rv;
+}
+
+static grub_extcmd_t cmd;
+
GRUB_MOD_INIT (tpm)
{
grub_verifier_register (&grub_tpm_verifier);
+
+ cmd = grub_register_extcmd ("tpm_record_pcrs", grub_tpm_record_pcrs, 0,
+ N_("LIST_OF_PCRS"),
+ N_("Snapshot one or more PCR values and record them in an EFI variable."),
+ grub_tpm_record_pcrs_options);
}
GRUB_MOD_FINI (tpm)
{
grub_verifier_unregister (&grub_tpm_verifier);
+ grub_unregister_extcmd (cmd);
}