Debrand for AlmaLinux

This commit is contained in:
Eduard Abdullin 2025-09-15 12:02:27 +00:00 committed by root
commit 1c1e46c10e
29 changed files with 9001 additions and 15 deletions

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,50 @@
From 1ff9d36ec874d5702be3815e74a71db7764c56ee Mon Sep 17 00:00:00 2001
From: "t.feng" <fengtao40@huawei.com>
Date: Tue, 29 Nov 2022 17:14:15 +0800
Subject: [PATCH 459/464] fs/xfs: Fix memory leaks in XFS module
Signed-off-by: t.feng <fengtao40@huawei.com>
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 17bf01f31ddb..8cf41d07c2ee 100644
--- a/grub-core/fs/xfs.c
+++ b/grub-core/fs/xfs.c
@@ -599,7 +599,10 @@ grub_xfs_read_block (grub_fshelp_node_t node, grub_disk_addr_t fileblock)
if (grub_disk_read (node->data->disk,
GRUB_XFS_FSB_TO_BLOCK (node->data, get_fsb (keys, i - 1 + recoffset)) << (node->data->sblock.log2_bsize - GRUB_DISK_SECTOR_BITS),
0, node->data->bsize, leaf))
- return 0;
+ {
+ grub_free (leaf);
+ return 0;
+ }
if ((!node->data->hascrc &&
grub_strncmp ((char *) leaf->magic, "BMAP", 4)) ||
@@ -790,6 +793,7 @@ static int iterate_dir_call_hook (grub_uint64_t ino, const char *filename,
if (err)
{
grub_print_error ();
+ grub_free (fdiro);
return 0;
}
@@ -907,7 +911,10 @@ grub_xfs_iterate_dir (grub_fshelp_node_t dir,
blk << dirblk_log2,
dirblk_size, dirblock, 0);
if (numread != dirblk_size)
- return 0;
+ {
+ grub_free (dirblock);
+ return 0;
+ }
entries = (grub_be_to_cpu32 (tail->leaf_count)
- grub_be_to_cpu32 (tail->leaf_stale));
--
2.46.1

View File

@ -0,0 +1,51 @@
From 270099a784d7dc0d251a8be1fed57e55f4dd4f8f Mon Sep 17 00:00:00 2001
From: Lidong Chen <lidong.chen@oracle.com>
Date: Thu, 28 Sep 2023 22:33:44 +0000
Subject: [PATCH 460/464] fs/xfs: Incorrect short form directory data boundary
check
After parsing of the current entry, the entry pointer is advanced
to the next entry at the end of the "for" loop. In case where the
last entry is at the end of the data boundary, the advanced entry
pointer can point off the data boundary. The subsequent boundary
check for the advanced entry pointer can cause a failure.
The fix is to include the boundary check into the "for" loop
condition.
Signed-off-by: Lidong Chen <lidong.chen@oracle.com>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
Tested-by: Sebastian Andrzej Siewior <sebastian@breakpoint.cc>
Tested-by: Marta Lewandowska <mlewando@redhat.com>
---
grub-core/fs/xfs.c | 7 ++-----
1 file changed, 2 insertions(+), 5 deletions(-)
diff --git a/grub-core/fs/xfs.c b/grub-core/fs/xfs.c
index 8cf41d07c2ee..a779eb6b8334 100644
--- a/grub-core/fs/xfs.c
+++ b/grub-core/fs/xfs.c
@@ -836,7 +836,8 @@ grub_xfs_iterate_dir (grub_fshelp_node_t dir,
if (iterate_dir_call_hook (parent, "..", &ctx))
return 1;
- for (i = 0; i < head->count; i++)
+ for (i = 0; i < head->count &&
+ (grub_uint8_t *) de < ((grub_uint8_t *) dir + grub_xfs_fshelp_size (dir->data)); i++)
{
grub_uint64_t ino;
grub_uint8_t *inopos = grub_xfs_inline_de_inopos(dir->data, de);
@@ -871,10 +872,6 @@ grub_xfs_iterate_dir (grub_fshelp_node_t dir,
de->name[de->len] = c;
de = grub_xfs_inline_next_de(dir->data, head, de);
-
- if ((grub_uint8_t *) de >= (grub_uint8_t *) dir + grub_xfs_fshelp_size (dir->data))
- return grub_error (GRUB_ERR_BAD_FS, "invalid XFS directory entry");
-
}
break;
}
--
2.46.1

View File

@ -0,0 +1,171 @@
From e5d18ae1b2b0ff58ce720dad90b3539aa2f28ee1 Mon Sep 17 00:00:00 2001
From: Jon DeVree <nuxi@vault24.org>
Date: Tue, 17 Oct 2023 23:03:47 -0400
Subject: [PATCH 461/464] fs/xfs: Fix XFS directory extent parsing
The XFS directory entry parsing code has never been completely correct
for extent based directories. The parser correctly handles the case
where the directory is contained in a single extent, but then mistakenly
assumes the data blocks for the multiple extent case are each identical
to the single extent case. The difference in the format of the data
blocks between the two cases is tiny enough that its gone unnoticed for
a very long time.
A recent change introduced some additional bounds checking into the XFS
parser. Like GRUB's existing parser, it is correct for the single extent
case but incorrect for the multiple extent case. When parsing a directory
with multiple extents, this new bounds checking is sometimes (but not
always) tripped and triggers an "invalid XFS directory entry" error. This
probably would have continued to go unnoticed but the /boot/grub/<arch>
directory is large enough that it often has multiple extents.
The difference between the two cases is that when there are multiple
extents, the data blocks do not contain a trailer nor do they contain
any leaf information. That information is stored in a separate set of
extents dedicated to just the leaf information. These extents come after
the directory entry extents and are not included in the inode size. So
the existing parser already ignores the leaf extents.
The only reason to read the trailer/leaf information at all is so that
the parser can avoid misinterpreting that data as directory entries. So
this updates the parser as follows:
For the single extent case the parser doesn't change much:
1. Read the size of the leaf information from the trailer
2. Set the end pointer for the parser to the start of the leaf
information. (The previous bounds checking set the end pointer to the
start of the trailer, so this is actually a small improvement.)
3. Set the entries variable to the expected number of directory entries.
For the multiple extent case:
1. Set the end pointer to the end of the block.
2. Do not set up the entries variable. Figuring out how many entries are
in each individual block is complex and does not seem worth it when
it appears to be safe to just iterate over the entire block.
The bounds check itself was also dependent upon the faulty XFS parser
because it accidentally used "filename + length - 1". Presumably this
was able to pass the fuzzer because in the old parser there was always
8 bytes of slack space between the tail pointer and the actual end of
the block. Since this is no longer the case the bounds check needs to be
updated to "filename + length + 1" in order to prevent a regression in
the handling of corrupt fliesystems.
Notes:
* When there is only one extent there will only ever be one block. If
more than one block is required then XFS will always switch to holding
leaf information in a separate extent.
* B-tree based directories seems to be parsed properly by the same code
that handles multiple extents. This is unlikely to ever occur within
/boot though because its only used when there are an extremely large
number of directory entries.
Fixes: ef7850c75 (fs/xfs: Fix issues found while fuzzing the XFS filesystem)
Fixes: b2499b29c (Adds support for the XFS filesystem.)
Fixes: https://savannah.gnu.org/bugs/?64376
Signed-off-by: Jon DeVree <nuxi@vault24.org>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
Tested-by: Sebastian Andrzej Siewior <sebastian@breakpoint.cc>
Tested-by: Marta Lewandowska <mlewando@redhat.com>
---
grub-core/fs/xfs.c | 52 +++++++++++++++++++++++++++++++++-------------
1 file changed, 38 insertions(+), 14 deletions(-)
diff --git a/grub-core/fs/xfs.c b/grub-core/fs/xfs.c
index a779eb6b8334..e178ffcdc290 100644
--- a/grub-core/fs/xfs.c
+++ b/grub-core/fs/xfs.c
@@ -223,6 +223,12 @@ struct grub_xfs_inode
/* Size of struct grub_xfs_inode v2, up to unused4 member included. */
#define XFS_V2_INODE_SIZE (XFS_V3_INODE_SIZE - 76)
+struct grub_xfs_dir_leaf_entry
+{
+ grub_uint32_t hashval;
+ grub_uint32_t address;
+} GRUB_PACKED;
+
struct grub_xfs_dirblock_tail
{
grub_uint32_t leaf_count;
@@ -900,9 +906,8 @@ grub_xfs_iterate_dir (grub_fshelp_node_t dir,
{
struct grub_xfs_dir2_entry *direntry =
grub_xfs_first_de(dir->data, dirblock);
- int entries;
- struct grub_xfs_dirblock_tail *tail =
- grub_xfs_dir_tail(dir->data, dirblock);
+ int entries = -1;
+ char *end = dirblock + dirblk_size;
numread = grub_xfs_read_file (dir, 0, 0,
blk << dirblk_log2,
@@ -913,14 +918,27 @@ grub_xfs_iterate_dir (grub_fshelp_node_t dir,
return 0;
}
- entries = (grub_be_to_cpu32 (tail->leaf_count)
- - grub_be_to_cpu32 (tail->leaf_stale));
+ /*
+ * 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))
+ {
+ 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);
- if (!entries)
- continue;
+ entries = grub_be_to_cpu32 (tail->leaf_count) - grub_be_to_cpu32 (tail->leaf_stale);
+
+ if (!entries)
+ continue;
+ }
/* Iterate over all entries within this block. */
- while ((char *)direntry < (char *)tail)
+ while ((char *) direntry < (char *) end)
{
grub_uint8_t *freetag;
char *filename;
@@ -940,7 +958,7 @@ grub_xfs_iterate_dir (grub_fshelp_node_t dir,
}
filename = (char *)(direntry + 1);
- if (filename + direntry->len - 1 > (char *) tail)
+ if (filename + direntry->len + 1 > (char *) end)
return grub_error (GRUB_ERR_BAD_FS, "invalid XFS directory entry");
/* The byte after the filename is for the filetype, padding, or
@@ -954,11 +972,17 @@ grub_xfs_iterate_dir (grub_fshelp_node_t dir,
return 1;
}
- /* Check if last direntry in this block is
- reached. */
- entries--;
- if (!entries)
- break;
+ /*
+ * 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))
+ {
+ /* Check if last direntry in this block is reached. */
+ entries--;
+ if (!entries)
+ break;
+ }
/* Select the next directory entry. */
direntry = grub_xfs_next_de(dir->data, direntry);
--
2.46.1

View File

@ -0,0 +1,119 @@
From 16ff7f17e65503ed53758ccc0245c1fabd444fb2 Mon Sep 17 00:00:00 2001
From: Anthony Iliopoulos <ailiop@suse.com>
Date: Thu, 26 Oct 2023 11:53:39 +0200
Subject: [PATCH 462/464] fs/xfs: Add large extent counters incompat feature
support
XFS introduced 64-bit extent counters for inodes via a series of
upstream commits and the feature was marked as stable in v6.5 via
commit 61d7e8274cd8 (xfs: drop EXPERIMENTAL tag for large extent
counts).
Further, xfsprogs release v6.5.0 switched this feature on by default
in mkfs.xfs via commit e5b18d7d1d96 (mkfs: enable large extent counts
by default).
Filesystems formatted with large extent count support, nrext64=1, are
thus currently not recognizable by GRUB, since this is an incompat
feature. Add the required support so that those filesystems and inodes
with large extent counters can be read by GRUB.
Signed-off-by: Anthony Iliopoulos <ailiop@suse.com>
Reviewed-by: Andrey Albershteyn <aalbersh@redhat.com>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
Tested-by: Marta Lewandowska <mlewando@redhat.com>
Tested-by: Sebastian Andrzej Siewior <sebastian@breakpoint.cc>
---
grub-core/fs/xfs.c | 30 +++++++++++++++++++++++++-----
1 file changed, 25 insertions(+), 5 deletions(-)
diff --git a/grub-core/fs/xfs.c b/grub-core/fs/xfs.c
index e178ffcdc290..70c9f449b133 100644
--- a/grub-core/fs/xfs.c
+++ b/grub-core/fs/xfs.c
@@ -79,6 +79,8 @@ GRUB_MOD_LICENSE ("GPLv3+");
/* Inode flags2 flags */
#define XFS_DIFLAG2_BIGTIME_BIT 3
#define XFS_DIFLAG2_BIGTIME (1 << XFS_DIFLAG2_BIGTIME_BIT)
+#define XFS_DIFLAG2_NREXT64_BIT 4
+#define XFS_DIFLAG2_NREXT64 (1 << XFS_DIFLAG2_NREXT64_BIT)
/* incompat feature flags */
#define XFS_SB_FEAT_INCOMPAT_FTYPE (1 << 0) /* filetype in dirent */
@@ -86,6 +88,7 @@ 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 */
/*
* Directory entries with ftype are explicitly handled by GRUB code.
@@ -101,7 +104,8 @@ GRUB_MOD_LICENSE ("GPLv3+");
XFS_SB_FEAT_INCOMPAT_SPINODES | \
XFS_SB_FEAT_INCOMPAT_META_UUID | \
XFS_SB_FEAT_INCOMPAT_BIGTIME | \
- XFS_SB_FEAT_INCOMPAT_NEEDSREPAIR)
+ XFS_SB_FEAT_INCOMPAT_NEEDSREPAIR | \
+ XFS_SB_FEAT_INCOMPAT_NREXT64)
struct grub_xfs_sblock
{
@@ -203,7 +207,8 @@ struct grub_xfs_inode
grub_uint16_t mode;
grub_uint8_t version;
grub_uint8_t format;
- grub_uint8_t unused2[26];
+ grub_uint8_t unused2[18];
+ grub_uint64_t nextents_big;
grub_uint64_t atime;
grub_uint64_t mtime;
grub_uint64_t ctime;
@@ -547,11 +552,26 @@ get_fsb (const void *keys, int idx)
return grub_be_to_cpu64 (grub_get_unaligned64 (p));
}
+static int
+grub_xfs_inode_has_large_extent_counts (const struct grub_xfs_inode *inode)
+{
+ return inode->version >= 3 &&
+ (inode->flags2 & grub_cpu_to_be64_compile_time (XFS_DIFLAG2_NREXT64));
+}
+
+static grub_uint64_t
+grub_xfs_get_inode_nextents (struct grub_xfs_inode *inode)
+{
+ return (grub_xfs_inode_has_large_extent_counts (inode)) ?
+ grub_be_to_cpu64 (inode->nextents_big) :
+ grub_be_to_cpu32 (inode->nextents);
+}
+
static grub_disk_addr_t
grub_xfs_read_block (grub_fshelp_node_t node, grub_disk_addr_t fileblock)
{
struct grub_xfs_btree_node *leaf = 0;
- int ex, nrec;
+ grub_uint64_t ex, nrec;
struct grub_xfs_extent *exts;
grub_uint64_t ret = 0;
@@ -576,7 +596,7 @@ grub_xfs_read_block (grub_fshelp_node_t node, grub_disk_addr_t fileblock)
/ (2 * sizeof (grub_uint64_t));
do
{
- int i;
+ grub_uint64_t i;
grub_addr_t keys_end, data_end;
if (grub_mul (sizeof (grub_uint64_t), nrec, &keys_end) ||
@@ -634,7 +654,7 @@ grub_xfs_read_block (grub_fshelp_node_t node, grub_disk_addr_t fileblock)
grub_addr_t exts_end = 0;
grub_addr_t data_end = 0;
- nrec = grub_be_to_cpu32 (node->inode.nextents);
+ nrec = grub_xfs_get_inode_nextents (&node->inode);
exts = (struct grub_xfs_extent *) grub_xfs_inode_data(&node->inode);
if (grub_mul (sizeof (struct grub_xfs_extent), nrec, &exts_end) ||
--
2.46.1

View File

@ -0,0 +1,57 @@
From 300b38fdf7036bf3b2f6244456e1adb3f9c1c359 Mon Sep 17 00:00:00 2001
From: Jon DeVree <nuxi@vault24.org>
Date: Sun, 11 Feb 2024 10:34:58 -0500
Subject: [PATCH 463/464] fs/xfs: Handle non-continuous data blocks in
directory extents
The directory extent list does not have to be a continuous list of data
blocks. When GRUB tries to read a non-existant member of the list,
grub_xfs_read_file() will return a block of zero'ed memory. Checking for
a zero'ed magic number is sufficient to skip this non-existant data block.
Prior to commit 07318ee7e (fs/xfs: Fix XFS directory extent parsing)
this was handled as a subtle side effect of reading the (non-existant)
tail data structure. Since the block was zero'ed the computation of the
number of directory entries in the block would return 0 as well.
Fixes: 07318ee7e (fs/xfs: Fix XFS directory extent parsing)
Fixes: https://bugzilla.redhat.com/show_bug.cgi?id=2254370
Signed-off-by: Jon DeVree <nuxi@vault24.org>
Reviewed-By: Vladimir Serbinenko <phcoder@gmail.com>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
---
grub-core/fs/xfs.c | 10 ++++++++++
1 file changed, 10 insertions(+)
diff --git a/grub-core/fs/xfs.c b/grub-core/fs/xfs.c
index 70c9f449b133..ab1281497472 100644
--- a/grub-core/fs/xfs.c
+++ b/grub-core/fs/xfs.c
@@ -928,6 +928,7 @@ grub_xfs_iterate_dir (grub_fshelp_node_t dir,
grub_xfs_first_de(dir->data, dirblock);
int entries = -1;
char *end = dirblock + dirblk_size;
+ grub_uint32_t magic;
numread = grub_xfs_read_file (dir, 0, 0,
blk << dirblk_log2,
@@ -938,6 +939,15 @@ grub_xfs_iterate_dir (grub_fshelp_node_t dir,
return 0;
}
+ /*
+ * If this data block isn't actually part of the extent list then
+ * grub_xfs_read_file() returns a block of zeros. So, if the magic
+ * number field is all zeros then this block should be skipped.
+ */
+ magic = *(grub_uint32_t *)(void *) dirblock;
+ if (!magic)
+ continue;
+
/*
* Leaf and tail information are only in the data block if the number
* of extents is 1.
--
2.46.1

View File

@ -0,0 +1,48 @@
From 6c6b8bebde2261aac2fbe7abd6d03008a5e06ce9 Mon Sep 17 00:00:00 2001
From: Eric Sandeen <sandeen@redhat.com>
Date: Wed, 4 Dec 2024 07:50:28 -0600
Subject: [PATCH 464/464] 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>
---
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 ab1281497472..c60db73613c5 100644
--- a/grub-core/fs/xfs.c
+++ b/grub-core/fs/xfs.c
@@ -952,7 +952,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)
{
struct grub_xfs_dirblock_tail *tail = grub_xfs_dir_tail (dir->data, dirblock);
@@ -1006,7 +1006,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.46.1

View File

@ -0,0 +1,167 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Sudhakar Kuppusamy <sudhakar@linux.ibm.com>
Date: Wed, 23 Oct 2024 17:54:32 +0530
Subject: [PATCH] grub-mkimage: Create new ELF note for SBAT
In order to store the SBAT data we create a new ELF note. The string
".sbat", zero-padded to 4 byte alignment, shall be entered in the name
field. The string "SBAT"'s ASCII values, 0x53424154, should be entered
in the type field.
Signed-off-by: Daniel Axtens <dja@axtens.net>
Signed-off-by: Sudhakar Kuppusamy <sudhakar@linux.ibm.com>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
---
include/grub/util/mkimage.h | 4 ++--
util/grub-mkimagexx.c | 48 +++++++++++++++++++++++++++++++++++++++++++--
util/mkimage.c | 5 +++--
3 files changed, 51 insertions(+), 6 deletions(-)
diff --git a/include/grub/util/mkimage.h b/include/grub/util/mkimage.h
index 6f1da89b9b65..881e3031f41f 100644
--- a/include/grub/util/mkimage.h
+++ b/include/grub/util/mkimage.h
@@ -51,12 +51,12 @@ grub_mkimage_load_image64 (const char *kernel_path,
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, size_t appsig_size, char **core_img, size_t *core_size,
+ int note, size_t appsig_size, char *sbat, 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, size_t appsig_size, char **core_img, size_t *core_size,
+ int note, size_t appsig_size, char *sbat, char **core_img, size_t *core_size,
Elf64_Addr target_addr,
struct grub_mkimage_layout *layout);
diff --git a/util/grub-mkimagexx.c b/util/grub-mkimagexx.c
index 393119486d3f..3609015673ec 100644
--- a/util/grub-mkimagexx.c
+++ b/util/grub-mkimagexx.c
@@ -115,6 +115,14 @@ struct section_metadata
const char *strtab;
};
+#define GRUB_SBAT_NOTE_NAME ".sbat"
+#define GRUB_SBAT_NOTE_TYPE 0x53424154 /* "SBAT" */
+
+struct grub_sbat_note {
+ Elf32_Nhdr header;
+ char name[ALIGN_UP(sizeof(GRUB_SBAT_NOTE_NAME), 4)];
+};
+
static int
is_relocatable (const struct grub_install_image_target_desc *image_target)
{
@@ -216,7 +224,7 @@ grub_arm_reloc_jump24 (grub_uint32_t *target, Elf32_Addr sym_addr)
void
SUFFIX (grub_mkimage_generate_elf) (const struct grub_install_image_target_desc *image_target,
- int note, size_t appsig_size, char **core_img, size_t *core_size,
+ int note, size_t appsig_size, char *sbat, char **core_img, size_t *core_size,
Elf_Addr target_addr,
struct grub_mkimage_layout *layout)
{
@@ -225,10 +233,17 @@ SUFFIX (grub_mkimage_generate_elf) (const struct grub_install_image_target_desc
Elf_Ehdr *ehdr;
Elf_Phdr *phdr;
Elf_Shdr *shdr;
- int header_size, footer_size = 0;
+ int header_size, footer_size = 0, footer_offset = 0;
int phnum = 1;
int shnum = 4;
int string_size = sizeof (".text") + sizeof ("mods") + 1;
+ char *footer;
+
+ if (sbat)
+ {
+ phnum++;
+ footer_size += ALIGN_UP (sizeof (struct grub_sbat_note) + layout->sbat_size, 4);
+ }
if (appsig_size)
{
@@ -262,6 +277,7 @@ SUFFIX (grub_mkimage_generate_elf) (const struct grub_install_image_target_desc
ehdr = (void *) elf_img;
phdr = (void *) (elf_img + sizeof (*ehdr));
shdr = (void *) (elf_img + sizeof (*ehdr) + phnum * sizeof (*phdr));
+ footer = elf_img + program_size + header_size;
memcpy (ehdr->e_ident, ELFMAG, SELFMAG);
ehdr->e_ident[EI_CLASS] = ELFCLASSXX;
if (!image_target->bigendian)
@@ -434,6 +450,8 @@ SUFFIX (grub_mkimage_generate_elf) (const struct grub_install_image_target_desc
phdr->p_filesz = grub_host_to_target32 (XEN_NOTE_SIZE);
phdr->p_memsz = 0;
phdr->p_offset = grub_host_to_target32 (header_size + program_size);
+ footer = ptr;
+ footer_offset = XEN_NOTE_SIZE;
}
if (image_target->id == IMAGE_XEN_PVH)
@@ -467,6 +485,8 @@ SUFFIX (grub_mkimage_generate_elf) (const struct grub_install_image_target_desc
phdr->p_filesz = grub_host_to_target32 (XEN_PVH_NOTE_SIZE);
phdr->p_memsz = 0;
phdr->p_offset = grub_host_to_target32 (header_size + program_size);
+ footer = ptr;
+ footer_offset = XEN_PVH_NOTE_SIZE;
}
if (note)
@@ -497,6 +517,30 @@ SUFFIX (grub_mkimage_generate_elf) (const struct grub_install_image_target_desc
phdr->p_filesz = grub_host_to_target32 (note_size);
phdr->p_memsz = 0;
phdr->p_offset = grub_host_to_target32 (header_size + program_size);
+ footer = (elf_img + program_size + header_size + note_size);
+ footer_offset += note_size;
+ }
+
+ if (sbat)
+ {
+ int note_size = ALIGN_UP (sizeof (struct grub_sbat_note) + layout->sbat_size, 4);
+ struct grub_sbat_note *note_ptr = (struct grub_sbat_note *) footer;
+
+ note_ptr->header.n_namesz = grub_host_to_target32 (sizeof (GRUB_SBAT_NOTE_NAME));
+ note_ptr->header.n_descsz = grub_host_to_target32 (ALIGN_UP(layout->sbat_size, 4));
+ note_ptr->header.n_type = grub_host_to_target32 (GRUB_SBAT_NOTE_TYPE);
+ memcpy (note_ptr->name, GRUB_SBAT_NOTE_NAME, sizeof (GRUB_SBAT_NOTE_NAME));
+ memcpy ((char *)(note_ptr + 1), sbat, layout->sbat_size);
+
+ 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 + footer_offset);
}
if (appsig_size) {
diff --git a/util/mkimage.c b/util/mkimage.c
index 9ba1a8988f19..358db8378422 100644
--- a/util/mkimage.c
+++ b/util/mkimage.c
@@ -1811,6 +1811,7 @@ grub_install_generate_image (const char *dir, const char *prefix,
case IMAGE_I386_IEEE1275:
{
grub_uint64_t target_addr;
+ char *sbat = NULL;
if (image_target->id == IMAGE_LOONGSON_ELF)
{
if (comp == GRUB_COMPRESSION_NONE)
@@ -1822,10 +1823,10 @@ grub_install_generate_image (const char *dir, const char *prefix,
else
target_addr = image_target->link_addr;
if (image_target->voidp_sizeof == 4)
- grub_mkimage_generate_elf32 (image_target, note, appsig_size, &core_img,
+ grub_mkimage_generate_elf32 (image_target, note, appsig_size, sbat, &core_img,
&core_size, target_addr, &layout);
else
- grub_mkimage_generate_elf64 (image_target, note, appsig_size, &core_img,
+ grub_mkimage_generate_elf64 (image_target, note, appsig_size, sbat, &core_img,
&core_size, target_addr, &layout);
}
break;

View File

@ -0,0 +1,45 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Sudhakar Kuppusamy <sudhakar@linux.ibm.com>
Date: Wed, 23 Oct 2024 17:54:33 +0530
Subject: [PATCH] grub-mkimage: Add SBAT metadata into ELF note for PowerPC
targets
The SBAT metadata is read from CSV file and transformed into an ELF note
with the -s option.
Signed-off-by: Daniel Axtens <dja@axtens.net>
Signed-off-by: Sudhakar Kuppusamy <sudhakar@linux.ibm.com>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
---
util/mkimage.c | 11 +++++++++--
1 file changed, 9 insertions(+), 2 deletions(-)
diff --git a/util/mkimage.c b/util/mkimage.c
index 358db8378422..eaa382b2a120 100644
--- a/util/mkimage.c
+++ b/util/mkimage.c
@@ -941,8 +941,8 @@ grub_install_generate_image (const char *dir, const char *prefix,
total_module_size += dtb_size + sizeof (struct grub_module_header);
}
- if (sbat_path != NULL && image_target->id != IMAGE_EFI)
- grub_util_error (_(".sbat section can be embedded into EFI images only"));
+ if (sbat_path != NULL && (image_target->id != IMAGE_EFI && image_target->id != IMAGE_PPC))
+ grub_util_error (_("SBAT data can be added only to EFI or powerpc-ieee1275 images"));
if (disable_shim_lock)
total_module_size += sizeof (struct grub_module_header);
@@ -1812,6 +1812,13 @@ grub_install_generate_image (const char *dir, const char *prefix,
{
grub_uint64_t target_addr;
char *sbat = NULL;
+ if (sbat_path != NULL)
+ {
+ sbat_size = grub_util_get_image_size (sbat_path);
+ sbat = xmalloc (sbat_size);
+ grub_util_load_image (sbat_path, sbat);
+ layout.sbat_size = sbat_size;
+ }
if (image_target->id == IMAGE_LOONGSON_ELF)
{
if (comp == GRUB_COMPRESSION_NONE)

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,200 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Sudhakar Kuppusamy <sudhakar@linux.ibm.com>
Date: Thu, 27 Mar 2025 01:02:35 +0530
Subject: [PATCH] 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.core.def | 1 +
grub-core/kern/powerpc/ieee1275/ieee1275.c | 140 +++++++++++++++++++++++++++++
include/grub/powerpc/ieee1275/ieee1275.h | 14 +++
3 files changed, 155 insertions(+)
create mode 100644 grub-core/kern/powerpc/ieee1275/ieee1275.c
diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def
index 3740330..05b9c8d 100644
--- a/grub-core/Makefile.core.def
+++ b/grub-core/Makefile.core.def
@@ -320,6 +320,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 0000000..f685afc
--- /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 3c7683f..45c7b16 100644
--- a/include/grub/powerpc/ieee1275/ieee1275.h
+++ b/include/grub/powerpc/ieee1275/ieee1275.h
@@ -25,4 +25,18 @@
#define GRUB_IEEE1275_CELL_SIZEOF 4
typedef grub_uint32_t grub_ieee1275_cell_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 */

View File

@ -0,0 +1,686 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Sudhakar Kuppusamy <sudhakar@linux.ibm.com>
Date: Thu, 27 Mar 2025 01:02:36 +0530
Subject: [PATCH] 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 | 332 +++++++++++++++++++++
include/grub/powerpc/ieee1275/platform_keystore.h | 225 ++++++++++++++
include/grub/types.h | 8 +
6 files changed, 580 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 dd49939..a398a04 100644
--- a/grub-core/Makefile.am
+++ b/grub-core/Makefile.am
@@ -245,6 +245,7 @@ KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/ieee1275/ieee1275.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 05b9c8d..218068b 100644
--- a/grub-core/Makefile.core.def
+++ b/grub-core/Makefile.core.def
@@ -325,6 +325,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 bb791f8..b853f04 100644
--- a/grub-core/kern/ieee1275/init.c
+++ b/grub-core/kern/ieee1275/init.c
@@ -47,6 +47,8 @@
#include <grub/machine/kernel.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__
@@ -956,7 +958,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;
grub_ieee1275_finddevice ("/", &root);
@@ -972,7 +974,16 @@ grub_get_ieee1275_secure_boot (void)
* We only support enforce.
*/
if (rc >= 0 && is_sb >= 2)
- grub_lockdown ();
+ {
+ grub_dprintf ("ieee1275", "Secure Boot Enabled\n");
+ rc = grub_pks_keystore_init ();
+ if (rc != GRUB_ERR_NONE)
+ grub_error (rc, "Initialization of the Platform Keystore failed!\n");
+
+ grub_lockdown ();
+ }
+ else
+ grub_dprintf ("ieee1275", "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 0000000..cf1d055
--- /dev/null
+++ b/grub-core/kern/powerpc/ieee1275/platform_keystore.c
@@ -0,0 +1,332 @@
+/*
+ * 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 grub_err_t
+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)
+ rc = grub_error (GRUB_ERR_BAD_FIRMWARE, "Firmware doesn't have PKS support!\n");
+ else
+ {
+ rc = grub_ieee1275_pks_max_object_size (&pks_max_object_size);
+ if (rc != GRUB_ERR_NONE)
+ rc = grub_error (GRUB_ERR_BAD_NUMBER, "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)
+ rc = grub_error (GRUB_ERR_READ_ERROR, "SB version read failed! (%d)\n", rc);
+ else if (len != 1 || (*data >= 2))
+ rc = grub_error (GRUB_ERR_BAD_NUMBER, "found unexpected SB version! (%d)\n", *data);
+
+ 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_dprintf ("ieee1275", "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_dprintf ("ieee1275", "dbx is not found in PKS\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 0000000..0641adb
--- /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 1587ff4..bfa7af9 100644
--- a/include/grub/types.h
+++ b/include/grub/types.h
@@ -345,4 +345,12 @@ static inline void grub_set_unaligned64 (void *ptr, grub_uint64_t val)
dd->d = val;
}
+#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 */

View File

@ -0,0 +1,764 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Sudhakar Kuppusamy <sudhakar@linux.ibm.com>
Date: Thu, 27 Mar 2025 01:02:37 +0530
Subject: [PATCH] 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 | 584 +++++++++++++++++++++++++--
grub-core/kern/file.c | 34 ++
include/grub/file.h | 1 +
3 files changed, 577 insertions(+), 42 deletions(-)
diff --git a/grub-core/commands/appendedsig/appendedsig.c b/grub-core/commands/appendedsig/appendedsig.c
index f4eefe5..994852f 100644
--- a/grub-core/commands/appendedsig/appendedsig.c
+++ b/grub-core/commands/appendedsig/appendedsig.c
@@ -34,7 +34,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+");
@@ -64,8 +64,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.
@@ -87,6 +102,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
{
@@ -95,6 +117,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)))
@@ -248,7 +468,7 @@ grub_verify_appended_signature (const grub_uint8_t *buf, grub_size_t bufsize)
struct pkcs7_signerInfo *si;
int i;
- if (!grub_trusted_key)
+ 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);
@@ -279,7 +499,7 @@ 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)
+ for (pk = db.keys; pk; pk = pk->next)
{
rc = grub_crypto_rsa_pad (&hashmpi, hash, si->hash, pk->mpis[0]);
if (rc)
@@ -376,16 +596,16 @@ grub_cmd_distrust (grub_command_t cmd __attribute__ ((unused)), int argc, char *
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)
@@ -432,8 +652,8 @@ grub_cmd_trust (grub_command_t cmd __attribute__ ((unused)), int argc, char **ar
}
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;
}
@@ -446,7 +666,7 @@ grub_cmd_list (grub_command_t cmd __attribute__ ((unused)), int argc __attribute
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);
@@ -539,6 +759,274 @@ static struct grub_fs pseudo_fs = { .name = "pseudo", .fs_read = pseudo_read };
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;
@@ -548,7 +1036,6 @@ 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_env_export ("check_appended_signatures");
@@ -556,37 +1043,50 @@ GRUB_MOD_INIT (appendedsig)
if (rc)
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;
+ 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;
- /* Not an X.509 certificate, 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_dprintf ("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_dprintf ("appendedsig", "the trusted list now has %" PRIuGRUB_SIZE " keys.\n"
+ "the distrusted list now has %" PRIuGRUB_SIZE " keys.\n",
+ db.signature_entries + db.key_entries, dbx.signature_entries);
+ }
- 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;
- }
+ grub_pks_free_keystore ();
+ }
cmd_trust = grub_register_command ("trust_certificate", grub_cmd_trust, N_("X509_CERTIFICATE"),
N_("Add X509_CERTIFICATE to trusted certificates."));
diff --git a/grub-core/kern/file.c b/grub-core/kern/file.c
index 58fae17..fa73c04 100644
--- a/grub-core/kern/file.c
+++ b/grub-core/kern/file.c
@@ -256,3 +256,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 d678de0..27e1a88 100644
--- a/include/grub/file.h
+++ b/include/grub/file.h
@@ -217,6 +217,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

View File

@ -0,0 +1,250 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Sudhakar Kuppusamy <sudhakar@linux.ibm.com>
Date: Thu, 27 Mar 2025 01:02:38 +0530
Subject: [PATCH] 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 | 193 +++++++++++++++++++--------
1 file changed, 139 insertions(+), 54 deletions(-)
diff --git a/grub-core/commands/appendedsig/appendedsig.c b/grub-core/commands/appendedsig/appendedsig.c
index 994852f..07d6b39 100644
--- a/grub-core/commands/appendedsig/appendedsig.c
+++ b/grub-core/commands/appendedsig/appendedsig.c
@@ -454,6 +454,83 @@ extract_appended_signature (const grub_uint8_t *buf, grub_size_t bufsize,
return parse_pkcs7_signedData (appsigdata, pkcs7_size, &sig->pkcs7);
}
+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)
{
@@ -463,12 +540,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);
@@ -476,69 +553,77 @@ 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)
{
- /*
- * 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)
+ err = grub_error (err, N_("failed to verify binary-hash/signature with any trusted binary-hash/key\n"));
+ pkcs7_signedData_release (&sig.pkcs7);
+ return err;
+ }
+ else if (err == GRUB_ERR_EOF)
+ {
+ /* 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)
- {
- err = grub_error (GRUB_ERR_BAD_SIGNATURE,
- N_("Error padding hash for RSA verification: %d"), rc);
- grub_free (context);
- goto cleanup;
- }
+ /*
+ * 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;
- rc = _gcry_pubkey_spec_rsa.verify (0, hashmpi, &si->sig_mpi, pk->mpis, NULL, NULL);
- gcry_mpi_release (hashmpi);
+ si->hash->init (context);
+ si->hash->write (context, buf, datasize);
+ si->hash->final (context);
+ hash = si->hash->read (context);
- 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",
+ "data size %" PRIxGRUB_SIZE ", signer %d hash %02x%02x%02x%02x...\n",
+ datasize, i, hash[0], hash[1], hash[2], hash[3]);
- grub_dprintf ("appendedsig", "verify signer %d with key '%s' failed with %d\n",
- i, pk->subject, rc);
- }
+ err = GRUB_ERR_BAD_SIGNATURE;
+ for (cert = db.keys; cert; cert = cert->next)
+ {
+ 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;
+ }
- grub_free (context);
+ 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;
+ }
- if (err == GRUB_ERR_NONE)
- break;
+ grub_dprintf ("appendedsig", "verify signer %d with key '%s' failed with %d\n",
+ i, cert->subject, rc);
+ }
+ 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);
+ if (err != GRUB_ERR_NONE)
+ err = grub_error (err, N_("failed to verify signature with any trusted key\n"));
+ else
+ grub_dprintf ("appendedsig", "successfully verified the signature with a trusted key\n");
+
return err;
}

View File

@ -0,0 +1,107 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Sudhakar Kuppusamy <sudhakar@linux.ibm.com>
Date: Thu, 27 Mar 2025 01:02:39 +0530
Subject: [PATCH] powerpc_ieee1275: set use_static_keys flag
Introduce the use_static_keys flag to indicate that static keys are to be used
rather than keys from the PKS storage's DB variable. This variable is set when
Secure Boot is enabled with PKS but the DB variable is not present in the PKS storage.
The appendedsig module would use this variable to extract the default DB keys from
the ELF note and store the keys found there in the trustedlist.
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/kern/powerpc/ieee1275/platform_keystore.c | 16 +++++++++++++++-
grub-core/term/tparm.c | 1 -
include/grub/powerpc/ieee1275/platform_keystore.h | 11 ++++++-----
include/grub/types.h | 2 ++
4 files changed, 23 insertions(+), 7 deletions(-)
diff --git a/grub-core/kern/powerpc/ieee1275/platform_keystore.c b/grub-core/kern/powerpc/ieee1275/platform_keystore.c
index cf1d055..a83fcf7 100644
--- a/grub-core/kern/powerpc/ieee1275/platform_keystore.c
+++ b/grub-core/kern/powerpc/ieee1275/platform_keystore.c
@@ -34,7 +34,11 @@
/* 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 };
+grub_pks_t grub_pks_keystore = { .db = NULL,
+ .dbx = NULL,
+ .db_entries = 0,
+ .dbx_entries = 0,
+ .use_static_keys = false };
/* Convert the esl data into the ESL */
static grub_esl_t *
@@ -312,6 +316,16 @@ grub_pks_keystore_init (void)
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 == PKS_OBJECT_NOT_FOUND)
+ {
+ rc = GRUB_ERR_NONE;
+ /*
+ * DB variable won't be available by default in PKS.
+ * So, it will load the Default Keys from ELF Note
+ */
+ grub_pks_keystore.use_static_keys = true;
+ }
+
if (rc == GRUB_ERR_NONE)
{
/* DBX */
diff --git a/grub-core/term/tparm.c b/grub-core/term/tparm.c
index fb5b15a..f2db325 100644
--- a/grub-core/term/tparm.c
+++ b/grub-core/term/tparm.c
@@ -46,7 +46,6 @@
/*
* Common/troublesome character definitions
*/
-typedef char grub_bool_t;
#ifndef FALSE
# define FALSE (0)
#endif
diff --git a/include/grub/powerpc/ieee1275/platform_keystore.h b/include/grub/powerpc/ieee1275/platform_keystore.h
index 0641adb..870fb8c 100644
--- a/include/grub/powerpc/ieee1275/platform_keystore.h
+++ b/include/grub/powerpc/ieee1275/platform_keystore.h
@@ -199,10 +199,11 @@ struct grub_pks_sd
/* 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_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_bool_t use_static_keys;/* flag to indicate use of static keys */
} GRUB_PACKED;
#ifdef __powerpc__
@@ -217,7 +218,7 @@ 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};
+grub_pks_t grub_pks_keystore = {NULL, NULL, 0, 0, false};
void grub_pks_free_keystore (void);
#endif
diff --git a/include/grub/types.h b/include/grub/types.h
index bfa7af9..32ca225 100644
--- a/include/grub/types.h
+++ b/include/grub/types.h
@@ -353,4 +353,6 @@ struct grub_uuid
grub_uint8_t b[GRUB_UUID_SIZE];
};
+typedef char grub_bool_t;
+
#endif /* ! GRUB_TYPES_HEADER */

View File

@ -0,0 +1,108 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Sudhakar Kuppusamy <sudhakar@linux.ibm.com>
Date: Thu, 27 Mar 2025 01:02:40 +0530
Subject: [PATCH] appendedsig: Reads the default DB keys from ELF Note
If Secure Boot is enabled with PKS and the use_static_keys flag is set,
then read the DB default keys from the ELF note and store them in the trusted list 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 | 56 ++++++++++++++++++++--------
1 file changed, 40 insertions(+), 16 deletions(-)
diff --git a/grub-core/commands/appendedsig/appendedsig.c b/grub-core/commands/appendedsig/appendedsig.c
index 07d6b39..f51942b 100644
--- a/grub-core/commands/appendedsig/appendedsig.c
+++ b/grub-core/commands/appendedsig/appendedsig.c
@@ -1041,7 +1041,7 @@ create_distrusted_list (void)
* parse it, and add it to the trusted list.
*/
static grub_err_t
-build_static_trusted_list (const struct grub_module_header *header)
+build_static_trusted_list (const struct grub_module_header *header, const grub_bool_t is_pks)
{
grub_err_t err = GRUB_ERR_NONE;
struct grub_file pseudo_file;
@@ -1060,6 +1060,13 @@ build_static_trusted_list (const struct grub_module_header *header)
if (err != GRUB_ERR_NONE)
return err;
+ if (is_pks)
+ {
+ err = is_distrusted_cert_hash (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);
@@ -1112,6 +1119,22 @@ free_distrusted_list (void)
grub_memset (&dbx, 0, sizeof (dbx));
}
+static grub_err_t
+load_static_keys (const struct grub_module_header *header, const grub_bool_t is_pks)
+{
+ int rc = GRUB_ERR_NONE;
+ FOR_MODULES (header)
+ {
+ /* Not an ELF module, skip. */
+ if (header->type != OBJ_TYPE_X509_PUBKEY)
+ continue;
+ rc = build_static_trusted_list (header, is_pks);
+ if (rc != GRUB_ERR_NONE)
+ return rc;
+ }
+ return rc;
+}
+
GRUB_MOD_INIT (appendedsig)
{
int rc;
@@ -1130,26 +1153,27 @@ GRUB_MOD_INIT (appendedsig)
if (!grub_pks_use_keystore && check_sigs == check_sigs_forced)
{
- FOR_MODULES (header)
+ rc = load_static_keys (header, false);
+ if (rc != GRUB_ERR_NONE)
{
- /* 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_dprintf ("appendedsig", "the trusted list now has %" PRIuGRUB_SIZE " static keys\n",
- db.key_entries);
+ free_trusted_list ();
+ grub_error (rc, "static trusted list creation failed");
}
+ else
+ grub_dprintf ("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 (grub_pks_keystore.use_static_keys)
+ {
+ grub_printf ("Warning: db variable is not available at PKS and using a static keys "
+ "as a default key in trusted list\n");
+ rc = load_static_keys (header, grub_pks_keystore.use_static_keys);
+ }
+ else
+ rc = create_trusted_list ();
+
if (rc != GRUB_ERR_NONE)
{
free_trusted_list ();

View File

@ -0,0 +1,660 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Sudhakar Kuppusamy <sudhakar@linux.ibm.com>
Date: Thu, 27 Mar 2025 01:02:41 +0530
Subject: [PATCH] appendedsig: The grub command's trusted and distrusted
support
To support the following trusted and distrusted commands
1. trusted_list:
It will show the list of trusted certificates and binary hashes
2. distrusted_list:
It will show the list of distrusted certificates and binary/certificate hashes
3. trusted_certificate:
It will add the trusted certificate to the trusted list
4. trusted_signature:
It will add the certificate/binary hash to the trusted list
5. distrusted_certificate:
It will remove the trusted certificate from trsuted list
6. distrusted_signature:
It will add the certificate/binary hash to the distrsuted list
Note:-
The addition/deletion of trusted certificates and binary hashes
are not allowed in grub command prompt while secure boot is enabled.
Signed-off-by: Sudhakar Kuppusamy <sudhakar@linux.ibm.com>
Reviewed-by: Avnish Chouhan <avnish@linux.ibm.com>
---
grub-core/commands/appendedsig/appendedsig.c | 528 ++++++++++++++++++---------
1 file changed, 356 insertions(+), 172 deletions(-)
diff --git a/grub-core/commands/appendedsig/appendedsig.c b/grub-core/commands/appendedsig/appendedsig.c
index f51942b..b8548f8 100644
--- a/grub-core/commands/appendedsig/appendedsig.c
+++ b/grub-core/commands/appendedsig/appendedsig.c
@@ -117,6 +117,36 @@ static enum
check_sigs_forced = 2
} check_sigs = check_sigs_no;
+enum
+{
+ OPTION_BINARY_HASH = 0,
+ OPTION_CERT_HASH = 1
+};
+
+static const struct grub_arg_option options[] =
+{
+ {"binary-hash", 'b', 0, N_("hash file of the binary."), 0, ARG_TYPE_NONE},
+ {"cert-hash", 'c', 1, N_("hash file of the certificate."), 0, ARG_TYPE_NONE},
+ {0, 0, 0, 0, 0, 0}
+};
+
+static void
+print_hex (const grub_uint8_t *data, const grub_size_t length)
+{
+ grub_size_t i, count = 0;
+ for (i = 0; i < length-1; i++)
+ {
+ grub_printf ("%02x:", data[i]);
+ count++;
+ if (count == 16)
+ {
+ grub_printf ("\n\t ");
+ count = 0;
+ }
+ }
+ grub_printf ("%02x\n", data[i]);
+}
+
/*
* GUID can be used to determine the hashing function and
* generate the hash using determined hashing function.
@@ -344,72 +374,6 @@ grub_env_write_sec (struct grub_env_var *var __attribute__ ((unused)), const cha
return grub_strdup (grub_env_read_sec (NULL, NULL));
}
-static grub_err_t
-file_read_all (grub_file_t file, grub_uint8_t **buf, grub_size_t *len)
-{
- grub_off_t full_file_size;
- grub_size_t file_size, total_read_size = 0;
- grub_ssize_t read_size;
-
- full_file_size = grub_file_size (file);
- if (full_file_size == GRUB_FILE_SIZE_UNKNOWN)
- return grub_error (GRUB_ERR_BAD_ARGUMENT,
- N_("Cannot read a file of unknown size into a buffer"));
-
- if (full_file_size > GRUB_SIZE_MAX)
- return grub_error (GRUB_ERR_OUT_OF_RANGE,
- N_("File is too large to read: %" PRIuGRUB_UINT64_T " bytes"),
- full_file_size);
-
- file_size = (grub_size_t) full_file_size;
-
- *buf = grub_malloc (file_size);
- if (!*buf)
- return grub_error (GRUB_ERR_OUT_OF_MEMORY,
- N_("Could not allocate file data buffer size %" PRIuGRUB_SIZE),
- file_size);
-
- while (total_read_size < file_size)
- {
- read_size = grub_file_read (file, *buf + total_read_size, file_size - total_read_size);
-
- if (read_size < 0)
- {
- grub_free (*buf);
- return grub_errno;
- }
- else if (read_size == 0)
- {
- grub_free (*buf);
- return grub_error (GRUB_ERR_IO,
- N_("Could not read full file size "
- "(%" PRIuGRUB_SIZE "), only %" PRIuGRUB_SIZE " bytes read"),
- file_size, total_read_size);
- }
-
- total_read_size += read_size;
- }
- *len = file_size;
- return GRUB_ERR_NONE;
-}
-
-static grub_err_t
-read_cert_from_file (grub_file_t f, struct x509_certificate *certificate)
-{
- grub_err_t err;
- grub_uint8_t *buf;
- grub_size_t file_size;
-
- err = file_read_all (f, &buf, &file_size);
- if (err != GRUB_ERR_NONE)
- return err;
-
- err = parse_x509_certificate (buf, file_size, certificate);
- grub_free (buf);
-
- return err;
-}
-
static grub_err_t
extract_appended_signature (const grub_uint8_t *buf, grub_size_t bufsize,
struct grub_appended_signature *sig)
@@ -630,143 +594,345 @@ grub_verify_appended_signature (const grub_uint8_t *buf, grub_size_t bufsize)
static grub_err_t
grub_cmd_verify_signature (grub_command_t cmd __attribute__ ((unused)), int argc, char **args)
{
- grub_file_t f;
grub_err_t err = GRUB_ERR_NONE;
- grub_uint8_t *data;
- grub_size_t file_size;
+ grub_file_t signed_file = NULL;
+ grub_uint8_t *signed_data = NULL;
+ grub_ssize_t signed_data_size = 0;
- if (argc < 1)
- return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("one argument expected"));
+ if (argc != 1)
+ {
+ grub_printf (N_("a signed file is expected\n"
+ "Example:\n\tverify_appended <SIGNED FILE>\n"));
+ return GRUB_ERR_BAD_ARGUMENT;
+ }
grub_dprintf ("appendedsig", "verifying %s\n", args[0]);
- f = grub_file_open (args[0], GRUB_FILE_TYPE_VERIFY_SIGNATURE);
- if (!f)
+ signed_file = grub_file_open (args[0], GRUB_FILE_TYPE_VERIFY_SIGNATURE);
+ if (signed_file == NULL)
+ return grub_error (GRUB_ERR_FILE_NOT_FOUND, N_("unable to open a signed file"));
+
+ err = grub_read_file (signed_file, &signed_data, &signed_data_size);
+ if (err != GRUB_ERR_NONE)
+ {
+ grub_file_close (signed_file);
+ return err;
+ }
+
+ grub_file_close (signed_file);
+ err = grub_verify_appended_signature (signed_data, signed_data_size);
+ grub_free (signed_data);
+
+ return err;
+}
+
+static grub_err_t
+grub_cmd_trusted_list (grub_command_t cmd __attribute__((unused)),
+ int argc __attribute__((unused)), char **args __attribute__((unused)))
+{
+ struct x509_certificate *cert = NULL;
+ grub_size_t i = 0, cert_num = 1;
+
+ for (cert = db.keys; cert; cert = cert->next)
+ {
+ grub_printf (N_("trusted certificate %" PRIuGRUB_SIZE ":\n"), cert_num);
+ grub_printf (N_("\tserial: "));
+
+ for (i = 0; i < cert->serial_len - 1; i++)
+ grub_printf ("%02x:", cert->serial[i]);
+
+ grub_printf ("%02x\n", cert->serial[cert->serial_len - 1]);
+ grub_printf ("\tCN: %s\n\n", cert->subject);
+ cert_num++;
+ }
+
+ for (i = 0; i < db.signature_entries; i++)
+ {
+ grub_printf (N_("trusted binary hash %" PRIuGRUB_SIZE ":\n"), i+1);
+ grub_printf (N_("\thash: "));
+ print_hex (db.signatures[i], db.signature_size[i]);
+ }
+
+ return GRUB_ERR_NONE;
+}
+
+static grub_err_t
+grub_cmd_distrusted_list (grub_command_t cmd __attribute__((unused)),
+ int argc __attribute__((unused)),
+ char **args __attribute__((unused)))
+{
+ struct x509_certificate *cert = NULL;
+ grub_size_t i = 0, cert_num = 1;
+
+ for (cert = dbx.keys; cert; cert = cert->next)
+ {
+ grub_printf (N_("distrusted certificate %" PRIuGRUB_SIZE ":\n"), cert_num);
+ grub_printf (N_("\tserial: "));
+
+ for (i = 0; i < cert->serial_len - 1; i++)
+ grub_printf ("%02x:", cert->serial[i]);
+
+ grub_printf ("%02x\n", cert->serial[cert->serial_len - 1]);
+ grub_printf ("\tCN: %s\n\n", cert->subject);
+ cert_num++;
+ }
+
+ for (i = 0; i < dbx.signature_entries; i++)
+ {
+ grub_printf (N_("distrusted certificate/binary hash %" PRIuGRUB_SIZE ":\n"), i+1);
+ grub_printf (N_("\thash: "));
+ print_hex (dbx.signatures[i], dbx.signature_size[i]);
+ }
+
+ return GRUB_ERR_NONE;
+}
+
+static grub_err_t
+grub_cmd_trusted_cert (grub_command_t cmd __attribute__((unused)),
+ int argc, char **args)
+{
+ grub_err_t err = GRUB_ERR_NONE;
+ grub_file_t cert_file = NULL;
+ grub_uint8_t *cert_data = NULL;
+ grub_ssize_t cert_data_size = 0;
+
+ if (argc != 1)
{
- err = grub_errno;
- goto cleanup;
+ grub_printf (N_("a trusted X.509 certificate file is expected\n"
+ "Example:\n\ttrusted_certificate <CERT FILE>\n"));
+ return GRUB_ERR_BAD_ARGUMENT;
}
- err = file_read_all (f, &data, &file_size);
+ if (check_sigs == check_sigs_forced)
+ {
+ grub_printf ("Warning: since secure boot is enabled, "
+ "adding of trusted X.509 certificate is not permitted!\n");
+ return grub_errno;
+ }
+
+ if (grub_strlen (args[0]) == 0)
+ return grub_error (GRUB_ERR_BAD_FILENAME,
+ N_("missing trusted X.509 certificate file"));
+
+ cert_file = grub_file_open (args[0], GRUB_FILE_TYPE_CERTIFICATE_TRUST |
+ GRUB_FILE_TYPE_NO_DECOMPRESS);
+ if (cert_file == NULL)
+ return grub_error (GRUB_ERR_FILE_NOT_FOUND,
+ N_("unable to open the trusted X.509 certificate file"));
+
+ err = grub_read_file (cert_file, &cert_data, &cert_data_size);
if (err != GRUB_ERR_NONE)
- goto cleanup;
+ {
+ grub_file_close (cert_file);
+ return err;
+ }
- err = grub_verify_appended_signature (data, file_size);
+ grub_file_close (cert_file);
+ err = add_certificate (cert_data, cert_data_size, &db, 1);
+ if (err != GRUB_ERR_NONE)
+ {
+ free_trusted_list ();
+ free_distrusted_list ();
+ grub_error (err, "adding of trusted certificate failed");
+ }
- grub_free (data);
+ grub_free (cert_data);
-cleanup:
- if (f)
- grub_file_close (f);
return err;
}
static grub_err_t
-grub_cmd_distrust (grub_command_t cmd __attribute__ ((unused)), int argc, char **args)
+grub_cmd_trusted_hash (grub_command_t cmd __attribute__((unused)), int argc, char**args)
{
- unsigned long cert_num, i;
- struct x509_certificate *cert, *prev;
+ grub_err_t rc = GRUB_ERR_NONE;
+ grub_file_t hash_file = NULL;
+ grub_uint8_t *hash_data = NULL;
+ grub_ssize_t hash_data_size = 0;
if (argc != 1)
- return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("One argument expected"));
+ {
+ grub_printf (N_("a trusted binary hash file is expected\n"
+ "Example:\n\ttrusted_signature <BINARY HASH FILE>\n"));
+ return GRUB_ERR_BAD_ARGUMENT;
+ }
+
+ if (check_sigs == check_sigs_forced)
+ {
+ grub_printf ("Warning: since secure boot is enabled, "
+ "adding of trusted binary hash is not permitted!\n");
+ return grub_errno;
+ }
+
+ if (grub_strlen (args[0]) == 0)
+ return grub_error (GRUB_ERR_BAD_FILENAME, N_("missing trusted binary hash file"));
+
+ hash_file = grub_file_open (args[0], GRUB_FILE_TYPE_TO_HASH | GRUB_FILE_TYPE_NO_DECOMPRESS);
+ if (hash_file == NULL)
+ return grub_error (GRUB_ERR_FILE_NOT_FOUND,
+ N_("unable to open the trusted binary hash file"));
+
+ rc = grub_read_file (hash_file, &hash_data, &hash_data_size);
+ if (rc != GRUB_ERR_NONE)
+ {
+ grub_file_close (hash_file);
+ return rc;
+ }
+
+ grub_file_close (hash_file);
+
+ grub_dprintf ("appendedsig", "adding a trusted binary hash %s\n with size of %" PRIuGRUB_SIZE "\n",
+ hash_data, hash_data_size);
+
+ /* only accept SHA256, SHA384 and SHA512 binary hash */
+ if (hash_data_size != 32 && hash_data_size != 48 && hash_data_size != 64)
+ return grub_error (GRUB_ERR_BAD_SIGNATURE, N_("unacceptable trusted binary hash type"));
+
+ rc = add_hash ((const grub_uint8_t **) &hash_data, hash_data_size, &db.signatures,
+ &db.signature_size, &db.signature_entries);
+ if (rc != GRUB_ERR_NONE)
+ {
+ free_trusted_list ();
+ free_distrusted_list ();
+ grub_error (rc, "adding of trusted binary hash failed");
+ }
+
+ grub_free (hash_data);
+
+ return rc;
+}
+
+static grub_err_t
+grub_cmd_distrusted_cert (grub_command_t cmd __attribute__((unused)), int argc, char **args)
+{
+ grub_size_t cert_num = 0, i = 1;
+ struct x509_certificate *current_cert = db.keys;
+ struct x509_certificate *previous_cert = db.keys;
+
+ if (argc != 1)
+ {
+ grub_printf (N_("trusted certificate number is expected\n"
+ "Example:\n\tdistrusted_certificate <CERT_NUMER>\n"));
+ return GRUB_ERR_BAD_ARGUMENT;
+ }
+
+ if (check_sigs == check_sigs_forced)
+ {
+ grub_printf ("Warning: since secure boot is enabled, "
+ "removing of trusted certificate is not permitted!\n");
+ return grub_errno;
+ }
- grub_errno = GRUB_ERR_NONE;
cert_num = grub_strtoul (args[0], NULL, 10);
- if (grub_errno != GRUB_ERR_NONE)
- return grub_errno;
-
if (cert_num < 1)
return grub_error (GRUB_ERR_BAD_ARGUMENT,
- N_("Certificate number too small - numbers start at 1"));
+ N_("trusted certificate number should to begin with 1"));
- if (cert_num == 1)
- {
- cert = db.keys;
- db.keys = cert->next;
+ if (cert_num > db.key_entries)
+ return grub_error (GRUB_ERR_BAD_ARGUMENT,
+ N_("trusted certificate number should not exceed %" PRIuGRUB_SIZE ""),
+ db.key_entries);
+ else if (cert_num < db.key_entries)
+ return grub_error (GRUB_ERR_BAD_ARGUMENT,
+ N_("there is no certificate on the trusted list. so, not permitted"));
- certificate_release (cert);
- grub_free (cert);
- return GRUB_ERR_NONE;
- }
- i = 2;
- prev = db.keys;
- cert = db.keys->next;
- while (cert)
+ for (i = 1; i < db.key_entries; i++)
{
- if (i == cert_num)
+ if (cert_num == 1)
+ {
+ previous_cert = current_cert->next;
+ break;
+ }
+ else if (cert_num == i)
{
- prev->next = cert->next;
- certificate_release (cert);
- grub_free (cert);
- return GRUB_ERR_NONE;
+ previous_cert->next = current_cert->next;
+ break;
}
- i++;
- prev = cert;
- cert = cert->next;
+
+ previous_cert = current_cert;
+ current_cert = current_cert->next;
}
- return grub_error (GRUB_ERR_BAD_ARGUMENT,
- N_("No certificate number %lu found - only %lu certificates in the store"),
- cert_num, i - 1);
+ certificate_release (current_cert);
+ grub_free (current_cert);
+
+ return GRUB_ERR_NONE;
}
static grub_err_t
-grub_cmd_trust (grub_command_t cmd __attribute__ ((unused)), int argc, char **args)
+grub_cmd_distrusted_hash (grub_extcmd_context_t ctxt, int argc, char **args)
{
- grub_file_t certf;
- struct x509_certificate *cert = NULL;
- grub_err_t err;
+ grub_err_t rc = GRUB_ERR_NONE;
+ grub_file_t hash_file = NULL;
+ grub_uint8_t *hash_data = NULL;
+ grub_ssize_t hash_data_size = 0;
- if (argc != 1)
- return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("one argument expected"));
-
- certf = grub_file_open (args[0], GRUB_FILE_TYPE_CERTIFICATE_TRUST | GRUB_FILE_TYPE_NO_DECOMPRESS);
- if (!certf)
- return grub_errno;
-
- cert = grub_zalloc (sizeof (struct x509_certificate));
- if (!cert)
- return grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("Could not allocate memory for certificate"));
+ if (argc != 2)
+ {
+ grub_printf (N_("a distrusted certificate/binary hash file is expected\n"
+ "Example:\n\tdistrusted_signature [option] <FILE>\n"
+ "option:\n[-b|--binary-hash] FILE [BINARY HASH FILE]\n"
+ "[-c|--cert-hash] FILE [CERTFICATE HASH FILE]\n"));
+ return GRUB_ERR_BAD_ARGUMENT;
+ }
- err = read_cert_from_file (certf, cert);
- grub_file_close (certf);
- if (err != GRUB_ERR_NONE)
+ if (check_sigs == check_sigs_forced)
{
- grub_free (cert);
- return err;
+ grub_printf ("Warning: since secure boot is enabled, "
+ "adding of distrusted certificate/binary hash is not permitted!\n");
+ return grub_errno;
}
- grub_dprintf ("appendedsig", "Loaded certificate with CN: %s\n", cert->subject);
- cert->next = db.keys;
- db.keys = cert;
+ if (!ctxt->state[OPTION_BINARY_HASH].set && !ctxt->state[OPTION_CERT_HASH].set)
+ return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("missing options and use --help to konw"));
- return GRUB_ERR_NONE;
-}
+ if (grub_strlen (args[1]) == 0)
+ return grub_error (GRUB_ERR_BAD_FILENAME,
+ N_("missing distrusted certificate/binary hash file"));
-static grub_err_t
-grub_cmd_list (grub_command_t cmd __attribute__ ((unused)), int argc __attribute__ ((unused)),
- char **args __attribute__ ((unused)))
-{
- struct x509_certificate *cert;
- int cert_num = 1;
- grub_size_t i;
+ hash_file = grub_file_open (args[1], GRUB_FILE_TYPE_TO_HASH | GRUB_FILE_TYPE_NO_DECOMPRESS);
+ if (hash_file == NULL)
+ return grub_error (GRUB_ERR_FILE_NOT_FOUND,
+ N_("unable to open the distrusted certificate/binary hash file"));
- for (cert = db.keys; cert; cert = cert->next)
+ rc = grub_read_file (hash_file, &hash_data, &hash_data_size);
+ if (rc != GRUB_ERR_NONE)
{
- grub_printf (N_("Certificate %d:\n"), cert_num);
+ grub_file_close (hash_file);
+ return rc;
+ }
- grub_printf (N_("\tSerial: "));
- for (i = 0; i < cert->serial_len - 1; i++)
- {
- grub_printf ("%02x:", cert->serial[i]);
- }
- grub_printf ("%02x\n", cert->serial[cert->serial_len - 1]);
+ grub_file_close (hash_file);
- grub_printf ("\tCN: %s\n\n", cert->subject);
- cert_num++;
+ grub_dprintf ("appendedsig", "adding a distrusted certificate/binary hash %s\n"
+ " with size of %" PRIuGRUB_SIZE "\n", hash_data, hash_data_size);
+
+ if (ctxt->state[OPTION_BINARY_HASH].set)
+ {
+ /* only accept SHA256, SHA384 and SHA512 binary hash */
+ if (hash_data_size != 32 && hash_data_size != 48 && hash_data_size != 64)
+ return grub_error (GRUB_ERR_BAD_SIGNATURE,
+ N_("unacceptable distrusted binary hash type"));
+ }
+ else if (ctxt->state[OPTION_CERT_HASH].set)
+ {
+ /* only accept SHA256, SHA384 and SHA512 certificate hash */
+ if (hash_data_size != 32 && hash_data_size != 48 && hash_data_size != 64)
+ return grub_error (GRUB_ERR_BAD_SIGNATURE,
+ N_("unacceptable distrusted certificate hash type"));
}
- return GRUB_ERR_NONE;
+ rc = add_hash ((const grub_uint8_t **) &hash_data, hash_data_size, &dbx.signatures,
+ &dbx.signature_size, &dbx.signature_entries);
+ if (rc != GRUB_ERR_NONE)
+ {
+ free_trusted_list ();
+ free_distrusted_list ();
+ grub_error (rc, "adding of distrusted binary/certificate hash failed");
+ }
+
+ grub_free (hash_data);
+
+ return rc;
}
static grub_err_t
@@ -842,8 +1008,6 @@ pseudo_read (struct grub_file *file, char *buf, grub_size_t len)
/* Filesystem descriptor. */
static struct grub_fs pseudo_fs = { .name = "pseudo", .fs_read = pseudo_read };
-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.
@@ -1135,6 +1299,10 @@ load_static_keys (const struct grub_module_header *header, const grub_bool_t is_
return rc;
}
+static grub_extcmd_t cmd_distrusted_hash;
+static grub_command_t cmd_verify, cmd_trusted_list, cmd_trusted_cert, cmd_trusted_hash,
+ cmd_distrusted_list, cmd_distrusted_cert;
+
GRUB_MOD_INIT (appendedsig)
{
int rc;
@@ -1196,17 +1364,31 @@ GRUB_MOD_INIT (appendedsig)
grub_pks_free_keystore ();
}
-
- cmd_trust = grub_register_command ("trust_certificate", grub_cmd_trust, N_("X509_CERTIFICATE"),
- N_("Add X509_CERTIFICATE to trusted certificates."));
- cmd_list = grub_register_command ("list_certificates", grub_cmd_list, 0,
- N_("Show the list of trusted x509 certificates."));
+ cmd_trusted_cert = grub_register_command ("trusted_certificate", grub_cmd_trusted_cert,
+ N_("X509_CERTIFICATE"),
+ N_("Add X509_CERTIFICATE to trusted list."));
+ cmd_trusted_hash = grub_register_command ("trusted_signature", grub_cmd_trusted_hash,
+ N_("BINARY HASH FILE"),
+ N_("Add trusted BINARY HASH to trusted list."));
+ cmd_distrusted_cert = grub_register_command ("distrusted_certificate", grub_cmd_distrusted_cert,
+ N_("CERT_NUMBER"),
+ N_("Remove CERT_NUMBER (as listed by list_trusted)"
+ " from trusted list."));
+ cmd_distrusted_hash = grub_register_extcmd ("distrusted_signature", grub_cmd_distrusted_hash, 0,
+ N_("[-b|--binary-hash] FILE [BINARY HASH FILE]\n"
+ "[-c|--cert-hash] FILE [CERTFICATE HASH FILE]"),
+ N_("Add distrusted CERTFICATE/BINARY HASH "
+ "to distrusted list."),
+ options);
+ cmd_trusted_list = grub_register_command ("trusted_list", grub_cmd_trusted_list, 0,
+ N_("Show the list of trusted x509 certificates and"
+ " trusted binary hashes."));
+ cmd_distrusted_list = grub_register_command ("distrusted_list", grub_cmd_distrusted_list, 0,
+ N_("Show the list of distrusted certificates and"
+ " certificate/binary hashes"));
cmd_verify = grub_register_command ("verify_appended", grub_cmd_verify_signature, N_("FILE"),
- N_("Verify FILE against the trusted x509 certificates."));
- cmd_distrust = grub_register_command ("distrust_certificate", grub_cmd_distrust,
- N_("CERT_NUMBER"),
- N_("Remove CERT_NUMBER (as listed by list_certificates)"
- " from trusted certificates."));
+ N_("Verify FILE against the trusted x509 certificates/"
+ "trusted binary hashes."));
grub_verifier_register (&grub_appendedsig_verifier);
grub_dl_set_persistent (mod);
@@ -1218,10 +1400,12 @@ GRUB_MOD_FINI (appendedsig)
* grub_dl_set_persistent should prevent this from actually running, but
* it does still run under emu.
*/
-
grub_verifier_unregister (&grub_appendedsig_verifier);
grub_unregister_command (cmd_verify);
- grub_unregister_command (cmd_list);
- grub_unregister_command (cmd_trust);
- grub_unregister_command (cmd_distrust);
+ grub_unregister_command (cmd_trusted_list);
+ grub_unregister_command (cmd_distrusted_list);
+ grub_unregister_command (cmd_trusted_cert);
+ grub_unregister_command (cmd_distrusted_cert);
+ grub_unregister_command (cmd_trusted_hash);
+ grub_unregister_extcmd (cmd_distrusted_hash);
}

View File

@ -0,0 +1,210 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Sudhakar Kuppusamy <sudhakar@linux.ibm.com>
Date: Thu, 27 Mar 2025 01:02:42 +0530
Subject: [PATCH] appendedsig: documentation
This explains how static and dynamic key appended signatures can be used to form part of
a secure boot chain, and documents the commands and variables introduced.
Signed-off-by: Sudhakar Kuppusamy <sudhakar@linux.ibm.com>
Reviewed-by: Avnish Chouhan <avnish@linux.ibm.com>
---
docs/grub.texi | 109 +++++++++++++++++++++++++++++++++++++++------------------
1 file changed, 74 insertions(+), 35 deletions(-)
diff --git a/docs/grub.texi b/docs/grub.texi
index 72cf517..a4ae8cd 100644
--- a/docs/grub.texi
+++ b/docs/grub.texi
@@ -4016,7 +4016,9 @@ you forget a command, you can run the command @command{help}
* date:: Display or set current date and time
* devicetree:: Load a device tree blob
* distrust:: Remove a pubkey from trusted keys
-* distrust_certificate:: Remove a certificate from the list of trusted certificates
+* distrusted_certificate:: Remove a certificate from the trusted list
+* distrusted_list:: List distrusted certificates and binary/certificate hashes
+* distrusted_signature:: Add a binary hash to the distrusted list
* drivemap:: Map a drive to another
* echo:: Display a line of text
* eval:: Evaluate agruments as GRUB commands
@@ -4033,7 +4035,6 @@ you forget a command, you can run the command @command{help}
* keystatus:: Check key modifier status
* linux:: Load a Linux kernel
* linux16:: Load a Linux kernel (16-bit mode)
-* list_certificates:: List trusted certificates
* list_env:: List variables in environment block
* list_trusted:: List trusted public keys
* load_env:: Load variables from environment block
@@ -4072,7 +4073,9 @@ you forget a command, you can run the command @command{help}
* test:: Check file types and compare values
* true:: Do nothing, successfully
* trust:: Add public key to list of trusted keys
-* trust_certificate:: Add an x509 certificate to the list of trusted certificates
+* trusted_certificate:: Add an x509 certificate to the trusted list
+* trusted_list:: List trusted certificates and binary hashes
+* trusted_signature:: Add a binary hash to the trusted list.
* unset:: Unset an environment variable
@comment * vbeinfo:: List available video modes
* verify_appended:: Verify appended digital signature
@@ -4416,16 +4419,15 @@ These keys are used to validate signatures when environment variable
GPG-style digital signatures}, for more information.
@end deffn
+@node distrusted_certificate
+@subsection distrusted_certificate
-@node distrust_certificate
-@subsection distrust_certificate
-
-@deffn Command distrust_certificate cert_number
+@deffn Command distrusted_certificate cert_number
Remove the x509 certificate numbered @var{cert_number} from GRUB's keyring of
trusted x509 certificates for verifying appended signatures.
@var{cert_number} is the certificate number as listed by
-@command{list_certificates} (@pxref{list_certificates}).
+@command{trusted_list} (@pxref{trusted_list}).
These certificates are used to validate appended signatures when environment
variable @code{check_appended_signatures} is set to @code{enforce} or
@@ -4434,6 +4436,27 @@ variable @code{check_appended_signatures} is set to @code{enforce} or
@xref{Using appended signatures} for more information.
@end deffn
+@node distrusted_list
+@subsection distrusted_list
+
+@deffn Command distrusted_list
+List all the distrusted x509 certificates and binary/certificate hashes.
+The output is a numbered list of certificates and binary/certificate hashes,
+showing the certificate's serial number and Common Name.
+@end deffn
+
+@node distrusted_signature
+@subsection distrusted_signature
+
+@deffn Command distrusted_signature
+Read a binary hash from the file @var{binary hash file}
+and add it to GRUB's internal distrusted list. These hash are used to
+restrict validation of linux image integrity using trusted list if appended
+signatures validation failed when the environment variable
+@code{check_appended_signatures} is set to @code{enforce}.
+
+See @xref{Using appended signatures} for more information.
+@end deffn
@node drivemap
@subsection drivemap
@@ -4691,22 +4714,6 @@ for the sake of convenience.
This command is only available on x86 systems.
@end deffn
-
-@node list_certificates
-@subsection list_certificates
-
-@deffn Command list_certificates
-List all x509 certificates trusted by GRUB for validating appended signatures.
-The output is a numbered list of certificates, showing the certificate's serial
-number and Common Name.
-
-The certificate number can be used as an argument to
-@command{distrust_certificate} (@pxref{distrust_certificate}).
-
-See @xref{Using appended signatures} for more information.
-@end deffn
-
-
@node list_env
@subsection list_env
@@ -5540,10 +5547,10 @@ information.
@end deffn
-@node trust_certificate
-@subsection trust_certificate
+@node trusted_certificate
+@subsection trusted_certificate
-@deffn Command trust_certificate x509_certificate
+@deffn Command trusted_certificate x509_certificate
Read an DER-formatted x509 certificate from the file @var{x509_certificate}
and add it to GRUB's internal list of trusted x509 certificates. These
certificates are used to validate appended signatures when the environment
@@ -5551,7 +5558,7 @@ variable @code{check_appended_signatures} is set to @code{enforce} or
@code{forced}.
Note that if @code{check_appended_signatures} is set to @code{enforce} or
-@code{forced} when @command{trust_certificate} is executed, then
+@code{forced} when @command{trusted_certificate} is executed, then
@var{x509_certificate} must itself bear an appended signature. (It is not
sufficient that @var{x509_certificate} be signed by a trusted certificate
according to the x509 rules: grub does not include support for validating
@@ -5560,6 +5567,32 @@ signatures within x509 certificates themselves.)
See @xref{Using appended signatures} for more information.
@end deffn
+@node trusted_list
+@subsection trusted_list
+
+@deffn Command trusted_list
+List all x509 certificates and binary hases trusted by GRUB for validating
+appended signatures. The output is a numbered list of certificates and binary
+hashes, showing the certificate's serial number and Common Name.
+
+The certificate number can be used as an argument to
+@command{distrusted_certificate} (@pxref{distrusted_certificate}).
+
+See @xref{Using appended signatures} for more information.
+@end deffn
+
+@node trusted_signature
+@subsection trusted_signature
+
+@deffn Command trust_signature
+Read a binary hash from the file @var{binary hash file}
+and add it to GRUB's internal trusted list. These binary hash are used to
+validate linux image integrity if appended signatures validation failed
+when the environment variable @code{check_appended_signatures} is set
+to @code{enforce}.
+
+See @xref{Using appended signatures} for more information.
+@end deffn
@node unset
@subsection unset
@@ -5584,9 +5617,8 @@ only on PC BIOS platforms.
@deffn Command verify_appended file
Verifies an appended signature on @var{file} against the trusted certificates
-known to GRUB (See @pxref{list_certificates}, @pxref{trust_certificate}, and
-@pxref{distrust_certificate}).
-
+known to GRUB (See @pxref{trusted_list}, @pxref{trusted_certificate}, and
+@pxref{distrusted_certificate}).
Exit code @code{$?} is set to 0 if the signature validates
successfully. If validation fails, it is set to a non-zero value.
See @xref{Using appended signatures}, for more information.
@@ -6183,10 +6215,17 @@ with an appended signature ends with the magic string:
where @code{\n} represents the line-feed character, @code{0x0a}.
-Certificates can be managed at boot time using the @pxref{trust_certificate},
-@pxref{distrust_certificate} and @pxref{list_certificates} commands.
-Certificates can also be built in to the core image using the @code{--x509}
-parameter to @command{grub-install} or @command{grub-mkimage}.
+For static key, Certificates will be built in to the core image using
+the @code{--x509} parameter to @command{grub-install} or @command{grub-mkimage}.
+it can allow to list the trusted certificates and binary hashes at boot time using
+@pxref{trusted_list} and list distrusted certificates and binary/certificate hashes
+at boot time using @pxref{distrusted_list} commands.
+
+For dynamic key, loads the signature database (DB) and forbidden
+signature database (DBX) from platform keystore (PKS) and it can allow to list
+the trusted certificates and binary hashes at boot time using @pxref{trusted_list}
+and list distrusted certificates and binary/certificate hashes at boot time using
+@pxref{distrusted_list} commands.
A file can be explictly verified using the @pxref{verify_appended} command.

View File

@ -0,0 +1,301 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Glenn Washburn <development@efficientek.com>
Date: Fri, 22 Jul 2022 02:16:33 -0500
Subject: [PATCH] efi: Add efitextmode command for getting/setting the text
mode resolution
This command is meant to behave similarly to the "mode" command of the EFI
Shell application. In addition to allowing mode selection by giving the
number of columns and rows as arguments, the command allows specifying the
mode number to select the mode. Also supported are the arguments "min" and
"max", which set the mode to the minimum and maximum mode respectively as
calculated by the columns * rows of that mode.
Signed-off-by: Glenn Washburn <development@efficientek.com>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
---
docs/grub.texi | 42 ++++++++++
grub-core/Makefile.core.def | 6 ++
grub-core/commands/efi/efitextmode.c | 155 +++++++++++++++++++++++++++++++++++
include/grub/efi/api.h | 6 ++
include/grub/err.h | 1 +
5 files changed, 210 insertions(+)
create mode 100644 grub-core/commands/efi/efitextmode.c
diff --git a/docs/grub.texi b/docs/grub.texi
index a4ae8cd..2677059 100644
--- a/docs/grub.texi
+++ b/docs/grub.texi
@@ -4021,6 +4021,7 @@ you forget a command, you can run the command @command{help}
* distrusted_signature:: Add a binary hash to the distrusted list
* drivemap:: Map a drive to another
* echo:: Display a line of text
+* efitextmode:: Set/Get text output mode resolution
* eval:: Evaluate agruments as GRUB commands
* export:: Export an environment variable
* false:: Do nothing, unsuccessfully
@@ -4527,6 +4528,47 @@ character will print that character.
@end deffn
+@node efitextmode
+@subsection efitextmode
+
+@deffn Command efitextmode [min | max | <mode_num> | <cols> <rows>]
+When used with no arguments displays all available text output modes. The
+set mode determines the columns and rows of the text display when in
+text mode. An asterisk, @samp{*}, will be at the end of the line of the
+currently set mode.
+
+If given a single parameter, it must be @samp{min}, @samp{max}, or a mode
+number given by the listing when run with no arguments. These arguments set
+the mode to the minimum, maximum, and particular mode respectively.
+
+Otherwise, the command must be given two numerical arguments specifying the
+columns and rows of the desired mode. Specifying a columns and rows
+combination that corresponds to no supported mode, will return error, but
+otherwise have no effect.
+
+By default GRUB will start in whatever mode the EFI firmware defaults to.
+There are firmwares known to set up the default mode such that output
+behaves strangely, for example the cursor in the GRUB shell never reaches
+the bottom of the screen or, when typing characters at the prompt,
+characters from previous command output are overwritten. Setting the mode
+may fix this.
+
+The EFI specification says that mode 0 must be available and have
+columns and rows of 80 and 25 respectively. Mode 1 may be defined and if
+so must have columns and rows of 80 and 50 respectively. Any other modes
+may have columns and rows arbitrarily defined by the firmware. This means
+that a mode with columns and rows of 100 and 31 on one firmware may be
+a different mode number on a different firmware or not exist at all.
+Likewise, mode number 2 on one firmware may have a different number of
+columns and rows than mode 2 on a different firmware. So one should not
+rely on a particular mode number or a mode of a certain number of columns
+and rows existing on all firmwares, except for mode 0.
+
+Note: This command is only available on EFI platforms and is similar to
+EFI shell "mode" command.
+@end deffn
+
+
@node eval
@subsection eval
diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def
index 218068b..4588fa7 100644
--- a/grub-core/Makefile.core.def
+++ b/grub-core/Makefile.core.def
@@ -844,6 +844,12 @@ module = {
enable = efi;
};
+module = {
+ name = efitextmode;
+ efi = commands/efi/efitextmode.c;
+ enable = efi;
+};
+
module = {
name = blocklist;
common = commands/blocklist.c;
diff --git a/grub-core/commands/efi/efitextmode.c b/grub-core/commands/efi/efitextmode.c
new file mode 100644
index 0000000..3679f6b
--- /dev/null
+++ b/grub-core/commands/efi/efitextmode.c
@@ -0,0 +1,155 @@
+/*
+ * GRUB -- GRand Unified Bootloader
+ * 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/>.
+ *
+ * Set/Get UEFI text output mode resolution.
+ */
+
+#include <grub/dl.h>
+#include <grub/misc.h>
+#include <grub/mm.h>
+#include <grub/command.h>
+#include <grub/i18n.h>
+#include <grub/efi/efi.h>
+#include <grub/efi/api.h>
+
+GRUB_MOD_LICENSE ("GPLv3+");
+
+static grub_err_t
+grub_efi_set_mode (grub_efi_simple_text_output_interface_t *o,
+ grub_efi_int32_t mode)
+{
+ grub_efi_status_t status;
+
+ if (mode != o->mode->mode)
+ {
+ status = efi_call_2 (o->set_mode, o, mode);
+ if (status == GRUB_EFI_SUCCESS)
+ ;
+ else if (status == GRUB_EFI_DEVICE_ERROR)
+ return grub_error (GRUB_ERR_BAD_DEVICE,
+ N_("device error: could not set requested mode"));
+ else if (status == GRUB_EFI_UNSUPPORTED)
+ return grub_error (GRUB_ERR_OUT_OF_RANGE,
+ N_("invalid mode: number not valid"));
+ else
+ return grub_error (GRUB_ERR_BAD_FIRMWARE,
+ N_("unexpected EFI error number: `%u'"),
+ (unsigned) status);
+ }
+
+ return GRUB_ERR_NONE;
+}
+
+static grub_err_t
+grub_cmd_efitextmode (grub_command_t cmd __attribute__ ((unused)),
+ int argc, char **args)
+{
+ grub_efi_simple_text_output_interface_t *o = grub_efi_system_table->con_out;
+ unsigned long mode;
+ const char *p = NULL;
+ grub_err_t err;
+ grub_efi_uintn_t columns, rows;
+ grub_efi_int32_t i;
+
+ if (o == NULL)
+ return grub_error (GRUB_ERR_BAD_DEVICE, N_("no UEFI output console interface"));
+
+ if (o->mode == NULL)
+ return grub_error (GRUB_ERR_BUG, N_("no mode struct for UEFI output console"));
+
+ if (argc > 2)
+ return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("at most two arguments expected"));
+
+ if (argc == 0)
+ {
+ grub_printf_ (N_("Available modes for console output device.\n"));
+
+ for (i = 0; i < o->mode->max_mode; i++)
+ if (GRUB_EFI_SUCCESS == efi_call_4 (o->query_mode, o, i,
+ &columns, &rows))
+ grub_printf_ (N_(" [%" PRIuGRUB_EFI_UINT32_T "] Col %5"
+ PRIuGRUB_EFI_UINTN_T " Row %5" PRIuGRUB_EFI_UINTN_T
+ " %c\n"),
+ i, columns, rows, (i == o->mode->mode) ? '*' : ' ');
+ }
+ else if (argc == 1)
+ {
+ if (grub_strcmp (args[0], "min") == 0)
+ mode = 0;
+ else if (grub_strcmp (args[0], "max") == 0)
+ mode = o->mode->max_mode - 1;
+ else
+ {
+ mode = grub_strtoul (args[0], &p, 0);
+
+ if (*args[0] == '\0' || *p != '\0')
+ return grub_error (GRUB_ERR_BAD_ARGUMENT,
+ N_("non-numeric or invalid mode `%s'"), args[0]);
+ }
+
+ if (mode < (unsigned long) o->mode->max_mode)
+ {
+ err = grub_efi_set_mode (o, (grub_efi_int32_t) mode);
+ if (err != GRUB_ERR_NONE)
+ return err;
+ }
+ else
+ return grub_error (GRUB_ERR_BAD_ARGUMENT,
+ N_("invalid mode: `%lu' is greater than maximum mode `%lu'"),
+ mode, (unsigned long) o->mode->max_mode);
+ }
+ else if (argc == 2)
+ {
+ grub_efi_uintn_t u_columns, u_rows;
+
+ u_columns = (grub_efi_uintn_t) grub_strtoul (args[0], &p, 0);
+
+ if (*args[0] == '\0' || *p != '\0')
+ return grub_error (GRUB_ERR_BAD_ARGUMENT,
+ N_("non-numeric or invalid columns number `%s'"), args[0]);
+
+ u_rows = (grub_efi_uintn_t) grub_strtoul (args[1], &p, 0);
+
+ if (*args[1] == '\0' || *p != '\0')
+ return grub_error (GRUB_ERR_BAD_ARGUMENT,
+ N_("non-numeric or invalid rows number `%s'"), args[1]);
+
+ for (i = 0; i < o->mode->max_mode; i++)
+ if (GRUB_EFI_SUCCESS == efi_call_4 (o->query_mode, o, i,
+ &columns, &rows))
+ if (u_columns == columns && u_rows == rows)
+ return grub_efi_set_mode (o, (grub_efi_int32_t) i);
+
+ return grub_error (GRUB_ERR_BAD_ARGUMENT,
+ N_("no mode found with requested columns and rows"));
+ }
+
+ return GRUB_ERR_NONE;
+}
+
+static grub_command_t cmd;
+GRUB_MOD_INIT (efitextmode)
+{
+ cmd = grub_register_command ("efitextmode", grub_cmd_efitextmode,
+ N_("[min | max | <mode_num> | <cols> <rows>]"),
+ N_("Get or set EFI text mode."));
+}
+
+GRUB_MOD_FINI (efitextmode)
+{
+ grub_unregister_command (cmd);
+}
diff --git a/include/grub/efi/api.h b/include/grub/efi/api.h
index 464842b..f224037 100644
--- a/include/grub/efi/api.h
+++ b/include/grub/efi/api.h
@@ -545,9 +545,13 @@ typedef char grub_efi_boolean_t;
#if GRUB_CPU_SIZEOF_VOID_P == 8
typedef grub_int64_t grub_efi_intn_t;
typedef grub_uint64_t grub_efi_uintn_t;
+#define PRIxGRUB_EFI_UINTN_T PRIxGRUB_UINT64_T
+#define PRIuGRUB_EFI_UINTN_T PRIuGRUB_UINT64_T
#else
typedef grub_int32_t grub_efi_intn_t;
typedef grub_uint32_t grub_efi_uintn_t;
+#define PRIxGRUB_EFI_UINTN_T PRIxGRUB_UINT32_T
+#define PRIuGRUB_EFI_UINTN_T PRIuGRUB_UINT32_T
#endif
typedef grub_int8_t grub_efi_int8_t;
typedef grub_uint8_t grub_efi_uint8_t;
@@ -555,6 +559,8 @@ typedef grub_int16_t grub_efi_int16_t;
typedef grub_uint16_t grub_efi_uint16_t;
typedef grub_int32_t grub_efi_int32_t;
typedef grub_uint32_t grub_efi_uint32_t;
+#define PRIxGRUB_EFI_UINT32_T PRIxGRUB_UINT32_T
+#define PRIuGRUB_EFI_UINT32_T PRIuGRUB_UINT32_T
typedef grub_int64_t grub_efi_int64_t;
typedef grub_uint64_t grub_efi_uint64_t;
typedef grub_uint8_t grub_efi_char8_t;
diff --git a/include/grub/err.h b/include/grub/err.h
index 905a6df..7530f58 100644
--- a/include/grub/err.h
+++ b/include/grub/err.h
@@ -73,6 +73,7 @@ typedef enum
GRUB_ERR_NET_NO_DOMAIN,
GRUB_ERR_EOF,
GRUB_ERR_BAD_SIGNATURE,
+ GRUB_ERR_BAD_FIRMWARE,
GRUB_ERR_STILL_REFERENCED,
GRUB_ERR_RECURSION_DEPTH
}

View File

@ -0,0 +1,45 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Leo Sandoval <lsandova@redhat.com>
Date: Wed, 7 May 2025 13:23:37 -0600
Subject: [PATCH] 10_linux.in: escape kernel option characters properly
This handles cases where kernel options, specifically the values,
contain special characters, in this case ';', '&' and '$'.
For example, the user defines the following GRUB_CMDLINE_LINUX on the
default grub file /etc/default/grub, note the dolar sign on the 'memmap'
option
GRUB_CMDLINE_LINUX="console=ttyS0 memmap=32g\\\$0x2000000000"
then regenerating the grub cfg and BLS options line with the
grub2-mkconfig command, resulting into
options root=UUID=6baedf23-2510-499a-815d-48b58cf6e619 ro
rootflags=subvol=root console=ttyS0 memmap=32g\$0x2000000000
without this patch, we would end up with
options root=UUID=6baedf23-2510-499a-815d-48b58cf6e619 ro
rootflags=subvol=root console=ttyS0 memmap=32g$0x2000000000
Note the missing '\' which is required to escape the '$', otherwise
it would be consider a variable by blscfg parser which is not the case.
Signed-off-by: Leo Sandoval <lsandova@redhat.com>
---
util/grub.d/10_linux.in | 1 +
1 file changed, 1 insertion(+)
diff --git a/util/grub.d/10_linux.in b/util/grub.d/10_linux.in
index fafdfbc4d3..4276d5e240 100755
--- a/util/grub.d/10_linux.in
+++ b/util/grub.d/10_linux.in
@@ -180,6 +180,7 @@ update_bls_cmdline()
options="$(echo "${options}" | sed -e 's/\//\\\//g')"
options="$(echo "${options}" | sed -e 's/\;/\\\;/g')"
options="$(echo "${options}" | sed -e 's/\\&/\\\\&/g')"
+ options="$(echo "${options}" | sed -e 's/\$/\\\$/g')"
sed -i -e "s/^options.*/options ${options}/" "${blsdir}/${bls}.conf"
done
}

View File

@ -0,0 +1,26 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Leo Sandoval <lsandova@redhat.com>
Date: Wed, 7 May 2025 13:49:47 -0600
Subject: [PATCH] blscfg: check if variable is escaped before considering one
Otherwise escaped variables are considered real variables.
Signed-off-by: Leo Sandoval <lsandova@redhat.com>
---
grub-core/commands/blscfg.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/grub-core/commands/blscfg.c b/grub-core/commands/blscfg.c
index 6e398fc175..5d931b0c9b 100644
--- a/grub-core/commands/blscfg.c
+++ b/grub-core/commands/blscfg.c
@@ -695,7 +695,8 @@ static char *expand_val(const char *value)
return NULL;
while (*value) {
- if (*value == '$') {
+ /* It's a variable only when *value is '$' and it is not escaped with '\'*/
+ if (*value == '$' && *end != '\\') {
if (start != end) {
buffer = field_append(is_var, buffer, start, end);
if (!buffer)

View File

@ -0,0 +1,86 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Renaud=20M=C3=A9trich?= <rmetrich@redhat.com>
Date: Thu, 24 Apr 2025 11:43:28 +0200
Subject: [PATCH] osdep/linux/getroot: Detect DDF container similar to IMSM
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Similarly to Intel IMSM, there are BIOS and UEFI implementations that
support DDF containers natively.
DDF and IMSM are very similar in handling, especially these should not
be considered as RAID abstraction. This fixes the requirement of having
a device map when probing DDF containers.
Fixes: https://issues.redhat.com/browse/RHEL-44336
Signed-off-by: Renaud Métrich <rmetrich@redhat.com>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
---
grub-core/osdep/linux/getroot.c | 19 +++++++++++++------
1 file changed, 13 insertions(+), 6 deletions(-)
diff --git a/grub-core/osdep/linux/getroot.c b/grub-core/osdep/linux/getroot.c
index 893527a..7430391 100644
--- a/grub-core/osdep/linux/getroot.c
+++ b/grub-core/osdep/linux/getroot.c
@@ -131,7 +131,7 @@ struct btrfs_ioctl_search_args {
struct btrfs_ioctl_fs_info_args)
static int
-grub_util_is_imsm (const char *os_dev);
+grub_util_is_imsm_or_ddf (const char *os_dev);
#define ESCAPED_PATH_MAX (4 * PATH_MAX)
@@ -762,10 +762,10 @@ out:
}
static int
-grub_util_is_imsm (const char *os_dev)
+grub_util_is_imsm_or_ddf (const char *os_dev)
{
int retry;
- int is_imsm = 0;
+ int is_imsm_or_ddf = 0;
int container_seen = 0;
const char *dev = os_dev;
@@ -826,10 +826,17 @@ grub_util_is_imsm (const char *os_dev)
if (strncmp (buf, "MD_METADATA=imsm",
sizeof ("MD_METADATA=imsm") - 1) == 0)
{
- is_imsm = 1;
+ is_imsm_or_ddf = 1;
grub_util_info ("%s is imsm", dev);
break;
}
+ if (strncmp (buf, "MD_METADATA=ddf",
+ sizeof ("MD_METADATA=ddf") - 1) == 0)
+ {
+ is_imsm_or_ddf = 1;
+ grub_util_info ("%s is ddf", dev);
+ break;
+ }
}
free (buf);
@@ -840,7 +847,7 @@ grub_util_is_imsm (const char *os_dev)
if (dev != os_dev)
free ((void *) dev);
- return is_imsm;
+ return is_imsm_or_ddf;
}
char *
@@ -1205,7 +1212,7 @@ grub_util_get_dev_abstraction_os (const char *os_dev)
/* Check for RAID. */
if (!strncmp (os_dev, "/dev/md", 7) && ! grub_util_device_is_mapped (os_dev)
- && !grub_util_is_imsm (os_dev))
+ && !grub_util_is_imsm_or_ddf (os_dev))
return GRUB_DEV_ABSTRACTION_RAID;
return GRUB_DEV_ABSTRACTION_NONE;
}

View File

@ -0,0 +1,342 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Leo Sandoval <lsandova@redhat.com>
Date: Mon, 28 Jul 2025 12:37:06 -0600
Subject: [PATCH] Set correctly the memory attributes for the kernel PE
sections
Currently the whole kernel memory region is set to RO, so at some
point when execution is passed to the kernel, the latter faults on a
memory write access, e.g. zeroing .bss section. The proposed change
sets the memory attribute appropriately for each kernel PE section.
Signed-off-by: Leo Sandoval <lsandova@redhat.com>
---
grub-core/loader/arm64/linux.c | 2 +-
grub-core/loader/efi/linux.c | 165 ++++++++++++++++++++++++++++----------
grub-core/loader/i386/efi/linux.c | 5 +-
include/grub/efi/linux.h | 7 ++
include/grub/efi/pe32.h | 28 +++++++
5 files changed, 161 insertions(+), 46 deletions(-)
diff --git a/grub-core/loader/arm64/linux.c b/grub-core/loader/arm64/linux.c
index a3a193c255..c03e602974 100644
--- a/grub-core/loader/arm64/linux.c
+++ b/grub-core/loader/arm64/linux.c
@@ -182,7 +182,7 @@ grub_arch_efi_linux_boot_image (grub_addr_t addr, grub_size_t size, char *args,
grub_dprintf ("linux", "linux command line: '%s'\n", args);
- retval = grub_efi_linux_boot (addr, size, handover_offset,
+ retval = grub_efi_linux_boot (addr, size, 0, handover_offset,
(void *)addr, nx_supported);
/* Never reached... */
diff --git a/grub-core/loader/efi/linux.c b/grub-core/loader/efi/linux.c
index e413bdcc23..4d7cd3c624 100644
--- a/grub-core/loader/efi/linux.c
+++ b/grub-core/loader/efi/linux.c
@@ -24,6 +24,7 @@
#include <grub/efi/efi.h>
#include <grub/efi/pe32.h>
#include <grub/efi/linux.h>
+#include <grub/safemath.h>
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wcast-align"
@@ -133,20 +134,130 @@ grub_efi_check_nx_required (int *nx_required)
typedef void (*handover_func) (void *, grub_efi_system_table_t *, void *);
grub_err_t
-grub_efi_linux_boot (grub_addr_t kernel_addr, grub_size_t kernel_size,
+grub_efi_mem_set_att (grub_addr_t kernel_address, grub_size_t kernel_size,
+ grub_size_t kernel_start, int nx_supported)
+{
+ grub_addr_t kernel_start_address = kernel_address + kernel_start;
+
+ grub_uint64_t default_set_attrs = GRUB_MEM_ATTR_R | GRUB_MEM_ATTR_W | GRUB_MEM_ATTR_X;
+ grub_uint64_t default_clear_attrs = 0;
+ grub_uint64_t stack_set_attrs = default_set_attrs;
+ grub_uint64_t stack_clear_attrs = default_clear_attrs;
+ grub_uint64_t kernel_set_attrs = default_set_attrs;
+ grub_uint64_t kernel_clear_attrs = default_clear_attrs;
+ grub_uint64_t attrs;
+
+ struct grub_msdos_image_header *header;
+ struct grub_pe_image_header *pe_image_header;
+ struct grub_pe32_coff_header *coff_header;
+ struct grub_pe32_section_table *section, *sections;
+ grub_uint16_t i;
+ grub_size_t sz;
+
+ header = (struct grub_msdos_image_header *)kernel_address;
+
+ if (grub_add ((grub_addr_t) header, header->pe_image_header_offset, &sz))
+ return grub_error (GRUB_ERR_OUT_OF_RANGE, N_("Error on PE image header address calculation"));
+
+ pe_image_header = (struct grub_pe_image_header *) (sz);
+
+ if (pe_image_header > (kernel_address + kernel_size))
+ return grub_error (GRUB_ERR_BAD_OS, N_("PE image header address is invalid"));
+
+ if (grub_memcmp (pe_image_header->signature, GRUB_PE32_SIGNATURE,
+ GRUB_PE32_SIGNATURE_SIZE) != 0)
+ return grub_error (GRUB_ERR_BAD_OS, N_("kernel PE magic is invalid"));
+
+ coff_header = &(pe_image_header->coff_header);
+ grub_dprintf ("nx", "coff_header 0x%"PRIxGRUB_ADDR" machine %08x\n", (grub_addr_t)coff_header, coff_header->machine);
+
+ if (grub_add ((grub_addr_t) coff_header, sizeof (*coff_header), &sz) ||
+ grub_add (sz, coff_header->optional_header_size, &sz))
+ return grub_error (GRUB_ERR_OUT_OF_RANGE, N_("Error on PE sections calculation"));
+
+ sections = (struct grub_pe32_section_table *) (sz);
+
+ if (sections > (kernel_address + kernel_size))
+ return grub_error (GRUB_ERR_BAD_OS, N_("Section address is invalid"));
+
+ /* Parse the PE, remove W for code section, remove X for data sections, RO for the rest */
+ for (i = 0, section = sections; i < coff_header->num_sections; i++, section++)
+ {
+ kernel_set_attrs = default_set_attrs;
+ kernel_clear_attrs = default_clear_attrs;
+
+ if (nx_supported)
+ {
+ if (section->characteristics & GRUB_PE32_SCN_MEM_EXECUTE)
+ {
+ /* RX section */
+ kernel_set_attrs &= ~GRUB_MEM_ATTR_W;
+ kernel_clear_attrs |= GRUB_MEM_ATTR_W;
+ }
+ else if (section->characteristics & GRUB_PE32_SCN_MEM_WRITE)
+ {
+ /* RW section */
+ kernel_set_attrs &= ~GRUB_MEM_ATTR_X;
+ kernel_clear_attrs |= GRUB_MEM_ATTR_X;
+ }
+ else
+ {
+ /* RO section */
+ kernel_set_attrs &= ~GRUB_MEM_ATTR_W & ~GRUB_MEM_ATTR_X;
+ kernel_clear_attrs |= GRUB_MEM_ATTR_X | GRUB_MEM_ATTR_W ;
+ }
+ }
+
+ /* Make sure we are inside range */
+ if (grub_add ((grub_addr_t) kernel_address, section->raw_data_offset, &sz))
+ return grub_error (GRUB_ERR_OUT_OF_RANGE, N_("Error on PE Executable section calculation"));
+
+ grub_update_mem_attrs (sz, section->raw_data_size, kernel_set_attrs, kernel_clear_attrs);
+
+ grub_get_mem_attrs (sz, 4096, &attrs);
+ grub_dprintf ("nx", "permissions for section %s 0x%"PRIxGRUB_ADDR" are %s%s%s\n",
+ section->name,
+ (grub_addr_t)sz,
+ (attrs & GRUB_MEM_ATTR_R) ? "r" : "-",
+ (attrs & GRUB_MEM_ATTR_W) ? "w" : "-",
+ (attrs & GRUB_MEM_ATTR_X) ? "x" : "-");
+ }
+
+ if (grub_stack_addr != (grub_addr_t)-1ll)
+ {
+ if (nx_supported)
+ {
+ stack_set_attrs &= ~GRUB_MEM_ATTR_X;
+ stack_clear_attrs |= GRUB_MEM_ATTR_X;
+ }
+
+ grub_dprintf ("nx", "Setting attributes for stack at 0x%"PRIxGRUB_ADDR"-0x%"PRIxGRUB_ADDR" to rw%c\n",
+ grub_stack_addr, grub_stack_addr + grub_stack_size - 1,
+ (stack_set_attrs & GRUB_MEM_ATTR_X) ? 'x' : '-');
+
+ grub_update_mem_attrs (grub_stack_addr, grub_stack_size,
+ stack_set_attrs, stack_clear_attrs);
+
+ grub_get_mem_attrs (grub_stack_addr, 4096, &attrs);
+ grub_dprintf ("nx", "permissions for 0x%"PRIxGRUB_ADDR" are %s%s%s\n",
+ grub_stack_addr,
+ (attrs & GRUB_MEM_ATTR_R) ? "r" : "-",
+ (attrs & GRUB_MEM_ATTR_W) ? "w" : "-",
+ (attrs & GRUB_MEM_ATTR_X) ? "x" : "-");
+ }
+
+ return GRUB_ERR_NONE;
+}
+
+grub_err_t
+grub_efi_linux_boot (grub_addr_t kernel_addr, grub_size_t kernel_size, grub_size_t kernel_start,
grub_off_t handover_offset, void *kernel_params,
int nx_supported)
{
+ grub_addr_t kernel_start_address = kernel_addr + kernel_start;
grub_efi_loaded_image_t *loaded_image = NULL;
handover_func hf;
int offset = 0;
- grub_uint64_t stack_set_attrs = GRUB_MEM_ATTR_R |
- GRUB_MEM_ATTR_W |
- GRUB_MEM_ATTR_X;
- grub_uint64_t stack_clear_attrs = 0;
- grub_uint64_t kernel_set_attrs = stack_set_attrs;
- grub_uint64_t kernel_clear_attrs = stack_clear_attrs;
- grub_uint64_t attrs;
int nx_required = 0;
#ifdef __x86_64__
@@ -171,41 +282,7 @@ grub_efi_linux_boot (grub_addr_t kernel_addr, grub_size_t kernel_size,
if (nx_required && !nx_supported)
return grub_error (GRUB_ERR_BAD_OS, N_("kernel does not support NX loading required by policy"));
- if (nx_supported)
- {
- kernel_set_attrs &= ~GRUB_MEM_ATTR_W;
- kernel_clear_attrs |= GRUB_MEM_ATTR_W;
- stack_set_attrs &= ~GRUB_MEM_ATTR_X;
- stack_clear_attrs |= GRUB_MEM_ATTR_X;
- }
-
- grub_dprintf ("nx", "Setting attributes for 0x%"PRIxGRUB_ADDR"-0x%"PRIxGRUB_ADDR" to r%cx\n",
- kernel_addr, kernel_addr + kernel_size - 1,
- (kernel_set_attrs & GRUB_MEM_ATTR_W) ? 'w' : '-');
- grub_update_mem_attrs (kernel_addr, kernel_size,
- kernel_set_attrs, kernel_clear_attrs);
-
- grub_get_mem_attrs (kernel_addr, 4096, &attrs);
- grub_dprintf ("nx", "permissions for 0x%"PRIxGRUB_ADDR" are %s%s%s\n",
- (grub_addr_t)kernel_addr,
- (attrs & GRUB_MEM_ATTR_R) ? "r" : "-",
- (attrs & GRUB_MEM_ATTR_W) ? "w" : "-",
- (attrs & GRUB_MEM_ATTR_X) ? "x" : "-");
- if (grub_stack_addr != (grub_addr_t)-1ll)
- {
- grub_dprintf ("nx", "Setting attributes for stack at 0x%"PRIxGRUB_ADDR"-0x%"PRIxGRUB_ADDR" to rw%c\n",
- grub_stack_addr, grub_stack_addr + grub_stack_size - 1,
- (stack_set_attrs & GRUB_MEM_ATTR_X) ? 'x' : '-');
- grub_update_mem_attrs (grub_stack_addr, grub_stack_size,
- stack_set_attrs, stack_clear_attrs);
-
- grub_get_mem_attrs (grub_stack_addr, 4096, &attrs);
- grub_dprintf ("nx", "permissions for 0x%"PRIxGRUB_ADDR" are %s%s%s\n",
- grub_stack_addr,
- (attrs & GRUB_MEM_ATTR_R) ? "r" : "-",
- (attrs & GRUB_MEM_ATTR_W) ? "w" : "-",
- (attrs & GRUB_MEM_ATTR_X) ? "x" : "-");
- }
+ grub_efi_mem_set_att (kernel_addr, kernel_size, kernel_start, nx_supported);
#if defined(__i386__) || defined(__x86_64__)
asm volatile ("cli");
@@ -214,7 +291,7 @@ grub_efi_linux_boot (grub_addr_t kernel_addr, grub_size_t kernel_size,
/* Invalidate the instruction cache */
grub_arch_sync_caches((void *)kernel_addr, kernel_size);
- hf = (handover_func)((char *)kernel_addr + handover_offset + offset);
+ hf = (handover_func)((char *)kernel_start_address + handover_offset + offset);
hf (grub_efi_image_handle, grub_efi_system_table, kernel_params);
return GRUB_ERR_BUG;
diff --git a/grub-core/loader/i386/efi/linux.c b/grub-core/loader/i386/efi/linux.c
index 9854b0defa..c44821608e 100644
--- a/grub-core/loader/i386/efi/linux.c
+++ b/grub-core/loader/i386/efi/linux.c
@@ -41,6 +41,7 @@ static grub_command_t cmd_linuxefi, cmd_initrdefi;
struct grub_linuxefi_context {
void *kernel_mem;
grub_uint64_t kernel_size;
+ grub_uint64_t kernel_start;
grub_uint32_t handover_offset;
struct linux_kernel_params *params;
char *cmdline;
@@ -169,6 +170,7 @@ grub_linuxefi_boot (void *data)
return grub_efi_linux_boot ((grub_addr_t)context->kernel_mem,
context->kernel_size,
+ context->kernel_start,
context->handover_offset,
context->params,
context->nx_supported);
@@ -527,7 +529,7 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
LOW_U32(kernel_mem));
lh->code32_start = LOW_U32(kernel_mem);
- grub_memcpy (kernel_mem, (char *)kernel + start, filelen - start);
+ grub_memcpy (kernel_mem, (char *)kernel, filelen);
lh->type_of_loader = 0x6;
grub_dprintf ("linux", "setting lh->type_of_loader = 0x%02x\n",
@@ -544,6 +546,7 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
goto fail;
context->kernel_mem = kernel_mem;
context->kernel_size = kernel_size;
+ context->kernel_start = start;
context->handover_offset = handover_offset;
context->params = params;
context->cmdline = cmdline;
diff --git a/include/grub/efi/linux.h b/include/grub/efi/linux.h
index b82f71006a..0aec66dafb 100644
--- a/include/grub/efi/linux.h
+++ b/include/grub/efi/linux.h
@@ -27,6 +27,7 @@
grub_err_t
EXPORT_FUNC(grub_efi_linux_boot) (grub_addr_t kernel_address,
grub_size_t kernel_size,
+ grub_size_t kernel_start,
grub_off_t handover_offset,
void *kernel_param, int nx_enabled);
@@ -38,4 +39,10 @@ EXPORT_FUNC(grub_efi_check_nx_image_support) (grub_addr_t kernel_addr,
grub_err_t
EXPORT_FUNC(grub_efi_check_nx_required) (int *nx_required);
+grub_err_t
+EXPORT_FUNC(grub_efi_mem_set_att) (grub_addr_t kernel_address,
+ grub_size_t kernel_size,
+ grub_size_t kernel_start,
+ int nx_supported);
+
#endif /* ! GRUB_EFI_LINUX_HEADER */
diff --git a/include/grub/efi/pe32.h b/include/grub/efi/pe32.h
index a5e623eb04..131a2c0c3d 100644
--- a/include/grub/efi/pe32.h
+++ b/include/grub/efi/pe32.h
@@ -71,6 +71,17 @@ struct grub_dos_header
grub_uint32_t lfanew;
};
+struct grub_msdos_image_header
+{
+ /* This is always 'MZ'. (GRUB_PE32_MAGIC) */
+ grub_uint16_t msdos_magic;
+
+ grub_uint16_t reserved[29];
+
+ /* The file offset of the PE image header. */
+ grub_uint32_t pe_image_header_offset;
+};
+
/* According to the spec, the minimal alignment is 512 bytes...
But some examples (such as EFI drivers in the Intel
Sample Implementation) use 32 bytes (0x20) instead, and it seems
@@ -308,6 +319,23 @@ struct grub_pe32_section_table
#define GRUB_PE32_SIGNATURE_SIZE 4
#define GRUB_PE32_SIGNATURE "PE\0\0"
+struct grub_pe_image_header
+{
+ /* This is always PE\0\0. */
+ char signature[GRUB_PE32_SIGNATURE_SIZE];
+
+ /* The COFF file header. */
+ struct grub_pe32_coff_header coff_header;
+
+#if GRUB_TARGET_SIZEOF_VOID_P == 8
+ /* The Optional header. */
+ struct grub_pe64_optional_header optional_header;
+#else
+ /* The Optional header. */
+ struct grub_pe32_optional_header optional_header;
+#endif
+};
+
struct grub_pe32_header
{
/* This should be filled in with GRUB_PE32_MSDOS_STUB. */

View File

@ -175,8 +175,9 @@ case "$COMMAND" in
if [[ "x${GRUB_ENABLE_BLSCFG}" = "xtrue" ]] || [[ ! -f /sbin/new-kernel-pkg ]]; then
BLS_TARGET="${BLS_DIR}/${MACHINE_ID}-${KERNEL_VERSION}.conf"
BLS_FAKE_TARGET="${BLS_DIR}/ffffffffffffffffffffffffffffffff-${KERNEL_VERSION}.conf"
BLS_DEBUG="$(echo ${BLS_TARGET} | sed -e "s/${KERNEL_VERSION}/${KERNEL_VERSION}~debug/")"
rm -f "${BLS_TARGET}" "${BLS_DEBUG}"
rm -f "${BLS_TARGET}" "${BLS_DEBUG}" "${BLS_FAKE_TARGET}"
for i in vmlinuz System.map config zImage.stub dtb; do
rm -rf "/boot/${i}-${KERNEL_VERSION}"

29
SOURCES/gen_grub_cfgstub Normal file
View File

@ -0,0 +1,29 @@
#!/bin/sh
set -eu
if [ $# -ne 2 ]
then
echo "Missing argument"
echo "Usage: script.sh GRUB_HOME EFI_HOME"
exit 1
fi
GRUB_HOME=$1
EFI_HOME=$2
# create a stub grub2 config in EFI
BOOT_UUID=$(grub2-probe --target=fs_uuid "${GRUB_HOME}")
GRUB_DIR=$(grub2-mkrelpath "${GRUB_HOME}")
echo "Generating grub stub config for drive " "${BOOT_UUID}"
echo "GRUB_DIR=" "${GRUB_DIR}"
echo "EFI_HOME=" "${EFI_HOME}"
cat << EOF > "${EFI_HOME}"/grub.cfg.stb
search --no-floppy --root-dev-only --fs-uuid --set=dev ${BOOT_UUID}
set prefix=(\$dev)${GRUB_DIR}
export \$prefix
configfile \$prefix/grub.cfg
EOF
mv ${EFI_HOME}/grub.cfg.stb ${EFI_HOME}/grub.cfg

View File

@ -527,6 +527,8 @@ install -m 700 %{3} $RPM_BUILD_ROOT%{efi_esp_dir}/%{3} \
%ifarch %{arm} \
install -D -m 700 %{2} $RPM_BUILD_ROOT%{efi_esp_boot}/BOOTARM.EFI \
%endif \
install -D -m 700 %{SOURCE13} \\\
${RPM_BUILD_ROOT}/usr/bin/gen_grub_cfgstub \
install -D -m 700 unicode.pf2 \\\
${RPM_BUILD_ROOT}/boot/%{name}/fonts/unicode.pf2 \
${RPM_BUILD_ROOT}/%{_bindir}/%{name}-editenv \\\
@ -638,6 +640,7 @@ ln -s ../boot/%{name}/grub.cfg \\\
%attr(0700,root,root) %verify(not mtime) %{efi_esp_boot}/BOOTARM.EFI \
%endif \
%attr(0700,root,root)/boot/%{name}/fonts \
%attr(0700,root,root)/usr/bin/gen_grub_cfgstub \
%dir %attr(0700,root,root)/boot/loader/entries \
%ghost %config(noreplace) %attr(0600,root,root)/boot/%{name}/grub.cfg \
%ghost %config(noreplace) %verify(not mtime) %attr(0700,root,root)%{efi_esp_dir}/grub.cfg \

View File

@ -454,3 +454,26 @@ Patch0454: 0454-fs-ext2-Rework-out-of-bounds-read-for-inline-and-ext.patch
Patch0455: 0455-tpm-Disable-the-tpm-verifier-if-the-TPM-device-is-no.patch
Patch0456: 0456-powerpc-increase-MIN-RMA-size-for-CAS-negotiation.patch
Patch0457: 0457-ieee1275-ofnet-Fix-grub_malloc-removed-after-added-s.patch
Patch0458: 0458-fs-Remove-trailing-whitespaces.patch
Patch0459: 0459-fs-xfs-Fix-memory-leaks-in-XFS-module.patch
Patch0460: 0460-fs-xfs-Incorrect-short-form-directory-data-boundary-.patch
Patch0461: 0461-fs-xfs-Fix-XFS-directory-extent-parsing.patch
Patch0462: 0462-fs-xfs-Add-large-extent-counters-incompat-feature-su.patch
Patch0463: 0463-fs-xfs-Handle-non-continuous-data-blocks-in-director.patch
Patch0464: 0464-fs-xfs-fix-large-extent-counters-incompat-feature-su.patch
Patch0465: 0465-grub-mkimage-Create-new-ELF-note-for-SBAT.patch
Patch0466: 0466-grub-mkimage-Add-SBAT-metadata-into-ELF-note-for-Pow.patch
Patch0467: 0467-appended-sig-sync-d-with-upstream-code.patch
Patch0468: 0468-ieee1275-Platform-Keystore-PKS-Support.patch
Patch0469: 0469-ieee1275-Read-the-DB-and-DBX-secure-boot-variables.patch
Patch0470: 0470-appendedsig-The-creation-of-trusted-and-distrusted-l.patch
Patch0471: 0471-appendedsig-While-verifying-the-kernel-use-trusted-a.patch
Patch0472: 0472-powerpc_ieee1275-set-use_static_keys-flag.patch
Patch0473: 0473-appendedsig-Reads-the-default-DB-keys-from-ELF-Note.patch
Patch0474: 0474-appendedsig-The-grub-command-s-trusted-and-distruste.patch
Patch0475: 0475-appendedsig-documentation.patch
Patch0476: 0476-efi-Add-efitextmode-command-for-getting-setting-the-.patch
Patch0477: 0477-10_linux.in-escape-kernel-option-characters-properly.patch
Patch0478: 0478-blscfg-check-if-variable-is-escaped-before-consideri.patch
Patch0479: 0479-osdep-linux-getroot-Detect-DDF-container-similar-to-.patch
Patch0480: 0480-Set-correctly-the-memory-attributes-for-the-kernel-P.patch

View File

@ -1,4 +1,5 @@
sbat,1,SBAT Version,sbat,1,https://github.com/rhboot/shim/blob/main/SBAT.md
grub,3,Free Software Foundation,grub,@@VERSION@@,https//www.gnu.org/software/grub/
grub,5,Free Software Foundation,grub,@@VERSION@@,https//www.gnu.org/software/grub/
grub.rh,2,Red Hat,grub2,@@RHEL_VERSION_RELEASE@@,mailto:secalert@redhat.com
grub.almalinux,2,AlmaLinux,grub2,@@VERSION_RELEASE@@,mailto:security@almalinux.org
grub.centos,2,Red Hat,grub2,@@VERSION_RELEASE@@,mailto:secalert@redhat.com

View File

@ -16,7 +16,7 @@
Name: grub2
Epoch: 1
Version: 2.06
Release: 100%{?dist}.alma.1
Release: 113%{?dist}.alma.1
Summary: Bootloader with support for Linux, Multiboot and more
License: GPLv3+
URL: http://www.gnu.org/software/grub/
@ -34,6 +34,7 @@ Source9: strtoull_test.c
Source10: 20-grub.install
Source11: grub.patches
Source12: sbat.csv.in
Source13: gen_grub_cfgstub
%include %{SOURCE1}
@ -352,23 +353,13 @@ if test -f ${EFI_HOME}/grub.cfg; then
fi
# create a stub grub2 config in EFI
BOOT_UUID=$(%{name}-probe --target=fs_uuid ${GRUB_HOME})
GRUB_DIR=$(%{name}-mkrelpath ${GRUB_HOME})
cat << EOF > ${EFI_HOME}/grub.cfg.stb
search --no-floppy --root-dev-only --fs-uuid --set=dev ${BOOT_UUID}
set prefix=(\$dev)${GRUB_DIR}
export \$prefix
configfile \$prefix/grub.cfg
EOF
gen_grub_cfgstub $GRUB_HOME $EFI_HOME || :
if test -f ${EFI_HOME}/grubenv; then
cp -a ${EFI_HOME}/grubenv ${EFI_HOME}/grubenv.rpmsave
mv --force ${EFI_HOME}/grubenv ${GRUB_HOME}/grubenv
fi
mv ${EFI_HOME}/grub.cfg.stb ${EFI_HOME}/grub.cfg
%files common -f grub.lang
%dir %{_libdir}/grub/
%dir %{_datarootdir}/grub/
@ -538,9 +529,50 @@ mv ${EFI_HOME}/grub.cfg.stb ${EFI_HOME}/grub.cfg
%endif
%changelog
* Fri Mar 28 2025 Eduard Abdullin <eabdullin@almalinux.org> - 1:2.06-100.alma.1
* Mon Sep 15 2025 Eduard Abdullin <eabdullin@almalinux.org> - 1:2.06-113.alma.1
- Debrand for AlmaLinux
* Thu Aug 7 2025 Nicolas Frayer <nfrayer@redhat.com> 2.06-113
- sbat: add new sbat entry for centos
- Resolves: #RHEL-108060
* Tue Jul 29 2025 Leo Sandoval <lsandova@redhat.com> 2.06-112
- Set correctly the memory attributes for the kernel PE sections
- Resolves: #RHEL-106075
* Tue Jul 29 2025 Nicolas Frayer <nfrayer@redhat.com> 2.06-111
- spec/posttrans: move grub config stub creation out of spec
- Resolves: #RHEL-69944
* Fri Jun 6 2025 Nicolas Frayer <nfrayer@redhat.com> - 2.06-110
- osdep/linux/getroot: Detect DDF container similar to IMSM
- Resolves: #RHEL-44336
* Mon Jun 2 2025 Leo Sandoval <lsandova@redhat.com> 2.06-109
- Handle special kernel parameter characters properly
- Resolves: #RHEL-64297
* Wed May 21 2025 Nicolas Frayer <nfrayer@redhat.com> - 2.06-108
- ieee1275: Appended signature support
- Resolves: #RHEL-24742
* Wed May 14 2025 Nicolas Frayer <nfrayer@redhat.com> - 2.06-107
- Remove BLS fake config in case of kernel removal
- Resolves: #RHEL-83915
* Wed May 14 2025 Nicolas Frayer <nfrayer@redhat.com> - 2.06-106
- sbat: bump grub sbat for new shim release
- Resolves: #RHEL-91278
* Tue Apr 15 2025 Nicolas Frayer <nfrayer@redhat.com> - 2.06-105
- ppc/mkimage: SBAT support on powerpc
- Resolves: #RHEL-87421
* Thu Apr 3 2025 Nicolas Frayer <nfrayer@redhat.com> 2.06-104
- fs/xfs: Sync with latest xfs upstream
- Resolves: #RHEL-85960
- (NVR bump to catch up with zstream)
* Tue Mar 25 2025 Nicolas Frayer <nfrayer@redhat.com> 2.06-100
- ieee1275/ofnet: Fix grub_malloc() removed after added safe
- Resolves: #RHEL-83117