import CS grub2-2.12-44.el10

This commit is contained in:
AlmaLinux RelEng Bot 2026-04-07 06:31:36 -04:00
parent ee935ffb38
commit 6a4763aca5
76 changed files with 280480 additions and 17 deletions

View File

@ -0,0 +1,32 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Nicolas Frayer <nfrayer@redhat.com>
Date: Wed, 19 Mar 2025 17:39:41 +0100
Subject: [PATCH] ieee1275/ofnet: Fix grub_malloc() removed after added safe
math functions
grub_malloc() has been inadvertently removed from the ieee1275/ofnet
code after it has been modified to use safe match function.
Fixes: 4beeff8a (net: Use safe math macros to prevent overflows)
Tested-by: Marta Lewandowska <mlewando@redhat.com>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
Signed-off-by: Nicolas Frayer <nfrayer@redhat.com>
---
grub-core/net/drivers/ieee1275/ofnet.c | 3 +++
1 file changed, 3 insertions(+)
diff --git a/grub-core/net/drivers/ieee1275/ofnet.c b/grub-core/net/drivers/ieee1275/ofnet.c
index 3e1b9094e2ab..37bc82467f60 100644
--- a/grub-core/net/drivers/ieee1275/ofnet.c
+++ b/grub-core/net/drivers/ieee1275/ofnet.c
@@ -463,6 +463,9 @@ search_net_devices (struct grub_ieee1275_devalias *alias)
return 0;
}
}
+
+ ofdata->path = grub_malloc(sz);
+
if (!ofdata->path)
{
grub_print_error ();

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 9488f052510a..b9930544889d 100644
--- a/util/grub-mkimagexx.c
+++ b/util/grub-mkimagexx.c
@@ -116,6 +116,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)
{
@@ -217,7 +225,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)
{
@@ -226,10 +234,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)
{
@@ -263,6 +278,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)
@@ -435,6 +451,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)
@@ -468,6 +486,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)
@@ -498,6 +518,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 f31fdefa814a..7fa6a7b21954 100644
--- a/util/mkimage.c
+++ b/util/mkimage.c
@@ -1848,6 +1848,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)
@@ -1859,10 +1860,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 7fa6a7b21954..f92949d1df25 100644
--- a/util/mkimage.c
+++ b/util/mkimage.c
@@ -957,8 +957,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);
@@ -1849,6 +1849,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)

View File

@ -0,0 +1,72 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Andrea Bolognani <abologna@redhat.com>
Date: Tue, 19 Nov 2024 15:42:01 +0000
Subject: [PATCH] loader/efi: Fix RISC-V build
Some struct definitions are currently limited to 32-bit and
64-bit Arm architectures, but they actually apply to other
architectures as well, specifically 32-bit and 64-bit RISC-V
respectively.
Update the preprocessor checks guarding their definition, and
change their names to make them more accurate by replacing the
word "arm" with the word "efi".
Signed-off-by: Andrea Bolognani <abologna@redhat.com>
---
grub-core/loader/efi/linux.c | 2 +-
include/grub/efi/efi.h | 12 ++++++------
2 files changed, 7 insertions(+), 7 deletions(-)
diff --git a/grub-core/loader/efi/linux.c b/grub-core/loader/efi/linux.c
index 5889e3f36f8..ef55556f2d9 100644
--- a/grub-core/loader/efi/linux.c
+++ b/grub-core/loader/efi/linux.c
@@ -684,7 +684,7 @@ parse_pe_header (void *kernel, grub_uint64_t *total_size,
grub_uint32_t *alignment, grub_uint32_t *code_size)
{
struct linux_arch_kernel_header *lh = kernel;
- struct grub_armxx_linux_pe_header *pe;
+ struct grub_efixx_linux_pe_header *pe;
grub_uint16_t i;
struct grub_pe32_section_table *sections;
diff --git a/include/grub/efi/efi.h b/include/grub/efi/efi.h
index 7eed1bd791d..81daf6bead1 100644
--- a/include/grub/efi/efi.h
+++ b/include/grub/efi/efi.h
@@ -36,28 +36,28 @@ struct linux_arch_kernel_header {
struct grub_pe_image_header pe_image_header;
};
-struct grub_arm_linux_pe_header
+struct grub_efi32_linux_pe_header
{
grub_uint32_t magic;
struct grub_pe32_coff_header coff;
struct grub_pe32_optional_header opt;
};
-struct grub_arm64_linux_pe_header
+struct grub_efi64_linux_pe_header
{
grub_uint32_t magic;
struct grub_pe32_coff_header coff;
struct grub_pe64_optional_header opt;
};
-#if defined(__arm__)
+#if defined(__arm__) || (defined(__riscv) && (__riscv_xlen == 32))
# define GRUB_PE32_PEXX_MAGIC GRUB_PE32_PE32_MAGIC
-# define grub_armxx_linux_pe_header grub_arm_linux_pe_header
+# define grub_efixx_linux_pe_header grub_efi32_linux_pe_header
#endif
-#if defined(__aarch64__)
+#if defined(__aarch64__) || (defined(__riscv) && (__riscv_xlen == 64))
# define GRUB_PE32_PEXX_MAGIC GRUB_PE32_PE64_MAGIC
-# define grub_armxx_linux_pe_header grub_arm64_linux_pe_header
+# define grub_efixx_linux_pe_header grub_efi64_linux_pe_header
#endif
#define GRUB_EFI_GRUB_VARIABLE_GUID \

View File

@ -0,0 +1,44 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Heinrich Schuchardt <heinrich.schuchardt@canonical.com>
Date: Mon, 12 Aug 2024 16:13:18 +0200
Subject: [PATCH] kern/riscv/efi/init: Use time register in
grub_efi_get_time_ms()
The cycle register is not guaranteed to count at constant frequency.
If it is counting at all depends on the state the performance monitoring
unit. Use the time register to measure time.
Signed-off-by: Heinrich Schuchardt <heinrich.schuchardt@canonical.com>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
---
grub-core/kern/riscv/efi/init.c | 15 +++++++--------
1 file changed, 7 insertions(+), 8 deletions(-)
diff --git a/grub-core/kern/riscv/efi/init.c b/grub-core/kern/riscv/efi/init.c
index 38795fe6741..0d7de4f541a 100644
--- a/grub-core/kern/riscv/efi/init.c
+++ b/grub-core/kern/riscv/efi/init.c
@@ -33,16 +33,15 @@ grub_efi_get_time_ms (void)
grub_uint64_t tmr;
#if __riscv_xlen == 64
- asm volatile ("rdcycle %0" : "=r" (tmr));
+ asm volatile ("rdtime %0" : "=r"(tmr));
#else
grub_uint32_t lo, hi, tmp;
- asm volatile (
- "1:\n"
- "rdcycleh %0\n"
- "rdcycle %1\n"
- "rdcycleh %2\n"
- "bne %0, %2, 1b"
- : "=&r" (hi), "=&r" (lo), "=&r" (tmp));
+ asm volatile ("1:\n"
+ "rdtimeh %0\n"
+ "rdtime %1\n"
+ "rdtimeh %2\n"
+ "bne %0, %2, 1b"
+ : "=&r" (hi), "=&r" (lo), "=&r" (tmp));
tmr = ((grub_uint64_t)hi << 32) | lo;
#endif

View File

@ -0,0 +1,36 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Jason Montleon <jason@montleon.com>
Date: Fri, 3 May 2024 13:18:37 -0400
Subject: [PATCH] Use medany instead of large model for RISCV
Signed-off-by: Jason Montleon <jason@montleon.com>
---
configure.ac | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)
diff --git a/configure.ac b/configure.ac
index 4788f3d6adc..a6a6957fbdb 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1313,7 +1313,7 @@ AC_SUBST(TARGET_LDFLAGS_OLDMAGIC)
LDFLAGS="$TARGET_LDFLAGS"
-if test "$target_cpu" = x86_64 || test "$target_cpu" = sparc64 || test "$target_cpu" = riscv64 ; then
+if test "$target_cpu" = x86_64 || test "$target_cpu" = sparc64 ; then
# Use large model to support 4G memory
AC_CACHE_CHECK([whether option -mcmodel=large works], grub_cv_cc_mcmodel, [
CFLAGS="$TARGET_CFLAGS -mcmodel=large"
@@ -1323,9 +1323,11 @@ if test "$target_cpu" = x86_64 || test "$target_cpu" = sparc64 || test "$target_
])
if test "x$grub_cv_cc_mcmodel" = xyes; then
TARGET_CFLAGS="$TARGET_CFLAGS -mcmodel=large"
- elif test "$target_cpu" = sparc64 || test "$target_cpu" = riscv64; then
+ elif test "$target_cpu" = sparc64; then
TARGET_CFLAGS="$TARGET_CFLAGS -mcmodel=medany"
fi
+elif test "$target_cpu" = riscv64 ; then
+ TARGET_CFLAGS="$TARGET_CFLAGS -mcmodel=medany"
fi
if test "$target_cpu"-"$platform" = x86_64-efi; then

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,293 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Leo Sandoval <lsandova@redhat.com>
Date: Wed, 16 Jul 2025 12:38:24 -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/efi/linux.c | 170 +++++++++++++++++++++++++++-----------
grub-core/loader/i386/efi/linux.c | 5 +-
include/grub/efi/linux.h | 6 ++
3 files changed, 134 insertions(+), 47 deletions(-)
diff --git a/grub-core/loader/efi/linux.c b/grub-core/loader/efi/linux.c
index efceb9b6dd..159bd9dc48 100644
--- a/grub-core/loader/efi/linux.c
+++ b/grub-core/loader/efi/linux.c
@@ -37,6 +37,7 @@
#include <grub/efi/sb.h>
#include <grub/i18n.h>
#include <grub/lib/cmdline.h>
+#include <grub/safemath.h>
#include <grub/verify.h>
GRUB_MOD_LICENSE ("GPLv3+");
@@ -203,22 +204,133 @@ 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 k_address, grub_size_t k_size,
+grub_efi_mem_set_att(grub_addr_t k_address, grub_size_t k_size,
+ grub_size_t k_start, int nx_supported)
+{
+ grub_addr_t k_start_address = k_address + k_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 *)k_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 > (k_address + k_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 > (k_address + k_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) k_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 k_address, grub_size_t k_size, grub_size_t k_start,
grub_off_t h_offset, void *k_params,
int nx_supported)
{
+ grub_addr_t k_start_address = k_address + k_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__
offset = 512;
#endif
@@ -242,41 +354,7 @@ grub_efi_linux_boot (grub_addr_t k_address, grub_size_t k_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",
- k_address, k_address + k_size - 1,
- (kernel_set_attrs & GRUB_MEM_ATTR_W) ? 'w' : '-');
- grub_update_mem_attrs (k_address, k_size,
- kernel_set_attrs, kernel_clear_attrs);
-
- grub_get_mem_attrs (k_address, 4096, &attrs);
- grub_dprintf ("nx", "permissions for 0x%"PRIxGRUB_ADDR" are %s%s%s\n",
- (grub_addr_t)k_address,
- (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 (k_address, k_size, k_start, nx_supported);
#if defined(__i386__) || defined(__x86_64__)
asm volatile ("cli");
@@ -285,7 +363,7 @@ grub_efi_linux_boot (grub_addr_t k_address, grub_size_t k_size,
/* Invalidate the instruction cache */
grub_arch_sync_caches((void *)kernel_addr, kernel_size);
- hf = (handover_func)((char *)k_address + h_offset + offset);
+ hf = (handover_func)((char *)k_start_address + h_offset + offset);
hf (grub_efi_image_handle, grub_efi_system_table, k_params);
return GRUB_ERR_BUG;
@@ -455,7 +533,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/i386/efi/linux.c b/grub-core/loader/i386/efi/linux.c
index abbf6b24f5..6c310d9879 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 5b4e626c37..cd17be506a 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,9 @@ 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 k_address,
+ grub_size_t k_size,
+ grub_size_t k_start, int nx_supported);
+
#endif /* ! GRUB_EFI_LINUX_HEADER */

View File

@ -0,0 +1,66 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: James Le Cuirot <jlecuirot@microsoft.com>
Date: Thu, 24 Oct 2024 14:42:46 +0100
Subject: [PATCH] script/execute: Don't let trailing blank lines determine the
return code
grub_script_execute_sourcecode() parses and executes code one line at a
time, updating the return code each time because only the last line
determines the final status. However, trailing new lines were also
executed, masking any failure on the previous line. Fix this by only
trying to execute the command when there is actually one present.
This has presumably never been noticed because this code is not used by
regular functions, only in special cases like eval and menu entries. The
latter generally don't return at all, having booted an OS. When failing
to boot, upstream GRUB triggers the fallback mechanism regardless of the
return code.
We noticed the problem while using Red Hat's patches, which change this
behaviour to take account of the return code. In that case, a failure
takes you back to the menu rather than triggering a fallback.
Signed-off-by: James Le Cuirot <jlecuirot@microsoft.com>
---
grub-core/script/execute.c | 5 ++++-
tests/grub_script_eval.in | 10 +++++++++-
2 files changed, 13 insertions(+), 2 deletions(-)
diff --git a/grub-core/script/execute.c b/grub-core/script/execute.c
index 014132703..3d26a3fe4 100644
--- a/grub-core/script/execute.c
+++ b/grub-core/script/execute.c
@@ -952,7 +952,10 @@ grub_script_execute_sourcecode (const char *source)
break;
}
- ret = grub_script_execute (parsed_script);
+ /* Don't let trailing blank lines determine the return code. */
+ if (parsed_script->cmd)
+ ret = grub_script_execute (parsed_script);
+
grub_script_free (parsed_script);
grub_free (line);
}
diff --git a/tests/grub_script_eval.in b/tests/grub_script_eval.in
index c97b78d77..9c6211042 100644
--- a/tests/grub_script_eval.in
+++ b/tests/grub_script_eval.in
@@ -3,4 +3,12 @@
eval echo "Hello world"
valname=tst
eval $valname=hi
-echo $tst
\ No newline at end of file
+echo $tst
+
+if eval "
+false
+"; then
+ echo should have failed
+else
+ echo failed as expected
+fi
--
2.48.1

View File

@ -0,0 +1,45 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: James Le Cuirot <jlecuirot@microsoft.com>
Date: Thu, 24 Oct 2024 15:00:26 +0100
Subject: [PATCH] normal/menu: Check return code of the script when executing a
menu entry
Don't rely on grub_errno here because grub_script_execute_new_scope()
calls grub_print_error(), which always resets grub_errno back to
GRUB_ERR_NONE. It may also get reset by grub_wait_after_message().
This problem was observed when a "bad signature" error resulted in the
menu being redisplayed rather than the fallback mechanism being
triggered, although another change was also needed to fix it. This only
happens with Red Hat's patches because upstream GRUB triggers the
fallback mechanism regardless of the return code.
Signed-off-by: James Le Cuirot <jlecuirot@microsoft.com>
---
grub-core/normal/menu.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/grub-core/normal/menu.c b/grub-core/normal/menu.c
index 97687013c..a2703dabb 100644
--- a/grub-core/normal/menu.c
+++ b/grub-core/normal/menu.c
@@ -377,14 +377,14 @@ grub_menu_execute_entry(grub_menu_entry_t entry, int auto_boot)
if (ptr && ptr[0] && ptr[1])
grub_env_set ("default", ptr + 1);
- grub_script_execute_new_scope (entry->sourcecode, entry->argc, entry->args);
+ err = grub_script_execute_new_scope (entry->sourcecode, entry->argc, entry->args);
if (errs_before != grub_err_printed_errors)
grub_wait_after_message ();
errs_before = grub_err_printed_errors;
- if (grub_errno == GRUB_ERR_NONE && grub_loader_is_loaded ())
+ if (err == GRUB_ERR_NONE && grub_loader_is_loaded ())
/* Implicit execution of boot, only if something is loaded. */
err = grub_command_execute ("boot", 0, 0);
--
2.48.1

View File

@ -0,0 +1,35 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Leo Sandoval <lsandova@redhat.com>
Date: Thu, 6 Nov 2025 11:19:16 -0600
Subject: [PATCH] Include license into grub-set-password util
Signed-off-by: Leo Sandoval <lsandova@redhat.com>
---
util/grub-set-password.in | 16 ++++++++++++++++
1 file changed, 16 insertions(+)
diff --git a/util/grub-set-password.in b/util/grub-set-password.in
index d8005e5a14..f6655add7b 100644
--- a/util/grub-set-password.in
+++ b/util/grub-set-password.in
@@ -1,4 +1,20 @@
#!/bin/sh -e
+#
+# Friendly password config tool from GRUB
+# Copyright (C) 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/>.
grubdir=`echo "/@bootdirname@/@grubdirname@" | sed 's,//*,/,g'`

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,299 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Vladimir Serbinenko <phcoder@gmail.com>
Date: Mon, 7 Jul 2025 14:52:08 +0000
Subject: [PATCH] b64dec: Import b64dec from gpg-error
Imported from libgpg-error 1.51.
Signed-off-by: Vladimir Serbinenko <phcoder@gmail.com>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
---
grub-core/lib/b64dec.c | 279 +++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 279 insertions(+)
create mode 100644 grub-core/lib/b64dec.c
diff --git a/grub-core/lib/b64dec.c b/grub-core/lib/b64dec.c
new file mode 100644
index 0000000..868d985
--- /dev/null
+++ b/grub-core/lib/b64dec.c
@@ -0,0 +1,279 @@
+/* b64dec.c - Simple Base64 decoder.
+ * Copyright (C) 2008, 2011 Free Software Foundation, Inc.
+ * Copyright (C) 2008, 2011, 2016 g10 Code GmbH
+ *
+ * This file is part of Libgpg-error.
+ *
+ * This file is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This file 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, see <https://www.gnu.org/licenses/>.
+ * SPDX-License-Identifier: LGPL-2.1-or-later
+ *
+ * This file was originally a part of GnuPG.
+ */
+
+#include <config.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "gpgrt-int.h"
+
+
+/* The reverse base-64 list used for base-64 decoding. */
+static unsigned char const asctobin[128] =
+ {
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0x3e, 0xff, 0xff, 0xff, 0x3f,
+ 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b,
+ 0x3c, 0x3d, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06,
+ 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e,
+ 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16,
+ 0x17, 0x18, 0x19, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20,
+ 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28,
+ 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30,
+ 0x31, 0x32, 0x33, 0xff, 0xff, 0xff, 0xff, 0xff
+ };
+
+enum decoder_states
+ {
+ s_init, s_idle, s_lfseen, s_beginseen, s_waitheader, s_waitblank, s_begin,
+ s_b64_0, s_b64_1, s_b64_2, s_b64_3,
+ s_waitendtitle, s_waitend
+ };
+
+
+
+/* Allocate and initialize the context for the base64 decoder. If
+ TITLE is NULL a plain base64 decoding is done. If it is the empty
+ string the decoder will skip everything until a "-----BEGIN " line
+ has been seen, decoding ends at a "----END " line. */
+gpgrt_b64state_t
+_gpgrt_b64dec_start (const char *title)
+{
+ gpgrt_b64state_t state;
+ char *t = NULL;
+
+ if (title)
+ {
+ t = xtrystrdup (title);
+ if (!t)
+ return NULL;
+ }
+
+ state = xtrycalloc (1, sizeof (struct _gpgrt_b64state));
+ if (!state)
+ {
+ xfree (t);
+ return NULL;
+ }
+
+ if (t)
+ {
+ state->title = t;
+ state->idx = s_init;
+ }
+ else
+ state->idx = s_b64_0;
+
+ state->using_decoder = 1;
+
+ return state;
+}
+
+
+/* Do in-place decoding of base-64 data of LENGTH in BUFFER. Stores the
+ new length of the buffer at R_NBYTES. */
+gpg_err_code_t
+_gpgrt_b64dec_proc (gpgrt_b64state_t state, void *buffer, size_t length,
+ size_t *r_nbytes)
+{
+ enum decoder_states ds = state->idx;
+ unsigned char val = state->radbuf[0];
+ int pos = state->quad_count;
+ char *d, *s;
+
+ if (state->lasterr)
+ return state->lasterr;
+
+ if (state->stop_seen)
+ {
+ *r_nbytes = 0;
+ state->lasterr = GPG_ERR_EOF;
+ xfree (state->title);
+ state->title = NULL;
+ return state->lasterr;
+ }
+
+ for (s=d=buffer; length && !state->stop_seen; length--, s++)
+ {
+ again:
+ switch (ds)
+ {
+ case s_idle:
+ if (*s == '\n')
+ {
+ ds = s_lfseen;
+ pos = 0;
+ }
+ break;
+ case s_init:
+ ds = s_lfseen;
+ /* Fall through */
+ case s_lfseen:
+ if (*s != "-----BEGIN "[pos])
+ {
+ ds = s_idle;
+ goto again;
+ }
+ else if (pos == 10)
+ {
+ pos = 0;
+ ds = s_beginseen;
+ }
+ else
+ pos++;
+ break;
+ case s_beginseen:
+ if (*s != "PGP "[pos])
+ ds = s_begin; /* Not a PGP armor. */
+ else if (pos == 3)
+ ds = s_waitheader;
+ else
+ pos++;
+ break;
+ case s_waitheader:
+ if (*s == '\n')
+ ds = s_waitblank;
+ break;
+ case s_waitblank:
+ if (*s == '\n')
+ ds = s_b64_0; /* blank line found. */
+ else if (*s == ' ' || *s == '\r' || *s == '\t')
+ ; /* Ignore spaces. */
+ else
+ {
+ /* Armor header line. Note that we don't care that our
+ * FSM accepts a header prefixed with spaces. */
+ ds = s_waitheader; /* Wait for next header. */
+ }
+ break;
+ case s_begin:
+ if (*s == '\n')
+ ds = s_b64_0;
+ break;
+ case s_b64_0:
+ case s_b64_1:
+ case s_b64_2:
+ case s_b64_3:
+ {
+ int c;
+
+ if (*s == '-' && state->title)
+ {
+ /* Not a valid Base64 character: assume end
+ header. */
+ ds = s_waitend;
+ }
+ else if (*s == '=')
+ {
+ /* Pad character: stop */
+ if (ds == s_b64_1)
+ *d++ = val;
+ ds = state->title? s_waitendtitle : s_waitend;
+ }
+ else if (*s == '\n' || *s == ' ' || *s == '\r' || *s == '\t')
+ ; /* Skip white spaces. */
+ else if ( (*s & 0x80)
+ || (c = asctobin[*(unsigned char *)s]) == 255)
+ {
+ /* Skip invalid encodings. */
+ state->invalid_encoding = 1;
+ }
+ else if (ds == s_b64_0)
+ {
+ val = c << 2;
+ ds = s_b64_1;
+ }
+ else if (ds == s_b64_1)
+ {
+ val |= (c>>4)&3;
+ *d++ = val;
+ val = (c<<4)&0xf0;
+ ds = s_b64_2;
+ }
+ else if (ds == s_b64_2)
+ {
+ val |= (c>>2)&15;
+ *d++ = val;
+ val = (c<<6)&0xc0;
+ ds = s_b64_3;
+ }
+ else
+ {
+ val |= c&0x3f;
+ *d++ = val;
+ ds = s_b64_0;
+ }
+ }
+ break;
+ case s_waitendtitle:
+ if (*s == '-')
+ ds = s_waitend;
+ break;
+ case s_waitend:
+ if ( *s == '\n')
+ state->stop_seen = 1;
+ break;
+ default:
+ gpgrt_assert (!"invalid state");
+ }
+ }
+
+
+ state->idx = ds;
+ state->radbuf[0] = val;
+ state->quad_count = pos;
+ *r_nbytes = (d -(char*) buffer);
+ return 0;
+}
+
+
+/* Return an error code in case an encoding error has been found
+ during decoding. */
+gpg_err_code_t
+_gpgrt_b64dec_finish (gpgrt_b64state_t state)
+{
+ gpg_error_t err;
+
+ if (!state)
+ return 0; /* Already released. */
+
+ if (!state->using_decoder)
+ err = GPG_ERR_CONFLICT; /* State was allocated for the encoder. */
+ else if (state->lasterr)
+ err = state->lasterr;
+ else
+ {
+ xfree (state->title);
+ err = state->invalid_encoding? GPG_ERR_BAD_DATA : 0;
+ }
+ xfree (state);
+
+ return err;
+}

View File

@ -0,0 +1,42 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Vladimir Serbinenko <phcoder@gmail.com>
Date: Mon, 7 Jul 2025 14:52:09 +0000
Subject: [PATCH] b64dec: Add harness for compilation in GRUB environment
Signed-off-by: Vladimir Serbinenko <phcoder@gmail.com>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
---
grub-core/lib/gpgrt-int.h | 24 ++++++++++++++++++++++++
1 file changed, 24 insertions(+)
create mode 100644 grub-core/lib/gpgrt-int.h
diff --git a/grub-core/lib/gpgrt-int.h b/grub-core/lib/gpgrt-int.h
new file mode 100644
index 0000000..45d6358
--- /dev/null
+++ b/grub-core/lib/gpgrt-int.h
@@ -0,0 +1,24 @@
+#include <grub/crypto.h>
+
+struct _gpgrt_b64state
+{
+ int idx;
+ int quad_count;
+ char *title;
+ unsigned char radbuf[4];
+ unsigned int crc;
+ gpg_err_code_t lasterr;
+ unsigned int flags;
+ unsigned int stop_seen:1;
+ unsigned int invalid_encoding:1;
+ unsigned int using_decoder:1;
+};
+
+#define _gpgrt_b64dec_start gpgrt_b64dec_start
+#define xtrystrdup grub_strdup
+#define xtrycalloc grub_calloc
+#define xfree grub_free
+#define _gpgrt_b64dec_finish gpgrt_b64dec_finish
+#define gpgrt_assert(expr) ((expr)? (void)0 \
+ : _gcry_assert_failed (#expr, __FILE__, __LINE__, __FUNCTION__))
+#define _gpgrt_b64dec_proc gpgrt_b64dec_proc

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,285 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Vladimir Serbinenko <phcoder@gmail.com>
Date: Mon, 7 Jul 2025 14:52:11 +0000
Subject: [PATCH] tests: Add DSA and RSA SEXP tests
This allows us to test purely the integration of the implementation of
DSA and RSA from libgcrypt without concerning with additional code.
Signed-off-by: Vladimir Serbinenko <phcoder@gmail.com>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
---
grub-core/Makefile.core.def | 16 +++++
grub-core/tests/dsa_sexp_test.c | 127 ++++++++++++++++++++++++++++++++++++++++
grub-core/tests/rsa_sexp_test.c | 101 ++++++++++++++++++++++++++++++++
3 files changed, 244 insertions(+)
create mode 100644 grub-core/tests/dsa_sexp_test.c
create mode 100644 grub-core/tests/rsa_sexp_test.c
diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def
index 4ba5d94..0b6b996 100644
--- a/grub-core/Makefile.core.def
+++ b/grub-core/Makefile.core.def
@@ -2215,6 +2215,22 @@ module = {
common = tests/setjmp_test.c;
};
+module = {
+ name = dsa_sexp_test;
+ common = tests/dsa_sexp_test.c;
+
+ cflags = '$(CFLAGS_GCRY) -Wno-redundant-decls -Wno-sign-compare';
+ cppflags = '$(CPPFLAGS_GCRY)';
+};
+
+module = {
+ name = rsa_sexp_test;
+ common = tests/rsa_sexp_test.c;
+
+ cflags = '$(CFLAGS_GCRY) -Wno-redundant-decls -Wno-sign-compare';
+ cppflags = '$(CPPFLAGS_GCRY)';
+};
+
module = {
name = appended_signature_test;
common = tests/appended_signature_test.c;
diff --git a/grub-core/tests/dsa_sexp_test.c b/grub-core/tests/dsa_sexp_test.c
new file mode 100644
index 0000000..31600d9
--- /dev/null
+++ b/grub-core/tests/dsa_sexp_test.c
@@ -0,0 +1,127 @@
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2025 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/test.h>
+#include <grub/crypto.h>
+#include <grub/gcrypt/gcrypt.h>
+
+GRUB_MOD_LICENSE ("GPLv3+");
+
+/* Sample DSA public key. */
+static char pubkey_dump[] = {
+ 0x28, 0x31, 0x30, 0x3a, 0x70, 0x75, 0x62, 0x6c,
+ 0x69, 0x63, 0x2d, 0x6b, 0x65, 0x79, 0x28, 0x33,
+ 0x3a, 0x64, 0x73, 0x61, 0x28, 0x31, 0x3a, 0x70,
+ 0x31, 0x32, 0x39, 0x3a, 0x00, 0xc0, 0x50, 0x14,
+ 0x4c, 0x97, 0x10, 0x69, 0x07, 0xa7, 0xe9, 0x2b,
+ 0xe5, 0xc6, 0x88, 0xe1, 0x6d, 0xd8, 0x38, 0x28,
+ 0x09, 0x49, 0x5b, 0xe8, 0xa3, 0x04, 0xb8, 0xc4,
+ 0x6e, 0x98, 0xc1, 0xc2, 0xb0, 0x2a, 0xe0, 0xe2,
+ 0x1a, 0x30, 0xd2, 0xdb, 0x45, 0x1a, 0x88, 0x80,
+ 0x28, 0x24, 0xb0, 0xbf, 0xc2, 0xbd, 0xe9, 0xf6,
+ 0x9d, 0xa2, 0x01, 0x94, 0xe6, 0x7f, 0xa0, 0xb6,
+ 0xe4, 0x39, 0xfc, 0x54, 0xba, 0x99, 0xb6, 0xbe,
+ 0x39, 0xee, 0xa5, 0xd9, 0xa0, 0x35, 0x3c, 0x2d,
+ 0x3e, 0x96, 0xc3, 0x96, 0xa5, 0x0d, 0x2b, 0xbf,
+ 0x3b, 0xa3, 0xe2, 0xe8, 0x89, 0xed, 0x60, 0xe0,
+ 0x43, 0x61, 0xb6, 0x73, 0xf6, 0xa7, 0xb4, 0x56,
+ 0x76, 0x04, 0xf7, 0x8b, 0xf1, 0x84, 0xaa, 0x3e,
+ 0xe0, 0x08, 0xad, 0xdd, 0xc2, 0x36, 0xfd, 0x3d,
+ 0xd0, 0xad, 0xf4, 0x3a, 0x7e, 0x80, 0x8c, 0x52,
+ 0x2b, 0x04, 0xa8, 0x03, 0x27, 0x29, 0x28, 0x31,
+ 0x3a, 0x71, 0x32, 0x31, 0x3a, 0x00, 0xd5, 0x34,
+ 0xd2, 0xc5, 0x1c, 0x26, 0xdf, 0xb0, 0xba, 0x78,
+ 0x75, 0xe5, 0xe9, 0x36, 0x6b, 0x04, 0x03, 0xe2,
+ 0x57, 0x3f, 0x29, 0x28, 0x31, 0x3a, 0x67, 0x31,
+ 0x32, 0x38, 0x3a, 0x3b, 0xa0, 0xac, 0xa3, 0xa1,
+ 0xd1, 0x04, 0x23, 0x5f, 0x9f, 0xbc, 0x6d, 0x9e,
+ 0x88, 0x2a, 0x28, 0xc1, 0x48, 0xaf, 0xa5, 0x17,
+ 0x59, 0x3a, 0x17, 0x33, 0x56, 0xaa, 0x8d, 0x27,
+ 0x64, 0xfe, 0x8e, 0x8a, 0x2e, 0xba, 0xf2, 0x66,
+ 0xcc, 0x66, 0xbd, 0xa4, 0xfe, 0xa9, 0x07, 0x0d,
+ 0xae, 0x8c, 0x9f, 0x70, 0xf7, 0x87, 0xaa, 0x01,
+ 0x47, 0x6b, 0xf9, 0x0f, 0x09, 0x18, 0x42, 0x76,
+ 0xc4, 0xa3, 0xb9, 0x55, 0x11, 0x8d, 0xa3, 0xa5,
+ 0x69, 0x30, 0x91, 0xb7, 0x03, 0xef, 0x7f, 0x12,
+ 0xe6, 0xb9, 0x78, 0x73, 0xe0, 0xc0, 0x4f, 0xc6,
+ 0xd9, 0x43, 0x99, 0x95, 0x0b, 0x4d, 0x58, 0xd3,
+ 0x6b, 0x76, 0xb0, 0x6a, 0xcf, 0x68, 0x6d, 0xf0,
+ 0xd9, 0xc1, 0x88, 0x43, 0x9d, 0xf9, 0x04, 0xcb,
+ 0xc9, 0x82, 0x6c, 0xee, 0xd4, 0x9c, 0xbd, 0x1c,
+ 0x4d, 0x54, 0x29, 0x83, 0xa9, 0x5e, 0xaa, 0x10,
+ 0xa7, 0xc1, 0x04, 0x29, 0x28, 0x31, 0x3a, 0x79,
+ 0x31, 0x32, 0x39, 0x3a, 0x00, 0x82, 0x33, 0xf1,
+ 0x91, 0xe3, 0xf2, 0x12, 0x93, 0x5a, 0xed, 0x0c,
+ 0x9d, 0xec, 0x67, 0xaa, 0xa7, 0x97, 0x7f, 0x9f,
+ 0x5e, 0xef, 0x6a, 0x3e, 0xa4, 0x7f, 0x9b, 0xed,
+ 0x65, 0xd7, 0xba, 0x40, 0x6d, 0xe1, 0xde, 0xc1,
+ 0x14, 0x4c, 0x9b, 0x28, 0x5c, 0x03, 0x8e, 0x1a,
+ 0xd4, 0x1b, 0x80, 0x1b, 0x07, 0xd6, 0x84, 0x04,
+ 0x49, 0x6c, 0x1b, 0x08, 0x84, 0x15, 0x54, 0x62,
+ 0xca, 0xd5, 0x75, 0xff, 0xc8, 0xb3, 0x81, 0x76,
+ 0x82, 0x91, 0x35, 0x80, 0x20, 0x73, 0x2a, 0x21,
+ 0xca, 0x22, 0x06, 0xa7, 0x73, 0x99, 0x75, 0x7e,
+ 0x5e, 0xa6, 0x09, 0x59, 0x66, 0x2c, 0xcd, 0xb1,
+ 0x8d, 0x3b, 0xc0, 0x68, 0xc5, 0x41, 0xa0, 0x9d,
+ 0x82, 0x15, 0xc4, 0xdd, 0x47, 0x1c, 0x5b, 0xa9,
+ 0x74, 0x18, 0xaf, 0x72, 0x63, 0x6b, 0x0a, 0x4e,
+ 0x95, 0x09, 0x7a, 0xb5, 0x4b, 0x98, 0x85, 0xb9,
+ 0x6d, 0x9d, 0x3b, 0x73, 0x8c, 0x29, 0x29, 0x29,
+};
+
+/* Sample DSA signature of message "hello" with sample key. */
+static char sig_dump[] = {
+ 0x28, 0x37, 0x3a, 0x73, 0x69, 0x67, 0x2d, 0x76,
+ 0x61, 0x6c, 0x28, 0x33, 0x3a, 0x64, 0x73, 0x61,
+ 0x28, 0x31, 0x3a, 0x72, 0x32, 0x30, 0x3a, 0xb6,
+ 0x60, 0x37, 0xef, 0x02, 0x7c, 0x7c, 0x6e, 0x4f,
+ 0x66, 0x8c, 0x7c, 0x26, 0x77, 0xd9, 0x33, 0x90,
+ 0xba, 0x7c, 0xfb, 0x29, 0x28, 0x31, 0x3a, 0x73,
+ 0x32, 0x30, 0x3a, 0x83, 0xc0, 0x84, 0x72, 0xc6,
+ 0x1c, 0x85, 0x6f, 0x8b, 0x9b, 0xb0, 0x38, 0x38,
+ 0xb2, 0xb6, 0xdf, 0x1c, 0x52, 0x96, 0x1b, 0x29,
+ 0x29, 0x29,
+};
+
+extern gcry_pk_spec_t _gcry_pubkey_spec_dsa;
+
+static void
+dsa_sexp_test (void)
+{
+ gcry_sexp_t sign_parms, sign_parms_invalid, pubkey, sig;
+ int rc;
+ grub_size_t errof;
+
+ rc = _gcry_sexp_build (&sign_parms_invalid, &errof,
+ "(data (value \"hi\"))\n");
+ grub_test_assert (rc == 0, "sexp build failed");
+
+ rc = _gcry_sexp_build (&sign_parms, &errof,
+ "(data (value \"hello\"))\n");
+ grub_test_assert (rc == 0, "sexp build failed");
+ rc = _gcry_sexp_new (&pubkey, pubkey_dump, sizeof(pubkey_dump), 0);
+ grub_test_assert (rc == 0, "sexp new failed");
+ rc = _gcry_sexp_new (&sig, sig_dump, sizeof(sig_dump), 0);
+ grub_test_assert (rc == 0, "sexp new failed");
+ rc = _gcry_pubkey_spec_dsa.verify (sig, sign_parms, pubkey);
+ grub_test_assert (rc == 0, "signature verification failed: %d", rc);
+ rc = _gcry_pubkey_spec_dsa.verify (sig, sign_parms_invalid, pubkey);
+ grub_test_assert (rc != 0, "signature verification succeded wrongly");
+}
+
+GRUB_FUNCTIONAL_TEST (dsa_sexp_test, dsa_sexp_test);
diff --git a/grub-core/tests/rsa_sexp_test.c b/grub-core/tests/rsa_sexp_test.c
new file mode 100644
index 0000000..6ebba81
--- /dev/null
+++ b/grub-core/tests/rsa_sexp_test.c
@@ -0,0 +1,101 @@
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2025 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/test.h>
+#include <grub/crypto.h>
+#include <grub/gcrypt/gcrypt.h>
+
+GRUB_MOD_LICENSE ("GPLv3+");
+
+/* Sample RSA key. */
+static char pubkey_dump[] = {
+ 0x28, 0x31, 0x30, 0x3a, 0x70, 0x75, 0x62, 0x6c,
+ 0x69, 0x63, 0x2d, 0x6b, 0x65, 0x79, 0x28, 0x33,
+ 0x3a, 0x72, 0x73, 0x61, 0x28, 0x31, 0x3a, 0x6e,
+ 0x31, 0x32, 0x39, 0x3a, 0x00, 0xe1, 0x35, 0xc1,
+ 0x97, 0x90, 0xe8, 0x54, 0xa8, 0x3b, 0x97, 0x05,
+ 0xaf, 0x45, 0xaf, 0x67, 0xbf, 0xec, 0x07, 0xbe,
+ 0x9b, 0x55, 0x9c, 0x3f, 0x47, 0xae, 0x25, 0xb6,
+ 0xe3, 0x23, 0x99, 0x10, 0x5e, 0x17, 0x1a, 0xda,
+ 0x33, 0xe6, 0x73, 0x0d, 0x96, 0x9c, 0x5c, 0x25,
+ 0x13, 0x5d, 0x49, 0xb9, 0x86, 0xc0, 0xb1, 0x80,
+ 0x29, 0x20, 0xb2, 0x91, 0x72, 0x43, 0xcc, 0x2a,
+ 0x67, 0xd3, 0x11, 0xe8, 0x7b, 0x21, 0x75, 0xf6,
+ 0x1b, 0xc0, 0xb2, 0x01, 0xc8, 0x35, 0xaa, 0xfb,
+ 0xa7, 0x29, 0xb4, 0xb9, 0x94, 0x4e, 0x53, 0x49,
+ 0x82, 0x74, 0xe9, 0x23, 0x69, 0xa4, 0xf6, 0xdf,
+ 0x40, 0x2a, 0x73, 0x01, 0xfa, 0xe7, 0xf8, 0x32,
+ 0x6b, 0x57, 0xfe, 0xb9, 0x7d, 0x02, 0xc2, 0xfb,
+ 0x7f, 0x99, 0x1f, 0x6e, 0x8d, 0x53, 0x01, 0x56,
+ 0xaf, 0x46, 0x62, 0xb3, 0xe0, 0xa8, 0xa6, 0x0a,
+ 0x55, 0x2c, 0x4b, 0x85, 0x5b, 0x29, 0x28, 0x31,
+ 0x3a, 0x65, 0x33, 0x3a, 0x01, 0x00, 0x01, 0x29,
+ 0x29, 0x29,
+};
+
+/* Sample RSA signature of message "hello" with sample key. */
+static char sig_dump[] = {
+ 0x28, 0x37, 0x3a, 0x73, 0x69, 0x67, 0x2d, 0x76,
+ 0x61, 0x6c, 0x28, 0x33, 0x3a, 0x72, 0x73, 0x61,
+ 0x28, 0x31, 0x3a, 0x73, 0x31, 0x32, 0x38, 0x3a,
+ 0x5b, 0x2d, 0xeb, 0xa5, 0x4b, 0x8b, 0xd9, 0x92,
+ 0x66, 0x57, 0x89, 0xd8, 0x31, 0xc0, 0x0e, 0x53,
+ 0xf8, 0x1c, 0x4f, 0xc8, 0x79, 0x67, 0xb9, 0x10,
+ 0xe5, 0x63, 0x5f, 0xef, 0xb1, 0x0b, 0x0e, 0x7f,
+ 0xed, 0x86, 0x06, 0xa8, 0x05, 0xbf, 0x6b, 0xd1,
+ 0x36, 0x41, 0x08, 0x3b, 0xd0, 0xbd, 0xef, 0xb7,
+ 0xc2, 0x69, 0xb8, 0xb4, 0x3e, 0x2c, 0xb5, 0x39,
+ 0x13, 0x03, 0xca, 0xad, 0x5f, 0xd2, 0x57, 0x23,
+ 0x19, 0xdd, 0x71, 0xdd, 0x93, 0xe1, 0x3e, 0x43,
+ 0xaf, 0xdd, 0x94, 0x07, 0xf3, 0x78, 0xb3, 0x2a,
+ 0x57, 0x24, 0x97, 0x04, 0x58, 0xc1, 0xaf, 0xd3,
+ 0xe7, 0xa7, 0x65, 0xd1, 0x23, 0xa3, 0x93, 0x18,
+ 0xc7, 0x52, 0x70, 0x53, 0x60, 0x8b, 0x5a, 0x5d,
+ 0x6e, 0xf9, 0x83, 0x52, 0x99, 0xbb, 0x0a, 0x53,
+ 0x0e, 0x2a, 0x7f, 0x81, 0x52, 0x02, 0x32, 0xa4,
+ 0xfc, 0xe0, 0x17, 0x0c, 0x0e, 0x96, 0xbd, 0x01,
+ 0x29, 0x29, 0x29,
+};
+
+extern gcry_pk_spec_t _gcry_pubkey_spec_rsa;
+
+static void
+rsa_sexp_test (void)
+{
+ gcry_sexp_t sign_parms, sign_parms_invalid, pubkey, sig;
+ int rc;
+ grub_size_t errof;
+
+ rc = _gcry_sexp_build (&sign_parms_invalid, &errof,
+ "(data (flags) (value \"hi\"))\n");
+ grub_test_assert (rc == 0, "sexp build failed");
+
+ rc = _gcry_sexp_build (&sign_parms, &errof,
+ "(data (flags) (value \"hello\"))\n");
+ grub_test_assert (rc == 0, "sexp build failed");
+ rc = _gcry_sexp_new (&pubkey, pubkey_dump, sizeof(pubkey_dump), 0);
+ grub_test_assert (rc == 0, "sexp new failed");
+ rc = _gcry_sexp_new (&sig, sig_dump, sizeof(sig_dump), 0);
+ grub_test_assert (rc == 0, "sexp new failed");
+ rc = _gcry_pubkey_spec_rsa.verify (sig, sign_parms, pubkey);
+ grub_test_assert (rc == 0, "signature verification failed: %d", rc);
+ rc = _gcry_pubkey_spec_rsa.verify (sig, sign_parms_invalid, pubkey);
+ grub_test_assert (rc != 0, "signature verification succeded wrongly");
+}
+
+GRUB_FUNCTIONAL_TEST (rsa_sexp_test, rsa_sexp_test);

View File

@ -0,0 +1,47 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Vladimir Serbinenko <phcoder@gmail.com>
Date: Mon, 7 Jul 2025 14:52:12 +0000
Subject: [PATCH] keccak: Disable acceleration with SSE asm
Libgcrypt code assumes that on x64 all SSE registers are fair game.
While it's true that CPUs in question support it, we disable it in
our compilation options. Disable the offending optimization.
Signed-off-by: Vladimir Serbinenko <phcoder@gmail.com>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
---
.../lib/libgcrypt-patches/02_keccak_sse.patch | 25 ++++++++++++++++++++++
1 file changed, 25 insertions(+)
create mode 100644 grub-core/lib/libgcrypt-patches/02_keccak_sse.patch
diff --git a/grub-core/lib/libgcrypt-patches/02_keccak_sse.patch b/grub-core/lib/libgcrypt-patches/02_keccak_sse.patch
new file mode 100644
index 0000000..4deda12
--- /dev/null
+++ b/grub-core/lib/libgcrypt-patches/02_keccak_sse.patch
@@ -0,0 +1,25 @@
+commit b0cf06271da5fe20360953a53a47c69da89669cd
+Author: Vladimir Serbinenko <phcoder@gmail.com>
+Date: Sun Apr 7 03:33:11 2024 +0000
+
+ keccak: Disable acceleration with SSE asm
+
+ Libgcrypt code assumes that on x64 all SSE registers are fair game.
+ While it's true that CPUs in question support it, we disable it in
+ our compilation options. Disable the offending optimization.
+
+ Signed-off-by: Vladimir Serbinenko <phcoder@gmail.com>
+
+diff --git a/grub-core/lib/libgcrypt/cipher/keccak.c b/grub-core/lib/libgcrypt/cipher/keccak.c
+index 11e64b3e7..8b570263b 100644
+--- a/grub-core/lib/libgcrypt-grub/cipher/keccak.c
++++ b/grub-core/lib/libgcrypt-grub/cipher/keccak.c
+@@ -275,7 +275,7 @@ keccak_absorb_lane32bi(u32 *lane, u32 x0, u32 x1)
+ /* Construct generic 64-bit implementation. */
+ #ifdef USE_64BIT
+
+-#if __GNUC__ >= 4 && defined(__x86_64__)
++#if __GNUC__ >= 4 && defined(__x86_64__) && 0
+
+ static inline void absorb_lanes64_8(u64 *dst, const byte *in)
+ {

View File

@ -0,0 +1,79 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Vladimir Serbinenko <phcoder@gmail.com>
Date: Mon, 7 Jul 2025 14:52:13 +0000
Subject: [PATCH] libgcrypt: Fix Coverity warnings
Signed-off-by: Vladimir Serbinenko <phcoder@gmail.com>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
---
.../lib/libgcrypt-patches/03_mpiutil_alloc.patch | 18 +++++++++++
grub-core/lib/libgcrypt-patches/03_sexp_free.patch | 35 ++++++++++++++++++++++
2 files changed, 53 insertions(+)
create mode 100644 grub-core/lib/libgcrypt-patches/03_mpiutil_alloc.patch
create mode 100644 grub-core/lib/libgcrypt-patches/03_sexp_free.patch
diff --git a/grub-core/lib/libgcrypt-patches/03_mpiutil_alloc.patch b/grub-core/lib/libgcrypt-patches/03_mpiutil_alloc.patch
new file mode 100644
index 0000000..42c6b2b
--- /dev/null
+++ b/grub-core/lib/libgcrypt-patches/03_mpiutil_alloc.patch
@@ -0,0 +1,18 @@
+mpiutil: Fix NULL pointer dereference in case of failed alloc
+
+Signed-off-by: Vladimir Serbinenko <phcoder@gmail.com>
+
+diff --git a/grub-core/lib/libgcrypt/mpi/mpiutil.c b/grub-core/lib/libgcrypt/mpi/mpiutil.c
+index 3a372374f..dc53db09d 100644
+--- a/grub-core/lib/libgcrypt-grub/mpi/mpiutil.c
++++ b/grub-core/lib/libgcrypt-grub/mpi/mpiutil.c
+@@ -432,6 +432,9 @@ _gcry_mpi_alloc_like( gcry_mpi_t a )
+ int n = (a->sign+7)/8;
+ void *p = _gcry_is_secure(a->d)? xtrymalloc_secure (n)
+ : xtrymalloc (n);
++ if ( !p ) {
++ _gcry_fatal_error (GPG_ERR_ENOMEM, NULL);
++ }
+ memcpy( p, a->d, n );
+ b = mpi_set_opaque( NULL, p, a->sign );
+ }
diff --git a/grub-core/lib/libgcrypt-patches/03_sexp_free.patch b/grub-core/lib/libgcrypt-patches/03_sexp_free.patch
new file mode 100644
index 0000000..1c0ffd6
--- /dev/null
+++ b/grub-core/lib/libgcrypt-patches/03_sexp_free.patch
@@ -0,0 +1,35 @@
+sexp: Add missing free on error path
+
+Signed-off-by: Vladimir Serbinenko <phcoder@gmail.com>
+
+diff --git a/grub-core/lib/libgcrypt/src/sexp.c b/grub-core/lib/libgcrypt/src/sexp.c
+index d15f1a790..250559f75 100644
+--- a/grub-core/lib/libgcrypt-grub/src/sexp.c
++++ b/grub-core/lib/libgcrypt-grub/src/sexp.c
+@@ -1157,6 +1157,17 @@ do_vsexp_sscan (gcry_sexp_t *retsexp, size_t *erroff,
+ } \
+ } while (0)
+
++#define MAKE_SPACE_EXTRA_CLEANUP(n, cleanup) do { \
++ gpg_err_code_t _ms_err = make_space (&c, (n)); \
++ if (_ms_err) \
++ { \
++ err = _ms_err; \
++ *erroff = p - buffer; \
++ cleanup; \
++ goto leave; \
++ } \
++ } while (0)
++
+ /* The STORE_LEN macro is used to store the length N at buffer P. */
+ #define STORE_LEN(p,n) do { \
+ DATALEN ashort = (n); \
+@@ -1368,7 +1379,7 @@ do_vsexp_sscan (gcry_sexp_t *retsexp, size_t *erroff,
+ goto leave;
+ }
+
+- MAKE_SPACE (datalen);
++ MAKE_SPACE_EXTRA_CLEANUP (datalen, xfree (b64buf));
+ *c.pos++ = ST_DATA;
+ STORE_LEN (c.pos, datalen);
+ for (i = 0; i < datalen; i++)

View File

@ -0,0 +1,40 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Vladimir Serbinenko <phcoder@gmail.com>
Date: Mon, 7 Jul 2025 14:52:14 +0000
Subject: [PATCH] libgcrypt: Remove now unneeded compilation flag
HAVE_STRTOUL is now defined in stdlib.h. Include it in g10lib.h rather
than defining on command line.
Signed-off-by: Vladimir Serbinenko <phcoder@gmail.com>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
---
conf/Makefile.common | 2 +-
util/import_gcry.py | 1 +
2 files changed, 2 insertions(+), 1 deletion(-)
diff --git a/conf/Makefile.common b/conf/Makefile.common
index c11ab27..5344a08 100644
--- a/conf/Makefile.common
+++ b/conf/Makefile.common
@@ -85,7 +85,7 @@ CFLAGS_POSIX = -fno-builtin
CPPFLAGS_POSIX = -I$(top_srcdir)/grub-core/lib/posix_wrap
CFLAGS_GCRY = -Wno-error=sign-compare -Wno-missing-field-initializers -Wno-redundant-decls -Wno-undef $(CFLAGS_POSIX)
-CPPFLAGS_GCRY = -I$(top_srcdir)/grub-core/lib/libgcrypt_wrap $(CPPFLAGS_POSIX) -D_GCRYPT_IN_LIBGCRYPT=1 -D_GCRYPT_CONFIG_H_INCLUDED=1 -DHAVE_STRTOUL=1 -I$(top_srcdir)/include/grub/gcrypt
+CPPFLAGS_GCRY = -I$(top_srcdir)/grub-core/lib/libgcrypt_wrap $(CPPFLAGS_POSIX) -D_GCRYPT_IN_LIBGCRYPT=1 -D_GCRYPT_CONFIG_H_INCLUDED=1 -I$(top_srcdir)/include/grub/gcrypt
CPPFLAGS_EFIEMU = -I$(top_srcdir)/grub-core/efiemu/runtime
diff --git a/util/import_gcry.py b/util/import_gcry.py
index 489356d..1be18cf 100644
--- a/util/import_gcry.py
+++ b/util/import_gcry.py
@@ -617,6 +617,7 @@ for src in sorted (os.listdir (os.path.join (indir, "src"))):
if src == "g10lib.h":
fw.write("#include <cipher_wrap.h>\n")
fw.write("#include <grub/crypto.h>\n")
+ fw.write("#include <stdlib.h>\n")
fw.write (f.read ().replace ("(printf,f,a)", "(__printf__,f,a)").replace ("#include \"../compat/libcompat.h\"", "").replace("#define N_(a) (a)", ""))
f.close ()
fw.close ()

View File

@ -0,0 +1,90 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Vladimir Serbinenko <phcoder@gmail.com>
Date: Mon, 7 Jul 2025 14:52:15 +0000
Subject: [PATCH] libgcrypt: Ignore sign-compare warnings
libgcrypt itself is compiled with -Wno-sign-compare. Do the same for consistency.
Signed-off-by: Vladimir Serbinenko <phcoder@gmail.com>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
---
conf/Makefile.common | 2 +-
grub-core/Makefile.core.def | 10 +++++-----
util/import_gcry.py | 2 +-
3 files changed, 7 insertions(+), 7 deletions(-)
diff --git a/conf/Makefile.common b/conf/Makefile.common
index 5344a08..f25abeb 100644
--- a/conf/Makefile.common
+++ b/conf/Makefile.common
@@ -84,7 +84,7 @@ CPPFLAGS_GNULIB = -I$(top_builddir)/grub-core/lib/gnulib -I$(top_srcdir)/grub-co
CFLAGS_POSIX = -fno-builtin
CPPFLAGS_POSIX = -I$(top_srcdir)/grub-core/lib/posix_wrap
-CFLAGS_GCRY = -Wno-error=sign-compare -Wno-missing-field-initializers -Wno-redundant-decls -Wno-undef $(CFLAGS_POSIX)
+CFLAGS_GCRY = -Wno-sign-compare -Wno-missing-field-initializers -Wno-redundant-decls -Wno-undef $(CFLAGS_POSIX)
CPPFLAGS_GCRY = -I$(top_srcdir)/grub-core/lib/libgcrypt_wrap $(CPPFLAGS_POSIX) -D_GCRYPT_IN_LIBGCRYPT=1 -D_GCRYPT_CONFIG_H_INCLUDED=1 -I$(top_srcdir)/include/grub/gcrypt
CPPFLAGS_EFIEMU = -I$(top_srcdir)/grub-core/efiemu/runtime
diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def
index 0b6b996..ba4ed96 100644
--- a/grub-core/Makefile.core.def
+++ b/grub-core/Makefile.core.def
@@ -1012,7 +1012,7 @@ module = {
module = {
name = pgp;
common = commands/pgp.c;
- cflags = '$(CFLAGS_GCRY) -Wno-redundant-decls -Wno-sign-compare';
+ cflags = '$(CFLAGS_GCRY) -Wno-redundant-decls';
cppflags = '$(CPPFLAGS_GCRY)';
};
@@ -2219,7 +2219,7 @@ module = {
name = dsa_sexp_test;
common = tests/dsa_sexp_test.c;
- cflags = '$(CFLAGS_GCRY) -Wno-redundant-decls -Wno-sign-compare';
+ cflags = '$(CFLAGS_GCRY) -Wno-redundant-decls';
cppflags = '$(CPPFLAGS_GCRY)';
};
@@ -2227,7 +2227,7 @@ module = {
name = rsa_sexp_test;
common = tests/rsa_sexp_test.c;
- cflags = '$(CFLAGS_GCRY) -Wno-redundant-decls -Wno-sign-compare';
+ cflags = '$(CFLAGS_GCRY) -Wno-redundant-decls';
cppflags = '$(CPPFLAGS_GCRY)';
};
@@ -2607,7 +2607,7 @@ module = {
common = lib/libgcrypt_wrap/mem.c;
common = lib/libgcrypt-grub/cipher/md.c;
- cflags = '$(CFLAGS_GCRY) -Wno-redundant-decls -Wno-sign-compare -Wno-unused-but-set-variable';
+ cflags = '$(CFLAGS_GCRY) -Wno-redundant-decls -Wno-unused-but-set-variable';
cppflags = '$(CPPFLAGS_GCRY)';
};
@@ -2619,7 +2619,7 @@ module = {
common = lib/libgcrypt-grub/src/sexp.c;
common = lib/b64dec.c;
- cflags = '$(CFLAGS_GCRY) -Wno-redundant-decls -Wno-sign-compare';
+ cflags = '$(CFLAGS_GCRY) -Wno-redundant-decls';
cppflags = '$(CPPFLAGS_GCRY)';
};
diff --git a/util/import_gcry.py b/util/import_gcry.py
index 1be18cf..a4411ec 100644
--- a/util/import_gcry.py
+++ b/util/import_gcry.py
@@ -551,7 +551,7 @@ for cipher_file in cipher_files:
confutil.write (" common = grub-core/lib/libgcrypt-grub/cipher/%s;\n" % src)
if modname == "gcry_ecc":
conf.write (" common = lib/libgcrypt-grub/mpi/ec.c;\n")
- conf.write (" cflags = '$(CFLAGS_GCRY) -Wno-redundant-decls -Wno-sign-compare';\n")
+ conf.write (" cflags = '$(CFLAGS_GCRY) -Wno-redundant-decls';\n")
elif modname == "gcry_rijndael" or modname == "gcry_md4" or modname == "gcry_md5" or modname == "gcry_rmd160" or modname == "gcry_sha1" or modname == "gcry_sha256" or modname == "gcry_sha512" or modname == "gcry_tiger":
# Alignment checked by hand
conf.write (" cflags = '$(CFLAGS_GCRY) -Wno-cast-align';\n");

View File

@ -0,0 +1,217 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Vladimir Serbinenko <phcoder@gmail.com>
Date: Mon, 7 Jul 2025 14:52:16 +0000
Subject: [PATCH] libgcrypt: Import blake family of hashes
Signed-off-by: Vladimir Serbinenko <phcoder@gmail.com>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
---
grub-core/lib/libgcrypt-patches/06_blake.patch | 80 ++++++++++++++++++++++++++
include/grub/crypto.h | 9 +++
util/import_gcry.py | 36 +++++++++---
3 files changed, 118 insertions(+), 7 deletions(-)
create mode 100644 grub-core/lib/libgcrypt-patches/06_blake.patch
diff --git a/grub-core/lib/libgcrypt-patches/06_blake.patch b/grub-core/lib/libgcrypt-patches/06_blake.patch
new file mode 100644
index 0000000..c3b9d6f
--- /dev/null
+++ b/grub-core/lib/libgcrypt-patches/06_blake.patch
@@ -0,0 +1,80 @@
+--- a/grub-core/lib/libgcrypt-grub/cipher/blake2.c
++++ b/grub-core/lib/libgcrypt-grub/cipher/blake2.c
+@@ -841,68 +841,6 @@
+ return blake2s_init(c, key, keylen);
+ }
+
+-/* Selftests from "RFC 7693, Appendix E. BLAKE2b and BLAKE2s Self-Test
+- * Module C Source". */
+-static void selftest_seq(byte *out, size_t len, u32 seed)
+-{
+- size_t i;
+- u32 t, a, b;
+-
+- a = 0xDEAD4BAD * seed;
+- b = 1;
+-
+- for (i = 0; i < len; i++)
+- {
+- t = a + b;
+- a = b;
+- b = t;
+- out[i] = (t >> 24) & 0xFF;
+- }
+-}
+-
+-
+-
+-
+-gcry_err_code_t _gcry_blake2_init_with_key(void *ctx, unsigned int flags,
+- const unsigned char *key,
+- size_t keylen, int algo)
+-{
+- gcry_err_code_t rc;
+- switch (algo)
+- {
+- case GCRY_MD_BLAKE2B_512:
+- rc = blake2b_init_ctx (ctx, flags, key, keylen, 512);
+- break;
+- case GCRY_MD_BLAKE2B_384:
+- rc = blake2b_init_ctx (ctx, flags, key, keylen, 384);
+- break;
+- case GCRY_MD_BLAKE2B_256:
+- rc = blake2b_init_ctx (ctx, flags, key, keylen, 256);
+- break;
+- case GCRY_MD_BLAKE2B_160:
+- rc = blake2b_init_ctx (ctx, flags, key, keylen, 160);
+- break;
+- case GCRY_MD_BLAKE2S_256:
+- rc = blake2s_init_ctx (ctx, flags, key, keylen, 256);
+- break;
+- case GCRY_MD_BLAKE2S_224:
+- rc = blake2s_init_ctx (ctx, flags, key, keylen, 224);
+- break;
+- case GCRY_MD_BLAKE2S_160:
+- rc = blake2s_init_ctx (ctx, flags, key, keylen, 160);
+- break;
+- case GCRY_MD_BLAKE2S_128:
+- rc = blake2s_init_ctx (ctx, flags, key, keylen, 128);
+- break;
+- default:
+- rc = GPG_ERR_DIGEST_ALGO;
+- break;
+- }
+-
+- return rc;
+-}
+-
+-
+ #define DEFINE_BLAKE2_VARIANT(bs, BS, dbits, oid_branch) \
+ static void blake2##bs##_##dbits##_init(void *ctx, unsigned int flags) \
+ { \
+@@ -936,7 +874,7 @@
+ dbits / 8, blake2##bs##_##dbits##_init, blake2##bs##_write, \
+ blake2##bs##_final, blake2##bs##_read, NULL, \
+ _gcry_blake2##bs##_##dbits##_hash_buffers, \
+- sizeof (BLAKE2##BS##_CONTEXT), selftests_blake2##bs \
++ sizeof (BLAKE2##BS##_CONTEXT) \
+ , \
+ GRUB_UTIL_MODNAME("gcry_blake2") \
+ .blocksize = GRUB_BLAKE2 ## BS ## _BLOCK_SIZE \
diff --git a/include/grub/crypto.h b/include/grub/crypto.h
index 25b1188..b0d7add 100644
--- a/include/grub/crypto.h
+++ b/include/grub/crypto.h
@@ -586,8 +586,14 @@ void grub_gcry_fini_all (void);
int
grub_get_random (void *out, grub_size_t len);
+#define GRUB_UTIL_MODNAME(x) .modname = x,
+#else
+#define GRUB_UTIL_MODNAME(x)
#endif
+#define GRUB_BLAKE2B_BLOCK_SIZE 128
+#define GRUB_BLAKE2S_BLOCK_SIZE 64
+
typedef struct _gpgrt_b64state *gpgrt_b64state_t;
gpgrt_b64state_t gpgrt_b64dec_start (const char *title);
gpg_error_t gpgrt_b64dec_proc (gpgrt_b64state_t state,
@@ -595,4 +601,7 @@ gpg_error_t gpgrt_b64dec_proc (gpgrt_b64state_t state,
grub_size_t *r_nbytes);
gpg_error_t gpgrt_b64dec_finish (gpgrt_b64state_t state);
const char *gpg_strerror (gpg_error_t err);
+
+gcry_err_code_t blake2b_vl_hash (const void *in, grub_size_t inlen,
+ grub_size_t outputlen, void *output);
#endif
diff --git a/util/import_gcry.py b/util/import_gcry.py
index a4411ec..ca918c7 100644
--- a/util/import_gcry.py
+++ b/util/import_gcry.py
@@ -120,7 +120,8 @@ mdblocksizes = {"_gcry_digest_spec_crc32" : 64,
"_gcry_digest_spec_gost3411_94": 32,
"_gcry_digest_spec_gost3411_cp": 32,
"_gcry_digest_spec_cshake128": 64,
- "_gcry_digest_spec_cshake256": 64}
+ "_gcry_digest_spec_cshake256": 64,
+ "_gcry_digest_spec_blake2": "GRUB_BLAKE2 ## BS ## _BLOCK_SIZE"}
cryptolist = codecs.open (os.path.join (cipher_dir_out, "crypto.lst"), "w", "utf-8")
@@ -209,6 +210,7 @@ for cipher_file in cipher_files:
skip = 0
skip2 = False
ismd = False
+ ismddefine = False
mdarg = 0
ispk = False
iscipher = False
@@ -245,19 +247,19 @@ for cipher_file in cipher_files:
mdarg = mdarg + len (spl) - 1
if ismd or iscipher or ispk:
if not re.search (" *};", line) is None:
+ escapenl = " \\" if ismddefine else ""
if not iscomma:
- fw.write (" ,\n")
- fw.write ("#ifdef GRUB_UTIL\n");
- fw.write (" .modname = \"%s\",\n" % modname);
- fw.write ("#endif\n");
+ fw.write (f" ,{escapenl}\n")
+ fw.write (f" GRUB_UTIL_MODNAME(\"%s\"){escapenl}\n" % modname);
if ismd:
if not (mdname in mdblocksizes):
print ("ERROR: Unknown digest blocksize: %s\n"
% mdname)
exit (1)
- fw.write (" .blocksize = %s\n"
+ fw.write (f" .blocksize = %s{escapenl}\n"
% mdblocksizes [mdname])
ismd = False
+ ismddefine = False
mdarg = 0
iscipher = False
ispk = False
@@ -281,7 +283,7 @@ for cipher_file in cipher_files:
hold = False
# We're optimising for size and exclude anything needing good
# randomness.
- if re.match ("(_gcry_hash_selftest_check_one|bulk_selftest_setkey|run_selftests|do_tripledes_set_extra_info|selftest|sm4_selftest|_gcry_[a-z0-9_]*_hash_buffers|_gcry_sha1_hash_buffer|tripledes_set2keys|_gcry_rmd160_mixblock|serpent_test|dsa_generate_ext|test_keys|gen_k|sign|gen_x931_parm_xp|generate_x931|generate_key|dsa_generate|dsa_sign|ecc_sign|generate|generate_fips186|_gcry_register_pk_dsa_progress|_gcry_register_pk_ecc_progress|progress|scanval|ec2os|ecc_generate_ext|ecc_generate|ecc_get_param|_gcry_register_pk_dsa_progress|gen_x931_parm_xp|gen_x931_parm_xi|rsa_decrypt|rsa_sign|rsa_generate_ext|rsa_generate|secret|check_exponent|rsa_blind|rsa_unblind|extract_a_from_sexp|curve_free|curve_copy|point_set|_gcry_dsa_gen_rfc6979_k|bits2octets|int2octets|_gcry_md_debug|_gcry_md_selftest|_gcry_md_is_enabled|_gcry_md_is_secure|_gcry_md_init|_gcry_md_info|md_get_algo|md_extract|_gcry_md_get |_gcry_md_get_algo |_gcry_md_extract|_gcry_md_setkey|md_setkey|prepare_macpads|_gcry_md_algo_name|search_oid|spec_from_oid|spec_from_name|spec_from_algo|map_algo|cshake_hash_buffers)", line) is not None:
+ if re.match ("(_gcry_hash_selftest_check_one|bulk_selftest_setkey|run_selftests|do_tripledes_set_extra_info|selftest|sm4_selftest|_gcry_[a-z0-9_]*_hash_buffers|_gcry_sha1_hash_buffer|tripledes_set2keys|_gcry_rmd160_mixblock|serpent_test|dsa_generate_ext|test_keys|gen_k|sign|gen_x931_parm_xp|generate_x931|generate_key|dsa_generate|dsa_sign|ecc_sign|generate|generate_fips186|_gcry_register_pk_dsa_progress|_gcry_register_pk_ecc_progress|progress|scanval|ec2os|ecc_generate_ext|ecc_generate|ecc_get_param|_gcry_register_pk_dsa_progress|gen_x931_parm_xp|gen_x931_parm_xi|rsa_decrypt|rsa_sign|rsa_generate_ext|rsa_generate|secret|check_exponent|rsa_blind|rsa_unblind|extract_a_from_sexp|curve_free|curve_copy|point_set|_gcry_dsa_gen_rfc6979_k|bits2octets|int2octets|_gcry_md_debug|_gcry_md_selftest|_gcry_md_is_enabled|_gcry_md_is_secure|_gcry_md_init|_gcry_md_info|md_get_algo|md_extract|_gcry_md_get |_gcry_md_get_algo |_gcry_md_extract|_gcry_md_setkey|md_setkey|prepare_macpads|_gcry_md_algo_name|search_oid|spec_from_oid|spec_from_name|spec_from_algo|map_algo|cshake_hash_buffers|selftest_seq)", line) is not None:
skip = 1
if not re.match ("selftest", line) is None and cipher_file == "idea.c":
@@ -355,6 +357,13 @@ for cipher_file in cipher_files:
ispk = True
iscryptostart = True
+ m = re.match (r"DEFINE_BLAKE2_VARIANT\((.), (.), ([0-9]*)", line)
+ if isc and not m is None:
+ bs = m.groups()[0]
+ bits = m.groups()[2]
+ mdname = f"_gcry_digest_spec_blake2{bs}_{bits}"
+ mdnames.append (mdname)
+
m = re.match ("(const )?gcry_md_spec_t", line)
if isc and not m is None:
assert (not ismd)
@@ -366,6 +375,19 @@ for cipher_file in cipher_files:
mdname = re.match("[a-zA-Z0-9_]*",mdname).group ()
mdnames.append (mdname)
ismd = True
+ ismddefine = False
+ mdarg = 0
+ iscryptostart = True
+ m = re.match (" (const )?gcry_md_spec_t _gcry_digest_spec_blake2.*\\\\", line)
+ if isc and not m is None:
+ assert (not ismd)
+ assert (not ispk)
+ assert (not iscipher)
+ assert (not iscryptostart)
+ line = removeprefix(line, " const ")
+ ismd = True
+ ismddefine = True
+ mdname = "_gcry_digest_spec_blake2"
mdarg = 0
iscryptostart = True
m = re.match (r"static const char \*selftest.*;$", line)

View File

@ -0,0 +1,44 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Vladimir Serbinenko <phcoder@gmail.com>
Date: Mon, 7 Jul 2025 14:52:17 +0000
Subject: [PATCH] util/import_gcry: Make compatible with Python 3.4
Signed-off-by: Vladimir Serbinenko <phcoder@gmail.com>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
---
util/import_gcry.py | 10 +++++-----
1 file changed, 5 insertions(+), 5 deletions(-)
diff --git a/util/import_gcry.py b/util/import_gcry.py
index ca918c7..9b0e8d9 100644
--- a/util/import_gcry.py
+++ b/util/import_gcry.py
@@ -249,15 +249,15 @@ for cipher_file in cipher_files:
if not re.search (" *};", line) is None:
escapenl = " \\" if ismddefine else ""
if not iscomma:
- fw.write (f" ,{escapenl}\n")
- fw.write (f" GRUB_UTIL_MODNAME(\"%s\"){escapenl}\n" % modname);
+ fw.write (" ,%s\n" % escapenl)
+ fw.write (" GRUB_UTIL_MODNAME(\"%s\")%s\n" % (modname, escapenl))
if ismd:
if not (mdname in mdblocksizes):
print ("ERROR: Unknown digest blocksize: %s\n"
% mdname)
exit (1)
- fw.write (f" .blocksize = %s{escapenl}\n"
- % mdblocksizes [mdname])
+ fw.write (" .blocksize = %s%s\n"
+ % (mdblocksizes [mdname], escapenl))
ismd = False
ismddefine = False
mdarg = 0
@@ -361,7 +361,7 @@ for cipher_file in cipher_files:
if isc and not m is None:
bs = m.groups()[0]
bits = m.groups()[2]
- mdname = f"_gcry_digest_spec_blake2{bs}_{bits}"
+ mdname = "_gcry_digest_spec_blake2%s_%s" % (bs, bits)
mdnames.append (mdname)
m = re.match ("(const )?gcry_md_spec_t", line)

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,34 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Vladimir Serbinenko <phcoder@gmail.com>
Date: Mon, 7 Jul 2025 14:52:19 +0000
Subject: [PATCH] libgcrypt: Don't use 64-bit division on platforms where it's
slow
Signed-off-by: Vladimir Serbinenko <phcoder@gmail.com>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
---
grub-core/lib/libgcrypt-patches/07_disable_64div.patch | 15 +++++++++++++++
1 file changed, 15 insertions(+)
create mode 100644 grub-core/lib/libgcrypt-patches/07_disable_64div.patch
diff --git a/grub-core/lib/libgcrypt-patches/07_disable_64div.patch b/grub-core/lib/libgcrypt-patches/07_disable_64div.patch
new file mode 100644
index 0000000..bb47bdf
--- /dev/null
+++ b/grub-core/lib/libgcrypt-patches/07_disable_64div.patch
@@ -0,0 +1,15 @@
+Don't use 64-bit division on platforms where it's slow
+
+diff --git a/grub-core/lib/libgcrypt/mpi/longlong.h b/grub-core/lib/libgcrypt/mpi/longlong.h
+index 21bd1a7ef..672448724 100644
+--- a/grub-core/lib/libgcrypt-grub/mpi/longlong.h
++++ b/grub-core/lib/libgcrypt-grub/mpi/longlong.h
+@@ -1711,7 +1711,7 @@ typedef unsigned int UTItype __attribute__ ((mode (TI)));
+ } while (0)
+
+ /* Use double word type if available. */
+-#if !defined (udiv_qrnnd) && defined (UDWtype)
++#if !defined (udiv_qrnnd) && defined (UDWtype) && !defined(__arm__) && !defined(__mips__) && !defined(__powerpc__)
+ # define udiv_qrnnd(q, r, nh, nl, d) \
+ do { \
+ UWtype __d = (d); \

View File

@ -0,0 +1,41 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Vladimir Serbinenko <phcoder@gmail.com>
Date: Mon, 7 Jul 2025 14:52:20 +0000
Subject: [PATCH] libgcrypt: Fix a memory leak
Fixes: CID 468917
Signed-off-by: Vladimir Serbinenko <phcoder@gmail.com>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
---
grub-core/lib/libgcrypt-patches/08_sexp_leak.patch | 21 +++++++++++++++++++++
1 file changed, 21 insertions(+)
create mode 100644 grub-core/lib/libgcrypt-patches/08_sexp_leak.patch
diff --git a/grub-core/lib/libgcrypt-patches/08_sexp_leak.patch b/grub-core/lib/libgcrypt-patches/08_sexp_leak.patch
new file mode 100644
index 0000000..eefd031
--- /dev/null
+++ b/grub-core/lib/libgcrypt-patches/08_sexp_leak.patch
@@ -0,0 +1,21 @@
+sexp: Fix a memory leak
+
+Fixes: CID 468917
+
+Signed-off-by: Vladimir Serbinenko <phcoder@gmail.com>
+
+diff -ur ../libgcrypt-1.11.0/src/sexp.c grub-core/lib/libgcrypt/src/sexp.c
+--- a/grub-core/lib/libgcrypt-grub/src/sexp.c 2024-03-28 10:07:27.000000000 +0000
++++ b/grub-core/lib/libgcrypt-grub/src/sexp.c 2025-07-02 17:10:32.714864459 +0000
+@@ -2725,8 +2725,10 @@
+ length = 0;
+ for (s=string; *s; s +=2 )
+ {
+- if (!hexdigitp (s) || !hexdigitp (s+1))
++ if (!hexdigitp (s) || !hexdigitp (s+1)) {
++ free (buffer);
+ return NULL; /* Invalid hex digits. */
++ }
+ ((unsigned char*)buffer)[length++] = xtoi_2 (s);
+ }
+ *r_length = length;

View File

@ -0,0 +1,67 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Vladimir Serbinenko <phcoder@gmail.com>
Date: Mon, 7 Jul 2025 14:52:21 +0000
Subject: [PATCH] docs: Write how to import new libgcrypt
Signed-off-by: Vladimir Serbinenko <phcoder@gmail.com>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
---
docs/grub-dev.texi | 38 ++++++++++++++++++++++++++++++++++++++
1 file changed, 38 insertions(+)
diff --git a/docs/grub-dev.texi b/docs/grub-dev.texi
index 8ad5494..090cc88 100644
--- a/docs/grub-dev.texi
+++ b/docs/grub-dev.texi
@@ -506,6 +506,7 @@ to update it.
* Gnulib::
* jsmn::
* minilzo::
+* libgcrypt::
@end menu
@node Gnulib
@@ -596,6 +597,43 @@ cp minilzo-2.10/*.[hc] grub-core/lib/minilzo
rm -r minilzo-2.10*
@end example
+@node libgcrypt
+@section libgcrypt
+
+libgcrypt is a GNU implementation of crypto library. To import a new version
+you need to unpack the release tarball into grub-core/lib/libgcrypt. Delete
+following files/directories:
+* acinclude.m4
+* aclocal.m4
+* autogen.rc
+* autogen.sh
+* build-aux
+* ChangeLog
+* ChangeLog-2011
+* doc
+* INSTALL
+* m4
+* Makefile.am
+* Makefile.in
+* NEWS
+* random
+* tests
+* TODO
+* */Makefile.in
+* mpi/hppa1.1
+
+Regenerate the file gost-sb.h:
+grub-core/lib/libgcrypt/cipher$ gcc -o gost-s-box gost-s-box.c
+grub-core/lib/libgcrypt/cipher$ ./gost-s-box gost-sb.h
+
+Then rerun ./bootstrap and pay attention to the errors. Especially to warnings
+that a file isn't a module as it means that some file is actually unused by
+GRUB. If any, find where it declares its cipher or hash and add a pattern to
+import_gcry.py. See commit ``libgcrypt: Import blake family of hashes'' for an
+example. If file reallly is useless to GRUB in its current state, add it to
+whitelist in import_gcry.py.
+Compile and fix any new errors. Put patches into grub-core/lib/libgcrypt-patches
+
@node Debugging
@chapter Debugging

View File

@ -0,0 +1,36 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Sudhakar Kuppusamy <sudhakar@linux.ibm.com>
Date: Mon, 6 Oct 2025 12:54:48 +0530
Subject: [PATCH] pgp: Rename OBJ_TYPE_PUBKEY to OBJ_TYPE_GPG_PUBKEY
Prior to the addition of the X.509 public key support for appended signature,
current PGP signature relied on the GPG public key. Changing the enum name
from "OBJ_TYPE_PUBKEY" to "OBJ_TYPE_GPG_PUBKEY" to differentiate between x509
certificate based appended signature and GPG certificate based PGP signature.
Signed-off-by: Alastair D'Silva <alastair@d-silva.org>
Signed-off-by: Daniel Axtens <dja@axtens.net>
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>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
---
include/grub/kernel.h | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/include/grub/kernel.h b/include/grub/kernel.h
index f98a780..8fdbde2 100644
--- a/include/grub/kernel.h
+++ b/include/grub/kernel.h
@@ -28,10 +28,9 @@ enum
OBJ_TYPE_MEMDISK,
OBJ_TYPE_CONFIG,
OBJ_TYPE_PREFIX,
- OBJ_TYPE_PUBKEY,
+ OBJ_TYPE_GPG_PUBKEY,
OBJ_TYPE_DTB,
OBJ_TYPE_DISABLE_SHIM_LOCK,
- OBJ_TYPE_GPG_PUBKEY,
OBJ_TYPE_X509_PUBKEY,
OBJ_TYPE_DISABLE_CLI
};

View File

@ -0,0 +1,210 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Sudhakar Kuppusamy <sudhakar@linux.ibm.com>
Date: Mon, 6 Oct 2025 12:54:49 +0530
Subject: [PATCH] grub-install: Support embedding x509 certificates
To support verification of appended signatures, we need a way to embed the
necessary public keys. Existing appended signature schemes in the Linux kernel
use X.509 certificates, so allow certificates to be embedded in the GRUB core
image in the same way as PGP keys.
Signed-off-by: Alastair D'Silva <alastair@d-silva.org>
Signed-off-by: Daniel Axtens <dja@axtens.net>
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>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
---
include/grub/kernel.h | 2 +-
include/grub/util/install.h | 9 ++++-----
util/grub-install-common.c | 18 ++++++++----------
util/grub-mkimage.c | 6 +++---
util/mkimage.c | 38 +++++++++++++++++++++-----------------
5 files changed, 37 insertions(+), 36 deletions(-)
diff --git a/include/grub/kernel.h b/include/grub/kernel.h
index 8fdbde2b0613..05f141201c61 100644
--- a/include/grub/kernel.h
+++ b/include/grub/kernel.h
@@ -29,9 +29,9 @@ enum
OBJ_TYPE_CONFIG,
OBJ_TYPE_PREFIX,
OBJ_TYPE_GPG_PUBKEY,
+ OBJ_TYPE_X509_PUBKEY,
OBJ_TYPE_DTB,
OBJ_TYPE_DISABLE_SHIM_LOCK,
- OBJ_TYPE_X509_PUBKEY,
OBJ_TYPE_DISABLE_CLI
};
diff --git a/include/grub/util/install.h b/include/grub/util/install.h
index dbf3c216d413..93c1f0ed4e0d 100644
--- a/include/grub/util/install.h
+++ b/include/grub/util/install.h
@@ -67,13 +67,12 @@
N_("SBAT metadata"), 0 }, \
{ "disable-shim-lock", GRUB_INSTALL_OPTIONS_DISABLE_SHIM_LOCK, 0, 0, \
N_("disable shim_lock verifier"), 0 }, \
- { "x509key", 'x', N_("FILE"), 0, \
- N_("embed FILE as an x509 certificate for signature checking"), 0}, \
- { "appended-signature-size", GRUB_INSTALL_OPTIONS_APPENDED_SIGNATURE_SIZE,\
- "SIZE", 0, N_("Add a note segment reserving SIZE bytes for an appended signature"), \
- 1}, \
{ "disable-cli", GRUB_INSTALL_OPTIONS_DISABLE_CLI, 0, 0, \
N_("disabled command line interface access"), 0 }, \
+ { "x509key", 'x', N_("FILE"), 0, \
+ N_("embed FILE as an x509 certificate for appended signature checking"), 0}, \
+ { "appended-signature-size", GRUB_INSTALL_OPTIONS_APPENDED_SIGNATURE_SIZE, \
+ "SIZE", 0, N_("Add a note segment reserving SIZE bytes for an appended signature"), 1}, \
{ "verbose", 'v', 0, 0, \
N_("print verbose messages."), 1 }
diff --git a/util/grub-install-common.c b/util/grub-install-common.c
index 42aec141e444..41251cee798b 100644
--- a/util/grub-install-common.c
+++ b/util/grub-install-common.c
@@ -463,10 +463,10 @@ handle_install_list (struct install_list *il, const char *val,
static char **pubkeys;
static size_t npubkeys;
-static char *sbat;
-static int disable_shim_lock;
static char **x509keys;
static size_t nx509keys;
+static char *sbat;
+static int disable_shim_lock;
static grub_compression_t compression;
static size_t appsig_size;
static int disable_cli;
@@ -509,15 +509,13 @@ grub_install_parse (int key, char *arg)
case GRUB_INSTALL_OPTIONS_DISABLE_SHIM_LOCK:
disable_shim_lock = 1;
return 1;
- case 'x':
- x509keys = xrealloc (x509keys,
- sizeof (x509keys[0])
- * (nx509keys + 1));
- x509keys[nx509keys++] = xstrdup (arg);
- return 1;
case GRUB_INSTALL_OPTIONS_DISABLE_CLI:
disable_cli = 1;
return 1;
+ case 'x':
+ x509keys = xrealloc (x509keys, sizeof (x509keys[0]) * (nx509keys + 1));
+ x509keys[nx509keys++] = xstrdup (arg);
+ return 1;
case GRUB_INSTALL_OPTIONS_VERBOSITY:
verbosity++;
@@ -649,7 +647,7 @@ grub_install_make_image_wrap_file (const char *dir, const char *prefix,
slen += sizeof (" --pubkey ''") + grub_strlen (*pk);
for (pk = x509keys; pk < x509keys + nx509keys; pk++)
- slen += 10 + grub_strlen (*pk);
+ slen += sizeof (" --x509key ''") + grub_strlen (*pk);
for (md = modules.entries; *md; md++)
slen += sizeof (" ''") + grub_strlen (*md);
@@ -693,7 +691,7 @@ grub_install_make_image_wrap_file (const char *dir, const char *prefix,
for (pk = x509keys; pk < x509keys + nx509keys; pk++)
{
- p = grub_stpcpy (p, "--x509 '");
+ p = grub_stpcpy (p, "--x509key '");
p = grub_stpcpy (p, *pk);
*p++ = '\'';
*p++ = ' ';
diff --git a/util/grub-mkimage.c b/util/grub-mkimage.c
index 13bdc6cf0397..89ca81ce6b10 100644
--- a/util/grub-mkimage.c
+++ b/util/grub-mkimage.c
@@ -76,7 +76,7 @@ static struct argp_option options[] = {
{"config", 'c', N_("FILE"), 0, N_("embed FILE as an early config"), 0},
/* TRANSLATORS: "embed" is a verb (command description). "*/
{"pubkey", 'k', N_("FILE"), 0, N_("embed FILE as public key for PGP signature checking"), 0},
- {"x509", 'x', N_("FILE"), 0, N_("embed FILE as an x509 certificate for appended signature checking"), 0},
+ {"x509key", 'x', N_("FILE"), 0, N_("embed FILE as an x509 certificate for appended signature checking"), 0},
/* TRANSLATORS: NOTE is a name of segment. */
{"note", 'n', 0, 0, N_("add NOTE segment for CHRP IEEE1275"), 0},
{"output", 'o', N_("FILE"), 0, N_("output a generated image to FILE [default=stdout]"), 0},
@@ -213,11 +213,11 @@ argp_parser (int key, char *arg, struct argp_state *state)
case 'x':
arguments->x509keys = xrealloc (arguments->x509keys,
- sizeof (arguments->x509keys[0])
- * (arguments->nx509keys + 1));
+ sizeof (arguments->x509keys[0]) * (arguments->nx509keys + 1));
arguments->x509keys[arguments->nx509keys++] = xstrdup (arg);
break;
+
case 'c':
if (arguments->config)
free (arguments->config);
diff --git a/util/mkimage.c b/util/mkimage.c
index f92949d1df25..8ae58ccef868 100644
--- a/util/mkimage.c
+++ b/util/mkimage.c
@@ -930,16 +930,21 @@ grub_install_generate_image (const char *dir, const char *prefix,
}
}
+ if (nx509keys != 0 && image_target->id != IMAGE_PPC)
+ grub_util_error (_("x509 public key can be support only to appended signature"
+ " with powerpc-ieee1275 images"));
+
{
size_t i;
+
for (i = 0; i < nx509keys; i++)
{
- size_t curs;
- curs = ALIGN_ADDR (grub_util_get_image_size (x509key_paths[i]));
- grub_util_info ("the size of x509 public key %u is 0x%"
- GRUB_HOST_PRIxLONG_LONG,
- (unsigned) i, (unsigned long long) curs);
- total_module_size += curs + sizeof (struct grub_module_header);
+ size_t curs;
+
+ curs = ALIGN_ADDR (grub_util_get_image_size (x509key_paths[i]));
+ grub_util_info ("the size of x509 public key %u is 0x%" GRUB_HOST_PRIxLONG_LONG,
+ (unsigned) i, (unsigned long long) curs);
+ total_module_size += curs + sizeof (struct grub_module_header);
}
}
@@ -1078,24 +1083,23 @@ grub_install_generate_image (const char *dir, const char *prefix,
{
size_t i;
+
for (i = 0; i < nx509keys; i++)
{
- size_t curs;
- struct grub_module_header *header;
+ size_t curs;
+ struct grub_module_header *header;
- curs = grub_util_get_image_size (x509key_paths[i]);
+ curs = grub_util_get_image_size (x509key_paths[i]);
+ header = (struct grub_module_header *) (kernel_img + offset);
+ header->type = grub_host_to_target32 (OBJ_TYPE_X509_PUBKEY);
+ header->size = grub_host_to_target32 (curs + sizeof (*header));
- header = (struct grub_module_header *) (kernel_img + offset);
- header->type = grub_host_to_target32 (OBJ_TYPE_X509_PUBKEY);
- header->size = grub_host_to_target32 (curs + sizeof (*header));
- offset += sizeof (*header);
-
- grub_util_load_image (x509key_paths[i], kernel_img + offset);
- offset += ALIGN_ADDR (curs);
+ offset += sizeof (*header);
+ grub_util_load_image (x509key_paths[i], kernel_img + offset);
+ offset += ALIGN_ADDR (curs);
}
}
-
if (memdisk_path)
{
struct grub_module_header *header;

View File

@ -0,0 +1,162 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Sudhakar Kuppusamy <sudhakar@linux.ibm.com>
Date: Tue, 18 Nov 2025 16:14:23 +0100
Subject: [PATCH] appended signatures: Import GNUTLS's ASN.1 description files
In order to parse PKCS#7 messages and X.509 certificates with libtasn1, we need
some information about how they are encoded. We get these from GNUTLS, which has
the benefit that they support the features we need and are well tested.
The GNUTLS files are from:
- https://github.com/gnutls/gnutls/blob/master/lib/gnutls.asn
- https://github.com/gnutls/gnutls/blob/master/lib/pkix.asn
The GNUTLS license is LGPLv2.1+, which is GPLv3 compatible, allowing us to import
it without issue.
Signed-off-by: Daniel Axtens <dja@axtens.net>
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>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
---
grub-core/commands/appendedsig/gnutls_asn1_tab.c | 33 +++++++++++++++++++++---
grub-core/commands/appendedsig/pkix_asn1_tab.c | 27 +++++++++----------
2 files changed, 44 insertions(+), 16 deletions(-)
diff --git a/grub-core/commands/appendedsig/gnutls_asn1_tab.c b/grub-core/commands/appendedsig/gnutls_asn1_tab.c
index ddd1314..efc0c14 100644
--- a/grub-core/commands/appendedsig/gnutls_asn1_tab.c
+++ b/grub-core/commands/appendedsig/gnutls_asn1_tab.c
@@ -1,7 +1,11 @@
#include <grub/mm.h>
-#include <grub/libtasn1.h>
+#include <libtasn1.h>
-const asn1_static_node gnutls_asn1_tab[] = {
+/*
+ * Imported from gnutls.asn.
+ * https://github.com/gnutls/gnutls/blob/master/lib/gnutls.asn
+ */
+const asn1_static_node grub_gnutls_asn1_tab[] = {
{ "GNUTLS", 536872976, NULL },
{ NULL, 1073741836, NULL },
{ "RSAPublicKey", 1610612741, NULL },
@@ -55,6 +59,9 @@ const asn1_static_node gnutls_asn1_tab[] = {
{ "prime", 1073741827, NULL },
{ "base", 1073741827, NULL },
{ "privateValueLength", 16387, NULL },
+ { "pkcs-11-ec-Parameters", 1610612754, NULL },
+ { "oId", 1073741836, NULL },
+ { "curveName", 31, NULL },
{ "ECParameters", 1610612754, NULL },
{ "namedCurve", 12, NULL },
{ "ECPrivateKey", 1610612741, NULL },
@@ -86,6 +93,13 @@ const asn1_static_node gnutls_asn1_tab[] = {
{ "trailerField", 536911875, NULL },
{ NULL, 1073741833, "1"},
{ NULL, 2056, "3"},
+ { "RSAOAEPParameters", 1610612741, NULL },
+ { "hashAlgorithm", 1610637314, "AlgorithmIdentifier"},
+ { NULL, 2056, "0"},
+ { "maskGenAlgorithm", 1610637314, "AlgorithmIdentifier"},
+ { NULL, 2056, "1"},
+ { "pSourceFunc", 536895490, "AlgorithmIdentifier"},
+ { NULL, 2056, "2"},
{ "GOSTParameters", 1610612741, NULL },
{ "publicKeyParamSet", 1073741836, NULL },
{ "digestParamSet", 16396, NULL },
@@ -113,9 +127,22 @@ const asn1_static_node gnutls_asn1_tab[] = {
{ "ephemeralPublicKey", 1610637314, "SubjectPublicKeyInfo"},
{ NULL, 4104, "0"},
{ "ukm", 7, NULL },
- { "GostR3410-KeyTransport", 536870917, NULL },
+ { "GostR3410-KeyTransport", 1610612741, NULL },
{ "sessionEncryptedKey", 1073741826, "Gost28147-89-EncryptedKey"},
{ "transportParameters", 536895490, "GostR3410-TransportParameters"},
{ NULL, 4104, "0"},
+ { "TPMKey", 1610612741, NULL },
+ { "type", 1073741836, NULL },
+ { "emptyAuth", 1610637316, NULL },
+ { NULL, 2056, "0"},
+ { "parent", 1073741827, NULL },
+ { "pubkey", 1073741831, NULL },
+ { "privkey", 7, NULL },
+ { "MLDSAPrivateKey", 536870917, NULL },
+ { "version", 1073741827, NULL },
+ { "privateKeyAlgorithm", 1073741826, "AlgorithmIdentifier"},
+ { "privateKey", 1073741831, NULL },
+ { "publicKey", 536895495, NULL },
+ { NULL, 2056, "1"},
{ NULL, 0, NULL }
};
diff --git a/grub-core/commands/appendedsig/pkix_asn1_tab.c b/grub-core/commands/appendedsig/pkix_asn1_tab.c
index adef69d..ec5f87b 100644
--- a/grub-core/commands/appendedsig/pkix_asn1_tab.c
+++ b/grub-core/commands/appendedsig/pkix_asn1_tab.c
@@ -1,7 +1,11 @@
#include <grub/mm.h>
-#include <grub/libtasn1.h>
+#include <libtasn1.h>
-const asn1_static_node pkix_asn1_tab[] = {
+/*
+ * Imported from pkix.asn.
+ * https://github.com/gnutls/gnutls/blob/master/lib/pkix.asn
+ */
+const asn1_static_node grub_pkix_asn1_tab[] = {
{ "PKIX1", 536875024, NULL },
{ NULL, 1073741836, NULL },
{ "PrivateKeyUsagePeriod", 1610612741, NULL },
@@ -27,9 +31,7 @@ const asn1_static_node pkix_asn1_tab[] = {
{ "MAX", 524298, "1"},
{ "utf8String", 1612709922, NULL },
{ "MAX", 524298, "1"},
- { "bmpString", 1612709921, NULL },
- { "MAX", 524298, "1"},
- { "ia5String", 538968093, NULL },
+ { "bmpString", 538968097, NULL },
{ "MAX", 524298, "1"},
{ "SubjectAltName", 1073741826, "GeneralNames"},
{ "GeneralNames", 1612709899, NULL },
@@ -64,8 +66,7 @@ const asn1_static_node pkix_asn1_tab[] = {
{ "BasicConstraints", 1610612741, NULL },
{ "cA", 1610645508, NULL },
{ NULL, 131081, NULL },
- { "pathLenConstraint", 537411587, NULL },
- { "0", 10, "MAX"},
+ { "pathLenConstraint", 16387, NULL },
{ "CRLDistributionPoints", 1612709899, NULL },
{ "MAX", 1074266122, "1"},
{ NULL, 2, "DistributionPoint"},
@@ -277,14 +278,15 @@ const asn1_static_node pkix_asn1_tab[] = {
{ "pkcs-5-PBES2-params", 1610612741, NULL },
{ "keyDerivationFunc", 1073741826, "AlgorithmIdentifier"},
{ "encryptionScheme", 2, "AlgorithmIdentifier"},
+ { "pkcs-5-PBMAC1-params", 1610612741, NULL },
+ { "keyDerivationFunc", 1073741826, "AlgorithmIdentifier"},
+ { "messageAuthScheme", 2, "AlgorithmIdentifier"},
{ "pkcs-5-PBKDF2-params", 1610612741, NULL },
{ "salt", 1610612754, NULL },
{ "specified", 1073741831, NULL },
{ "otherSource", 2, "AlgorithmIdentifier"},
- { "iterationCount", 1611137027, NULL },
- { "1", 10, "MAX"},
- { "keyLength", 1611153411, NULL },
- { "1", 10, "MAX"},
+ { "iterationCount", 1073741827, NULL },
+ { "keyLength", 1073758211, NULL },
{ "prf", 16386, "AlgorithmIdentifier"},
{ "pkcs-12-PFX", 1610612741, NULL },
{ "version", 1610874883, NULL },
@@ -341,8 +343,7 @@ const asn1_static_node pkix_asn1_tab[] = {
{ "MAX", 1074266122, "1"},
{ NULL, 2, "Attribute"},
{ "ProxyCertInfo", 1610612741, NULL },
- { "pCPathLenConstraint", 1611153411, NULL },
- { "0", 10, "MAX"},
+ { "pCPathLenConstraint", 1073758211, NULL },
{ "proxyPolicy", 2, "ProxyPolicy"},
{ "ProxyPolicy", 1610612741, NULL },
{ "policyLanguage", 1073741836, NULL },

View File

@ -0,0 +1,274 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Sudhakar Kuppusamy <sudhakar@linux.ibm.com>
Date: Tue, 18 Nov 2025 16:18:32 +0100
Subject: [PATCH] appended signatures: Parse ASN1 node
This code allows us to parse ASN1 node and allocating memory to store it.
It will work for anything where the size libtasn1 returns is right:
- Integers
- Octet strings
- DER encoding of other structures
It will _not_ work for things where libtasn1 size requires adjustment:
- Strings that require an extra NULL byte at the end
- Bit strings because libtasn1 returns the length in bits, not bytes.
If the function returns a non-NULL value, the caller must free it.
Signed-off-by: Daniel Axtens <dja@axtens.net>
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>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
---
grub-core/commands/appendedsig/appendedsig.h | 96 +++++-----------------------
grub-core/commands/appendedsig/asn1util.c | 59 ++++++++---------
2 files changed, 43 insertions(+), 112 deletions(-)
diff --git a/grub-core/commands/appendedsig/appendedsig.h b/grub-core/commands/appendedsig/appendedsig.h
index 9792ef3..601d616 100644
--- a/grub-core/commands/appendedsig/appendedsig.h
+++ b/grub-core/commands/appendedsig/appendedsig.h
@@ -1,6 +1,7 @@
/*
* GRUB -- GRand Unified Bootloader
- * Copyright (C) 2020 IBM Corporation.
+ * Copyright (C) 2020, 2022 Free Software Foundation, Inc.
+ * Copyright (C) 2020, 2022, 2025 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
@@ -16,95 +17,28 @@
* along with GRUB. If not, see <http://www.gnu.org/licenses/>.
*/
-#include <grub/crypto.h>
-#include <grub/libtasn1.h>
+#include <libtasn1.h>
-extern asn1_node _gnutls_gnutls_asn;
-extern asn1_node _gnutls_pkix_asn;
+extern asn1_node grub_gnutls_gnutls_asn;
+extern asn1_node grub_gnutls_pkix_asn;
-#define MAX_OID_LEN 32
+/* Do libtasn1 init. */
+extern int
+grub_asn1_init (void);
/*
- * One or more x509 certificates.
- *
- * We do limited parsing: extracting only the serial, CN and RSA public key.
- */
-struct x509_certificate
-{
- struct x509_certificate *next;
-
- grub_uint8_t *serial;
- grub_size_t serial_len;
-
- char *subject;
- grub_size_t subject_len;
-
- /* We only support RSA public keys. This encodes [modulus, publicExponent] */
- gcry_mpi_t mpis[2];
-};
-
-/*
- * A PKCS#7 signedData message.
- *
- * We make no attempt to match intelligently, so we don't save any info about
- * the signer. We also support only 1 signerInfo, so we only store a single
- * MPI for the signature.
- */
-struct pkcs7_signedData
-{
- const gcry_md_spec_t *hash;
- gcry_mpi_t sig_mpi;
-};
-
-
-/* Do libtasn1 init */
-int asn1_init (void);
-
-/*
- * Import a DER-encoded certificate at 'data', of size 'size'.
- *
- * Place the results into 'results', which must be already allocated.
- */
-grub_err_t
-certificate_import (void *data, grub_size_t size,
- struct x509_certificate *results);
-
-/*
- * Release all the storage associated with the x509 certificate.
- * If the caller dynamically allocated the certificate, it must free it.
- * The caller is also responsible for maintenance of the linked list.
- */
-void certificate_release (struct x509_certificate *cert);
-
-/*
- * Parse a PKCS#7 message, which must be a signedData message.
- *
- * The message must be in 'sigbuf' and of size 'data_size'. The result is
- * placed in 'msg', which must already be allocated.
- */
-grub_err_t
-parse_pkcs7_signedData (void *sigbuf, grub_size_t data_size,
- struct pkcs7_signedData *msg);
-
-/*
- * Release all the storage associated with the PKCS#7 message.
- * If the caller dynamically allocated the message, it must free it.
- */
-void pkcs7_signedData_release (struct pkcs7_signedData *msg);
-
-/*
- * Read a value from an ASN1 node, allocating memory to store it.
- *
- * It will work for anything where the size libtasn1 returns is right:
+ * Read a value from an ASN1 node, allocating memory to store it. It will work
+ * for anything where the size libtasn1 returns is right:
* - Integers
* - Octet strings
* - DER encoding of other structures
+ *
* It will _not_ work for things where libtasn1 size requires adjustment:
- * - Strings that require an extra NULL byte at the end
+ * - Strings that require an extra null byte at the end
* - Bit strings because libtasn1 returns the length in bits, not bytes.
*
* If the function returns a non-NULL value, the caller must free it.
*/
-void *grub_asn1_allocate_and_read (asn1_node node, const char *name,
- const char *friendly_name,
- int *content_size);
+extern void *
+grub_asn1_allocate_and_read (asn1_node node, const char *name, const char *friendly_name,
+ grub_int32_t *content_size);
diff --git a/grub-core/commands/appendedsig/asn1util.c b/grub-core/commands/appendedsig/asn1util.c
index eff095a..9dd7898 100644
--- a/grub-core/commands/appendedsig/asn1util.c
+++ b/grub-core/commands/appendedsig/asn1util.c
@@ -1,6 +1,7 @@
/*
* GRUB -- GRand Unified Bootloader
- * Copyright (C) 2020 IBM Corporation.
+ * Copyright (C) 2020, 2022 Free Software Foundation, Inc.
+ * Copyright (C) 2020, 2022, 2025 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
@@ -16,28 +17,29 @@
* along with GRUB. If not, see <http://www.gnu.org/licenses/>.
*/
-#include <grub/libtasn1.h>
+#include <libtasn1.h>
#include <grub/types.h>
#include <grub/err.h>
#include <grub/mm.h>
#include <grub/crypto.h>
+#include <grub/misc.h>
#include <grub/gcrypt/gcrypt.h>
#include "appendedsig.h"
-asn1_node _gnutls_gnutls_asn = ASN1_TYPE_EMPTY;
-asn1_node _gnutls_pkix_asn = ASN1_TYPE_EMPTY;
+asn1_node grub_gnutls_gnutls_asn = NULL;
+asn1_node grub_gnutls_pkix_asn = NULL;
-extern const ASN1_ARRAY_TYPE gnutls_asn1_tab[];
-extern const ASN1_ARRAY_TYPE pkix_asn1_tab[];
+extern const asn1_static_node grub_gnutls_asn1_tab[];
+extern const asn1_static_node grub_pkix_asn1_tab[];
/*
- * Read a value from an ASN1 node, allocating memory to store it.
- *
- * It will work for anything where the size libtasn1 returns is right:
+ * Read a value from an ASN1 node, allocating memory to store it. It will work
+ * for anything where the size libtasn1 returns is right:
* - Integers
* - Octet strings
* - DER encoding of other structures
+ *
* It will _not_ work for things where libtasn1 size requires adjustment:
* - Strings that require an extra NULL byte at the end
* - Bit strings because libtasn1 returns the length in bits, not bytes.
@@ -45,30 +47,26 @@ extern const ASN1_ARRAY_TYPE pkix_asn1_tab[];
* If the function returns a non-NULL value, the caller must free it.
*/
void *
-grub_asn1_allocate_and_read (asn1_node node, const char *name,
- const char *friendly_name, int *content_size)
+grub_asn1_allocate_and_read (asn1_node node, const char *name, const char *friendly_name,
+ grub_int32_t *content_size)
{
- int result;
+ grub_int32_t result;
grub_uint8_t *tmpstr = NULL;
- int tmpstr_size = 0;
+ grub_int32_t tmpstr_size = 0;
result = asn1_read_value (node, name, NULL, &tmpstr_size);
if (result != ASN1_MEM_ERROR)
{
- grub_snprintf (grub_errmsg, sizeof (grub_errmsg),
- _
- ("Reading size of %s did not return expected status: %s"),
- friendly_name, asn1_strerror (result));
- grub_errno = GRUB_ERR_BAD_FILE_TYPE;
+ grub_error (GRUB_ERR_BAD_FILE_TYPE, "reading size of %s did not return expected status: %s",
+ friendly_name, asn1_strerror (result)) ;
return NULL;
}
tmpstr = grub_malloc (tmpstr_size);
if (tmpstr == NULL)
{
- grub_snprintf (grub_errmsg, sizeof (grub_errmsg),
- "Could not allocate memory to store %s", friendly_name);
- grub_errno = GRUB_ERR_OUT_OF_MEMORY;
+ grub_error (GRUB_ERR_OUT_OF_MEMORY, "could not allocate memory to store %s",
+ friendly_name) ;
return NULL;
}
@@ -76,10 +74,8 @@ grub_asn1_allocate_and_read (asn1_node node, const char *name,
if (result != ASN1_SUCCESS)
{
grub_free (tmpstr);
- grub_snprintf (grub_errmsg, sizeof (grub_errmsg),
- "Error reading %s: %s",
- friendly_name, asn1_strerror (result));
- grub_errno = GRUB_ERR_BAD_FILE_TYPE;
+ grub_error (GRUB_ERR_BAD_FILE_TYPE, "error reading %s: %s", friendly_name,
+ asn1_strerror (result)) ;
return NULL;
}
@@ -89,14 +85,15 @@ grub_asn1_allocate_and_read (asn1_node node, const char *name,
}
int
-asn1_init (void)
+grub_asn1_init (void)
{
int res;
- res = asn1_array2tree (gnutls_asn1_tab, &_gnutls_gnutls_asn, NULL);
+
+ res = asn1_array2tree (grub_gnutls_asn1_tab, &grub_gnutls_gnutls_asn, NULL);
if (res != ASN1_SUCCESS)
- {
- return res;
- }
- res = asn1_array2tree (pkix_asn1_tab, &_gnutls_pkix_asn, NULL);
+ return res;
+
+ res = asn1_array2tree (grub_pkix_asn1_tab, &grub_gnutls_pkix_asn, NULL);
+
return res;
}

View File

@ -0,0 +1,659 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Sudhakar Kuppusamy <sudhakar@linux.ibm.com>
Date: Tue, 18 Nov 2025 16:20:56 +0100
Subject: [PATCH] appended signatures: Parse PKCS#7 signed data
This code allows us to parse:
- PKCS#7 signed data messages. Only a single signer info is supported, which
is all that the Linux sign-file utility supports creating out-of-the-box.
Only RSA, SHA-256 and SHA-512 are supported. Any certificate embedded in
the PKCS#7 message will be ignored.
Signed-off-by: Daniel Axtens <dja@axtens.net>
Signed-off-by: Sudhakar Kuppusamy <sudhakar@linux.ibm.com>
Reviewed-by: Avnish Chouhan <avnish@linux.ibm.com>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
---
grub-core/commands/appendedsig/appendedsig.h | 37 +++
grub-core/commands/appendedsig/pkcs7.c | 439 ++++++++++++++++++---------
2 files changed, 330 insertions(+), 146 deletions(-)
diff --git a/grub-core/commands/appendedsig/appendedsig.h b/grub-core/commands/appendedsig/appendedsig.h
index 601d616..b0beb89 100644
--- a/grub-core/commands/appendedsig/appendedsig.h
+++ b/grub-core/commands/appendedsig/appendedsig.h
@@ -17,11 +17,48 @@
* along with GRUB. If not, see <http://www.gnu.org/licenses/>.
*/
+#include <grub/crypto.h>
#include <libtasn1.h>
extern asn1_node grub_gnutls_gnutls_asn;
extern asn1_node grub_gnutls_pkix_asn;
+#define GRUB_MAX_OID_LEN 32
+
+/* A PKCS#7 signed data signer info. */
+struct pkcs7_signer
+{
+ const gcry_md_spec_t *hash;
+ gcry_mpi_t sig_mpi;
+};
+typedef struct pkcs7_signer grub_pkcs7_signer_t;
+
+/*
+ * A PKCS#7 signed data message. We make no attempt to match intelligently, so
+ * we don't save any info about the signer.
+ */
+struct pkcs7_data
+{
+ grub_int32_t signer_count;
+ grub_pkcs7_signer_t *signers;
+};
+typedef struct pkcs7_data grub_pkcs7_data_t;
+
+/*
+ * Parse a PKCS#7 message, which must be a signed data message. The message must
+ * be in 'sigbuf' and of size 'data_size'. The result is placed in 'msg', which
+ * must already be allocated.
+ */
+extern grub_err_t
+grub_pkcs7_data_parse (const void *sigbuf, grub_size_t data_size, grub_pkcs7_data_t *msg);
+
+/*
+ * Release all the storage associated with the PKCS#7 message. If the caller
+ * dynamically allocated the message, it must free it.
+ */
+extern void
+grub_pkcs7_data_release (grub_pkcs7_data_t *msg);
+
/* Do libtasn1 init. */
extern int
grub_asn1_init (void);
diff --git a/grub-core/commands/appendedsig/pkcs7.c b/grub-core/commands/appendedsig/pkcs7.c
index dc6afe2..b8e2720 100644
--- a/grub-core/commands/appendedsig/pkcs7.c
+++ b/grub-core/commands/appendedsig/pkcs7.c
@@ -1,6 +1,7 @@
/*
* GRUB -- GRand Unified Bootloader
- * Copyright (C) 2020 IBM Corporation.
+ * Copyright (C) 2020, 2022 Free Software Foundation, Inc.
+ * Copyright (C) 2020, 2022, 2025 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
@@ -20,57 +21,55 @@
#include <grub/misc.h>
#include <grub/crypto.h>
#include <grub/gcrypt/gcrypt.h>
-
+#include <sys/types.h>
static char asn1_error[ASN1_MAX_ERROR_DESCRIPTION_SIZE];
-/*
- * RFC 5652 s 5.1
- */
-const char *signedData_oid = "1.2.840.113549.1.7.2";
+/* RFC 5652 s 5.1. */
+static const char *signedData_oid = "1.2.840.113549.1.7.2";
-/*
- * RFC 4055 s 2.1
- */
-const char *sha256_oid = "2.16.840.1.101.3.4.2.1";
-const char *sha512_oid = "2.16.840.1.101.3.4.2.3";
+/* RFC 4055 s 2.1. */
+static const char *sha256_oid = "2.16.840.1.101.3.4.2.1";
+static const char *sha512_oid = "2.16.840.1.101.3.4.2.3";
static grub_err_t
-process_content (grub_uint8_t * content, int size,
- struct pkcs7_signedData *msg)
+process_content (grub_uint8_t *content, grub_int32_t size, grub_pkcs7_data_t *msg)
{
- int res;
+ grub_int32_t res;
asn1_node signed_part;
grub_err_t err = GRUB_ERR_NONE;
- char algo_oid[MAX_OID_LEN];
- int algo_oid_size = sizeof (algo_oid);
- int algo_count;
+ char algo_oid[GRUB_MAX_OID_LEN];
+ grub_int32_t algo_oid_size;
+ grub_int32_t algo_count;
+ grub_int32_t signer_count;
+ grub_int32_t i;
char version;
- int version_size = sizeof (version);
+ grub_int32_t version_size = sizeof (version);
grub_uint8_t *result_buf;
- int result_size = 0;
- int crls_size = 0;
+ grub_int32_t result_size = 0;
+ grub_int32_t crls_size = 0;
gcry_error_t gcry_err;
+ bool sha256_in_da, sha256_in_si, sha512_in_da, sha512_in_si;
+ char *da_path;
+ char *si_sig_path;
+ char *si_da_path;
- res = asn1_create_element (_gnutls_pkix_asn, "PKIX1.pkcs-7-SignedData",
- &signed_part);
+ res = asn1_create_element (grub_gnutls_pkix_asn, "PKIX1.pkcs-7-SignedData", &signed_part);
if (res != ASN1_SUCCESS)
- {
- return grub_error (GRUB_ERR_OUT_OF_MEMORY,
- "Could not create ASN.1 structure for PKCS#7 signed part.");
- }
+ return grub_error (GRUB_ERR_OUT_OF_MEMORY,
+ "could not create ASN.1 structure for PKCS#7 signed part");
res = asn1_der_decoding2 (&signed_part, content, &size,
- ASN1_DECODE_FLAG_STRICT_DER, asn1_error);
+ ASN1_DECODE_FLAG_STRICT_DER, asn1_error);
if (res != ASN1_SUCCESS)
{
- err =
- grub_error (GRUB_ERR_BAD_SIGNATURE,
- "Error reading PKCS#7 signed data: %s", asn1_error);
+ err = grub_error (GRUB_ERR_BAD_SIGNATURE,
+ "error reading PKCS#7 signed data: %s", asn1_error);
goto cleanup_signed_part;
}
- /* SignedData ::= SEQUENCE {
+ /*
+ * SignedData ::= SEQUENCE {
* version CMSVersion,
* digestAlgorithms DigestAlgorithmIdentifiers,
* encapContentInfo EncapsulatedContentInfo,
@@ -79,23 +78,19 @@ process_content (grub_uint8_t * content, int size,
* signerInfos SignerInfos }
*/
- /* version per the algo in 5.1, must be 1 */
res = asn1_read_value (signed_part, "version", &version, &version_size);
if (res != ASN1_SUCCESS)
{
- err =
- grub_error (GRUB_ERR_BAD_SIGNATURE,
- "Error reading signedData version: %s",
- asn1_strerror (res));
+ err = grub_error (GRUB_ERR_BAD_SIGNATURE, "error reading signedData version: %s",
+ asn1_strerror (res));
goto cleanup_signed_part;
}
+ /* Signature version must be 1 because appended signature only support v1. */
if (version != 1)
{
- err =
- grub_error (GRUB_ERR_BAD_SIGNATURE,
- "Unexpected signature version v%d, only v1 supported",
- version);
+ err = grub_error (GRUB_ERR_BAD_SIGNATURE,
+ "unexpected signature version v%d, only v1 supported", version);
goto cleanup_signed_part;
}
@@ -104,147 +99,301 @@ process_content (grub_uint8_t * content, int size,
*
* DigestAlgorithmIdentifiers ::= SET OF DigestAlgorithmIdentifier
* DigestAlgorithmIdentifer is an X.509 AlgorithmIdentifier (10.1.1)
- *
+ *
* RFC 4055 s 2.1:
* sha256Identifier AlgorithmIdentifier ::= { id-sha256, NULL }
* sha512Identifier AlgorithmIdentifier ::= { id-sha512, NULL }
*
* We only support 1 element in the set, and we do not check parameters atm.
*/
- res =
- asn1_number_of_elements (signed_part, "digestAlgorithms", &algo_count);
+ res = asn1_number_of_elements (signed_part, "digestAlgorithms", &algo_count);
if (res != ASN1_SUCCESS)
{
- err =
- grub_error (GRUB_ERR_BAD_SIGNATURE,
- "Error counting number of digest algorithms: %s",
- asn1_strerror (res));
+ err = grub_error (GRUB_ERR_BAD_SIGNATURE, "error counting number of digest algorithms: %s",
+ asn1_strerror (res));
goto cleanup_signed_part;
}
- if (algo_count != 1)
+ if (algo_count <= 0)
{
- err =
- grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET,
- "Only 1 digest algorithm is supported");
+ err = grub_error (GRUB_ERR_BAD_SIGNATURE, "a minimum of 1 digest algorithm is required");
goto cleanup_signed_part;
}
- res =
- asn1_read_value (signed_part, "digestAlgorithms.?1.algorithm", algo_oid,
- &algo_oid_size);
- if (res != ASN1_SUCCESS)
+ if (algo_count > 2)
{
- err =
- grub_error (GRUB_ERR_BAD_SIGNATURE,
- "Error reading digest algorithm: %s",
- asn1_strerror (res));
+ err = grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, "a maximum of 2 digest algorithms is supported");
goto cleanup_signed_part;
}
- if (grub_strncmp (sha512_oid, algo_oid, algo_oid_size) == 0)
- {
- msg->hash = grub_crypto_lookup_md_by_name ("sha512");
- }
- else if (grub_strncmp (sha256_oid, algo_oid, algo_oid_size) == 0)
- {
- msg->hash = grub_crypto_lookup_md_by_name ("sha256");
- }
- else
- {
- err =
- grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET,
- "Only SHA-256 and SHA-512 hashes are supported, found OID %s",
- algo_oid);
- goto cleanup_signed_part;
- }
+ sha256_in_da = false;
+ sha512_in_da = false;
- if (!msg->hash)
+ for (i = 0; i < algo_count; i++)
{
- err =
- grub_error (GRUB_ERR_BAD_SIGNATURE,
- "Hash algorithm for OID %s not loaded", algo_oid);
- goto cleanup_signed_part;
+ da_path = grub_xasprintf ("digestAlgorithms.?%d.algorithm", i + 1);
+ if (da_path == NULL)
+ {
+ err = grub_error (GRUB_ERR_OUT_OF_MEMORY,
+ "could not allocate path for digest algorithm parsing path");
+ goto cleanup_signed_part;
+ }
+
+ algo_oid_size = sizeof (algo_oid);
+ res = asn1_read_value (signed_part, da_path, algo_oid, &algo_oid_size);
+ if (res != ASN1_SUCCESS)
+ {
+ err = grub_error (GRUB_ERR_BAD_SIGNATURE, "error reading digest algorithm: %s",
+ asn1_strerror (res));
+ grub_free (da_path);
+ goto cleanup_signed_part;
+ }
+
+ if (grub_strncmp (sha512_oid, algo_oid, algo_oid_size) == 0)
+ {
+ if (sha512_in_da == false)
+ sha512_in_da = true;
+ else
+ {
+ err = grub_error (GRUB_ERR_BAD_SIGNATURE,
+ "SHA-512 specified twice in digest algorithm list");
+ grub_free (da_path);
+ goto cleanup_signed_part;
+ }
+ }
+ else if (grub_strncmp (sha256_oid, algo_oid, algo_oid_size) == 0)
+ {
+ if (sha256_in_da == false)
+ sha256_in_da = true;
+ else
+ {
+ err = grub_error (GRUB_ERR_BAD_SIGNATURE,
+ "SHA-256 specified twice in digest algorithm list");
+ grub_free (da_path);
+ goto cleanup_signed_part;
+ }
+ }
+ else
+ {
+ err = grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET,
+ "only SHA-256 and SHA-512 hashes are supported, found OID %s",
+ algo_oid);
+ grub_free (da_path);
+ goto cleanup_signed_part;
+ }
+
+ grub_free (da_path);
}
+ /* At this point, at least one of sha{256,512}_in_da must be true. */
+
/*
- * We ignore the certificates, but we don't permit CRLs.
- * A CRL entry might be revoking the certificate we're using, and we have
- * no way of dealing with that at the moment.
+ * We ignore the certificates, but we don't permit CRLs. A CRL entry might be
+ * revoking the certificate we're using, and we have no way of dealing with
+ * that at the moment.
*/
res = asn1_read_value (signed_part, "crls", NULL, &crls_size);
if (res != ASN1_ELEMENT_NOT_FOUND)
{
- err =
- grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET,
- "PKCS#7 messages with embedded CRLs are not supported");
+ err = grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET,
+ "PKCS#7 messages with embedded CRLs are not supported");
goto cleanup_signed_part;
}
- /* read the signature */
- result_buf =
- grub_asn1_allocate_and_read (signed_part, "signerInfos.?1.signature",
- "signature data", &result_size);
- if (!result_buf)
+ /* Read the signatures */
+ res = asn1_number_of_elements (signed_part, "signerInfos", &signer_count);
+ if (res != ASN1_SUCCESS)
{
- err = grub_errno;
+ err = grub_error (GRUB_ERR_BAD_SIGNATURE, "error counting number of signers: %s",
+ asn1_strerror (res));
goto cleanup_signed_part;
}
- gcry_err =
- gcry_mpi_scan (&(msg->sig_mpi), GCRYMPI_FMT_USG, result_buf, result_size,
- NULL);
- if (gcry_err != GPG_ERR_NO_ERROR)
+ if (signer_count <= 0)
{
- err =
- grub_error (GRUB_ERR_BAD_SIGNATURE,
- "Error loading signature into MPI structure: %d",
- gcry_err);
- goto cleanup_result;
+ err = grub_error (GRUB_ERR_BAD_SIGNATURE, "a minimum of 1 signer is required");
+ goto cleanup_signed_part;
+ }
+
+ msg->signers = grub_calloc (signer_count, sizeof (grub_pkcs7_signer_t));
+ if (msg->signers == NULL)
+ {
+ err = grub_error (GRUB_ERR_OUT_OF_MEMORY,
+ "could not allocate space for %d signers", signer_count);
+ goto cleanup_signed_part;
+ }
+
+ msg->signer_count = 0;
+ for (i = 0; i < signer_count; i++)
+ {
+ si_da_path = grub_xasprintf ("signerInfos.?%d.digestAlgorithm.algorithm", i + 1);
+ if (si_da_path == NULL)
+ {
+ err = grub_error (GRUB_ERR_OUT_OF_MEMORY,
+ "could not allocate path for signer %d's digest algorithm parsing path",
+ i);
+ goto cleanup_signerInfos;
+ }
+
+ algo_oid_size = sizeof (algo_oid);
+ res = asn1_read_value (signed_part, si_da_path, algo_oid, &algo_oid_size);
+ if (res != ASN1_SUCCESS)
+ {
+ err = grub_error (GRUB_ERR_BAD_SIGNATURE,
+ "error reading signer %d's digest algorithm: %s", i, asn1_strerror (res));
+ grub_free (si_da_path);
+ goto cleanup_signerInfos;
+ }
+
+ grub_free (si_da_path);
+
+ if (grub_strncmp (sha512_oid, algo_oid, algo_oid_size) == 0)
+ {
+ if (sha512_in_da == false)
+ {
+ err = grub_error (GRUB_ERR_BAD_SIGNATURE,
+ "signer %d claims a SHA-512 signature which was not "
+ "specified in the outer DigestAlgorithms", i);
+ goto cleanup_signerInfos;
+ }
+ else
+ {
+ sha512_in_si = true;
+ msg->signers[i].hash = grub_crypto_lookup_md_by_name ("sha512");
+ }
+ }
+ else if (grub_strncmp (sha256_oid, algo_oid, algo_oid_size) == 0)
+ {
+ if (sha256_in_da == false)
+ {
+ err = grub_error (GRUB_ERR_BAD_SIGNATURE,
+ "signer %d claims a SHA-256 signature which was not "
+ "specified in the outer DigestAlgorithms", i);
+ goto cleanup_signerInfos;
+ }
+ else
+ {
+ sha256_in_si = true;
+ msg->signers[i].hash = grub_crypto_lookup_md_by_name ("sha256");
+ }
+ }
+ else
+ {
+ err = grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET,
+ "only SHA-256 and SHA-512 hashes are supported, found OID %s",
+ algo_oid);
+ goto cleanup_signerInfos;
+ }
+
+ if (msg->signers[i].hash == NULL)
+ {
+ err = grub_error (GRUB_ERR_BAD_SIGNATURE,
+ "Hash algorithm for signer %d (OID %s) not loaded", i, algo_oid);
+ goto cleanup_signerInfos;
+ }
+
+ si_sig_path = grub_xasprintf ("signerInfos.?%d.signature", i + 1);
+ if (si_sig_path == NULL)
+ {
+ err = grub_error (GRUB_ERR_OUT_OF_MEMORY,
+ "could not allocate path for signer %d's signature parsing path", i);
+ goto cleanup_signerInfos;
+ }
+
+ result_buf = grub_asn1_allocate_and_read (signed_part, si_sig_path, "signature data", &result_size);
+ grub_free (si_sig_path);
+
+ if (result_buf == NULL)
+ {
+ err = grub_errno;
+ goto cleanup_signerInfos;
+ }
+
+ gcry_err = _gcry_mpi_scan (&(msg->signers[i].sig_mpi), GCRYMPI_FMT_USG,
+ result_buf, result_size, NULL);
+ grub_free (result_buf);
+
+ if (gcry_err != GPG_ERR_NO_ERROR)
+ {
+ err = grub_error (GRUB_ERR_BAD_SIGNATURE,
+ "error loading signature %d into MPI structure: %d",
+ i, gcry_err);
+ goto cleanup_signerInfos;
+ }
+
+ /*
+ * Use msg->signer_count to track fully populated signerInfos so we know
+ * how many we need to clean up.
+ */
+ msg->signer_count++;
+ }
+
+ /*
+ * Final consistency check of signerInfo.*.digestAlgorithm vs digestAlgorithms
+ * .*.algorithm. An algorithm must be present in both digestAlgorithms and
+ * signerInfo or in neither. We have already checked for an algorithm in
+ * signerInfo that is not in digestAlgorithms, here we check for algorithms in
+ * digestAlgorithms but not in signerInfos.
+ */
+ if (sha512_in_da == true && sha512_in_si == false)
+ {
+ err = grub_error (GRUB_ERR_BAD_SIGNATURE,
+ "SHA-512 specified in DigestAlgorithms but did not appear in SignerInfos");
+ goto cleanup_signerInfos;
}
-cleanup_result:
- grub_free (result_buf);
-cleanup_signed_part:
+ if (sha256_in_da == true && sha256_in_si == false)
+ {
+ err = grub_error (GRUB_ERR_BAD_SIGNATURE,
+ "SHA-256 specified in DigestAlgorithms but did not appear in SignerInfos");
+ goto cleanup_signerInfos;
+ }
+
+ asn1_delete_structure (&signed_part);
+
+ return GRUB_ERR_NONE;
+
+ cleanup_signerInfos:
+ for (i = 0; i < msg->signer_count; i++)
+ _gcry_mpi_release (msg->signers[i].sig_mpi);
+
+ grub_free (msg->signers);
+
+ cleanup_signed_part:
asn1_delete_structure (&signed_part);
return err;
}
grub_err_t
-parse_pkcs7_signedData (void *sigbuf, grub_size_t data_size,
- struct pkcs7_signedData *msg)
+grub_pkcs7_data_parse (const void *sigbuf, grub_size_t data_size, grub_pkcs7_data_t *msg)
{
- int res;
+ grub_int32_t res;
asn1_node content_info;
grub_err_t err = GRUB_ERR_NONE;
- char content_oid[MAX_OID_LEN];
+ char content_oid[GRUB_MAX_OID_LEN];
grub_uint8_t *content;
- int content_size;
- int content_oid_size = sizeof (content_oid);
- int size;
+ grub_int32_t content_size;
+ grub_int32_t content_oid_size = sizeof (content_oid);
+ grub_int32_t size = (grub_int32_t) data_size;
- if (data_size > GRUB_INT_MAX)
+ if (data_size > GRUB_UINT_MAX)
return grub_error (GRUB_ERR_OUT_OF_RANGE,
- "Cannot parse a PKCS#7 message where data size > INT_MAX");
- size = (int) data_size;
+ "cannot parse a PKCS#7 message where data size > GRUB_UINT_MAX");
- res = asn1_create_element (_gnutls_pkix_asn,
- "PKIX1.pkcs-7-ContentInfo", &content_info);
+ res = asn1_create_element (grub_gnutls_pkix_asn, "PKIX1.pkcs-7-ContentInfo", &content_info);
if (res != ASN1_SUCCESS)
- {
- return grub_error (GRUB_ERR_OUT_OF_MEMORY,
- "Could not create ASN.1 structure for PKCS#7 data: %s",
- asn1_strerror (res));
- }
+ return grub_error (GRUB_ERR_OUT_OF_MEMORY,
+ "could not create ASN.1 structure for PKCS#7 data: %s",
+ asn1_strerror (res));
res = asn1_der_decoding2 (&content_info, sigbuf, &size,
- ASN1_DECODE_FLAG_STRICT_DER, asn1_error);
+ ASN1_DECODE_FLAG_STRICT_DER | ASN1_DECODE_FLAG_ALLOW_PADDING,
+ asn1_error);
if (res != ASN1_SUCCESS)
{
- err =
- grub_error (GRUB_ERR_BAD_SIGNATURE,
- "Error decoding PKCS#7 message DER: %s", asn1_error);
+ err = grub_error (GRUB_ERR_BAD_SIGNATURE,
+ "error decoding PKCS#7 message DER: %s", asn1_error);
goto cleanup;
}
@@ -255,32 +404,24 @@ parse_pkcs7_signedData (void *sigbuf, grub_size_t data_size,
*
* ContentType ::= OBJECT IDENTIFIER
*/
- res =
- asn1_read_value (content_info, "contentType", content_oid,
- &content_oid_size);
+ res = asn1_read_value (content_info, "contentType", content_oid, &content_oid_size);
if (res != ASN1_SUCCESS)
{
- err =
- grub_error (GRUB_ERR_BAD_SIGNATURE,
- "Error reading PKCS#7 content type: %s",
- asn1_strerror (res));
+ err = grub_error (GRUB_ERR_BAD_SIGNATURE, "error reading PKCS#7 content type: %s",
+ asn1_strerror (res));
goto cleanup;
}
- /* OID for SignedData defined in 5.1 */
+ /* OID for SignedData defined in 5.1. */
if (grub_strncmp (signedData_oid, content_oid, content_oid_size) != 0)
{
- err =
- grub_error (GRUB_ERR_BAD_SIGNATURE,
- "Unexpected content type in PKCS#7 message: OID %s",
- content_oid);
+ err = grub_error (GRUB_ERR_BAD_SIGNATURE,
+ "unexpected content type in PKCS#7 message: OID %s", content_oid);
goto cleanup;
}
- content =
- grub_asn1_allocate_and_read (content_info, "content",
- "PKCS#7 message content", &content_size);
- if (!content)
+ content = grub_asn1_allocate_and_read (content_info, "content", "PKCS#7 message content", &content_size);
+ if (content == NULL)
{
err = grub_errno;
goto cleanup;
@@ -289,17 +430,23 @@ parse_pkcs7_signedData (void *sigbuf, grub_size_t data_size,
err = process_content (content, content_size, msg);
grub_free (content);
-cleanup:
+ cleanup:
asn1_delete_structure (&content_info);
+
return err;
}
/*
- * Release all the storage associated with the PKCS#7 message.
- * If the caller dynamically allocated the message, it must free it.
+ * Release all the storage associated with the PKCS#7 message. If the caller
+ * dynamically allocated the message, it must free it.
*/
void
-pkcs7_signedData_release (struct pkcs7_signedData *msg)
+grub_pkcs7_data_release (grub_pkcs7_data_t *msg)
{
- gcry_mpi_release (msg->sig_mpi);
+ grub_int32_t i;
+
+ for (i = 0; i < msg->signer_count; i++)
+ _gcry_mpi_release (msg->signers[i].sig_mpi);
+
+ grub_free (msg->signers);
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,122 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Sudhakar Kuppusamy <sudhakar@linux.ibm.com>
Date: Mon, 6 Oct 2025 12:54:54 +0530
Subject: [PATCH] powerpc/ieee1275: Enter lockdown based on /ibm, secure-boot
Read secure boot mode from 'ibm,secure-boot' property and if the secure boot
mode is set to 2 (enforce), enter lockdown. Else it is considered as disabled.
There are three secure boot modes. They are
0 - disabled
No signature verification is performed. This is the default.
1 - audit
Signature verification is performed and if signature verification fails,
display the errors and allow the boot to continue.
2 - enforce
Lockdown the GRUB. Signature verification is performed and if signature
verification fails, display the errors and stop the boot.
Now, only support disabled and enforce.
Signed-off-by: Daniel Axtens <dja@axtens.net>
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>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
---
grub-core/kern/ieee1275/init.c | 56 +++++++++++++++++++++++++++++++-----------
1 file changed, 42 insertions(+), 14 deletions(-)
diff --git a/grub-core/kern/ieee1275/init.c b/grub-core/kern/ieee1275/init.c
index 482cad2..0c587d3 100644
--- a/grub-core/kern/ieee1275/init.c
+++ b/grub-core/kern/ieee1275/init.c
@@ -49,7 +49,14 @@
#if defined(__powerpc__) || defined(__i386__)
#include <grub/ieee1275/alloc.h>
#endif
+#if defined(__powerpc__)
#include <grub/lockdown.h>
+#endif
+
+#ifdef __powerpc__
+#define GRUB_SB_DISABLED ((grub_uint32_t) 0)
+#define GRUB_SB_ENFORCE ((grub_uint32_t) 2)
+#endif
/* The maximum heap size we're going to claim. Not used by sparc. */
#ifdef __i386__
@@ -1009,30 +1016,49 @@ grub_parse_cmdline (void)
}
}
+#ifdef __powerpc__
static void
-grub_get_ieee1275_secure_boot (void)
+grub_ieee1275_get_secure_boot (void)
{
grub_ieee1275_phandle_t root;
- int rc;
- grub_uint32_t is_sb;
+ grub_uint32_t sb_mode = GRUB_SB_DISABLED;
+ grub_int32_t rc;
- grub_ieee1275_finddevice ("/", &root);
+ rc = grub_ieee1275_finddevice ("/", &root);
+ if (rc != 0)
+ {
+ grub_error (GRUB_ERR_UNKNOWN_DEVICE, "couldn't find / node");
+ return;
+ }
- rc = grub_ieee1275_get_integer_property (root, "ibm,secure-boot", &is_sb,
- sizeof (is_sb), 0);
-
- /* ibm,secure-boot:
+ rc = grub_ieee1275_get_integer_property (root, "ibm,secure-boot", &sb_mode, sizeof (sb_mode), 0);
+ if (rc != 0)
+ {
+ grub_error (GRUB_ERR_UNKNOWN_DEVICE, "couldn't examine /ibm,secure-boot property");
+ return;
+ }
+ /*
+ * Secure Boot Mode:
* 0 - disabled
+ * No signature verification is performed. This is the default.
* 1 - audit
+ * Signature verification is performed and if signature verification
+ * fails, display the errors and allow the boot to continue.
* 2 - enforce
- * 3 - enforce + OS-specific behaviour
+ * Lockdown the GRUB. Signature verification is performed and If
+ * signature verification fails, display the errors and stop the boot.
*
- * We only support enforce.
+ * Now, only support disabled and enforce.
*/
- if (rc >= 0 && is_sb >= 2)
- grub_lockdown ();
+ if (sb_mode == GRUB_SB_ENFORCE)
+ {
+ grub_dprintf ("ieee1275", "Secure Boot Enabled\n");
+ grub_lockdown ();
+ }
+ else
+ grub_dprintf ("ieee1275", "Secure Boot Disabled\n");
}
-
+#endif /* __powerpc__ */
grub_addr_t grub_modbase;
void
@@ -1059,7 +1085,9 @@ grub_machine_init (void)
grub_install_get_time_ms (grub_rtc_get_time_ms);
#endif
- grub_get_ieee1275_secure_boot ();
+#ifdef __powerpc__
+ grub_ieee1275_get_secure_boot ();
+#endif
}
void

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,775 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Sudhakar Kuppusamy <sudhakar@linux.ibm.com>
Date: Mon, 6 Oct 2025 12:54:56 +0530
Subject: [PATCH] powerpc/ieee1275: Read the db and dbx secure boot variables
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.
If PKS is enabled, it will read secure boot variables such as db and dbx
from PKS and extract EFI Signature List (ESL) from it. The ESLs 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 management mode will be activated:
1. When Secure Boot is enabled with static key management mode
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: Key Management Mode
1 - Enable dynamic key management mode. Read the db and dbx variables from PKS,
and use them for signature verification.
0 - Enable static key management mode. Read keys from the GRUB ELF Note and
use it for signature verification.
Signed-off-by: Sudhakar Kuppusamy <sudhakar@linux.ibm.com>
Reviewed-by: Avnish Chouhan <avnish@linux.ibm.com>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
---
grub-core/Makefile.am | 2 +
grub-core/Makefile.core.def | 2 +
grub-core/kern/ieee1275/ieee1275.c | 1 -
grub-core/kern/ieee1275/init.c | 4 +
grub-core/kern/powerpc/ieee1275/ieee1275.c | 137 +++++++++
.../kern/powerpc/ieee1275/platform_keystore.c | 333 +++++++++++++++++++++
include/grub/ieee1275/ieee1275.h | 3 +
include/grub/powerpc/ieee1275/ieee1275.h | 36 +++
include/grub/powerpc/ieee1275/platform_keystore.h | 123 ++++++++
9 files changed, 640 insertions(+), 1 deletion(-)
create mode 100644 grub-core/kern/powerpc/ieee1275/ieee1275.c
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 aa17239..8dd7014 100644
--- a/grub-core/Makefile.am
+++ b/grub-core/Makefile.am
@@ -247,6 +247,8 @@ KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/ieee1275/alloc.h
KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/terminfo.h
KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/extcmd.h
KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/lib/arg.h
+KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/powerpc/ieee1275/ieee1275.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 15721c5..e16013a 100644
--- a/grub-core/Makefile.core.def
+++ b/grub-core/Makefile.core.def
@@ -338,6 +338,8 @@ kernel = {
powerpc_ieee1275 = kern/powerpc/dl.c;
powerpc_ieee1275 = kern/powerpc/compiler-rt.S;
powerpc_ieee1275 = kern/lockdown.c;
+ powerpc_ieee1275 = kern/powerpc/ieee1275/ieee1275.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/ieee1275.c b/grub-core/kern/ieee1275/ieee1275.c
index 36ca2db..afa37a9 100644
--- a/grub-core/kern/ieee1275/ieee1275.c
+++ b/grub-core/kern/ieee1275/ieee1275.c
@@ -23,7 +23,6 @@
#define IEEE1275_PHANDLE_INVALID ((grub_ieee1275_cell_t) -1)
#define IEEE1275_IHANDLE_INVALID ((grub_ieee1275_cell_t) 0)
-#define IEEE1275_CELL_INVALID ((grub_ieee1275_cell_t) -1)
diff --git a/grub-core/kern/ieee1275/init.c b/grub-core/kern/ieee1275/init.c
index 0c587d3..32ee281 100644
--- a/grub-core/kern/ieee1275/init.c
+++ b/grub-core/kern/ieee1275/init.c
@@ -51,6 +51,8 @@
#endif
#if defined(__powerpc__)
#include <grub/lockdown.h>
+#include <grub/powerpc/ieee1275/ieee1275.h>
+#include <grub/powerpc/ieee1275/platform_keystore.h>
#endif
#ifdef __powerpc__
@@ -1057,6 +1059,8 @@ grub_ieee1275_get_secure_boot (void)
}
else
grub_dprintf ("ieee1275", "Secure Boot Disabled\n");
+
+ grub_pks_keystore_init ();
}
#endif /* __powerpc__ */
grub_addr_t grub_modbase;
diff --git a/grub-core/kern/powerpc/ieee1275/ieee1275.c b/grub-core/kern/powerpc/ieee1275/ieee1275.c
new file mode 100644
index 0000000..20c49e3
--- /dev/null
+++ b/grub-core/kern/powerpc/ieee1275/ieee1275.c
@@ -0,0 +1,137 @@
+/* ieee1275.c - Access the Open Firmware client interface. */
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2003,2004,2005,2007,2008,2009 Free Software Foundation, Inc.
+ * Copyright (C) 2020, 2021, 2022, 2023, 2024, 2025 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/ieee1275/ieee1275.h>
+#include <grub/powerpc/ieee1275/ieee1275.h>
+#include <grub/misc.h>
+
+grub_int32_t
+grub_ieee1275_test (const char *interface_name)
+{
+ struct test_args
+ {
+ struct grub_ieee1275_common_hdr common;/* The header information like interface name, number of inputs and outputs. */
+ grub_ieee1275_cell_t name; /* The interface name. */
+ grub_ieee1275_cell_t missing;
+ } args;
+
+ INIT_IEEE1275_COMMON (&args.common, "test", 1, 1);
+ args.name = (grub_ieee1275_cell_t) interface_name;
+
+ if (IEEE1275_CALL_ENTRY_FN (&args) == -1)
+ return -1;
+
+ if (args.missing == IEEE1275_CELL_INVALID)
+ return -1;
+
+ return 0;
+}
+
+grub_int32_t
+grub_ieee1275_pks_max_object_size (grub_uint32_t *result)
+{
+ struct mos_args
+ {
+ struct grub_ieee1275_common_hdr common;/* The header information like interface name, number of inputs and outputs. */
+ grub_ieee1275_cell_t size; /* The maximum object size for a PKS object. */
+ } args;
+
+ INIT_IEEE1275_COMMON (&args.common, GRUB_PKS_MAX_OBJ_INTERFACE, 0, 1);
+
+ if (IEEE1275_CALL_ENTRY_FN (&args) == -1)
+ return -1;
+
+ if (args.size == IEEE1275_CELL_INVALID || args.size == 0)
+ return -1;
+
+ *result = args.size;
+
+ return 0;
+}
+
+grub_int32_t
+grub_ieee1275_pks_read_object (const grub_uint32_t consumer, const char *label,
+ const grub_uint32_t label_len, const grub_uint32_t buffer_len,
+ grub_uint8_t *buffer, grub_uint32_t *data_len,
+ grub_uint32_t *policies)
+{
+ struct pks_read_args
+ {
+ struct grub_ieee1275_common_hdr common; /* The header information like interface name, number of inputs and outputs. */
+ grub_ieee1275_cell_t consumer; /* The object belonging to consumer with the label. */
+ grub_ieee1275_cell_t label; /* Object label buffer logical real address. */
+ grub_ieee1275_cell_t label_len; /* The byte length of the object label. */
+ grub_ieee1275_cell_t buffer; /* Output buffer logical real address. */
+ grub_ieee1275_cell_t buffer_len; /* Length of the output buffer. */
+ grub_ieee1275_cell_t data_len; /* The number of bytes copied to the output buffer. */
+ grub_ieee1275_cell_t policies; /* The object policies. */
+ grub_int32_t rc; /* The return code. */
+ } args;
+
+ INIT_IEEE1275_COMMON (&args.common, GRUB_PKS_READ_OBJ_INTERFACE, 5, 3);
+ args.consumer = consumer;
+ args.label_len = label_len;
+ args.buffer_len = buffer_len;
+ args.label = (grub_ieee1275_cell_t) label;
+ args.buffer = (grub_ieee1275_cell_t) buffer;
+
+ 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 args.rc;
+}
+
+grub_int32_t
+grub_ieee1275_pks_read_sbvar (const grub_uint32_t sbvar_flags, const grub_uint32_t sbvar_type,
+ const grub_uint32_t buffer_len, grub_uint8_t *buffer,
+ grub_size_t *data_len)
+{
+ struct pks_read_sbvar_args
+ {
+ struct grub_ieee1275_common_hdr common; /* The header information like interface name, number of inputs and outputs. */
+ grub_ieee1275_cell_t sbvar_flags; /* The sbvar operation flags. */
+ grub_ieee1275_cell_t sbvar_type; /* The sbvar being requested. */
+ grub_ieee1275_cell_t buffer; /* Output buffer logical real address. */
+ grub_ieee1275_cell_t buffer_len; /* Length of the Output buffer. */
+ grub_ieee1275_cell_t data_len; /* The number of bytes copied to the output buffer. */
+ grub_int32_t rc; /* The return code. */
+ } args;
+
+ INIT_IEEE1275_COMMON (&args.common, GRUB_PKS_READ_SBVAR_INTERFACE, 4, 2);
+ args.sbvar_flags = sbvar_flags;
+ args.sbvar_type = sbvar_type;
+ args.buffer_len = buffer_len;
+ args.buffer = (grub_ieee1275_cell_t) buffer;
+
+ if (IEEE1275_CALL_ENTRY_FN (&args) == -1)
+ return -1;
+
+ if (args.data_len == IEEE1275_CELL_INVALID)
+ return -1;
+
+ *data_len = args.data_len;
+
+ return args.rc;
+}
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..cc2d493
--- /dev/null
+++ b/grub-core/kern/powerpc/ieee1275/platform_keystore.c
@@ -0,0 +1,333 @@
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2024 Free Software Foundation, Inc.
+ * Copyright (C) 2022, 2023, 2024, 2025 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/types.h>
+#include <grub/misc.h>
+#include <grub/lockdown.h>
+#include <grub/ieee1275/ieee1275.h>
+#include <grub/powerpc/ieee1275/ieee1275.h>
+#include <grub/powerpc/ieee1275/platform_keystore.h>
+
+/* PKS object maximum size. */
+static grub_uint32_t pks_max_object_size = 0;
+
+/* Platform KeyStore db and dbx. */
+static grub_pks_t pks_keystore = { .db = NULL, .dbx = NULL, .db_entries = 0,
+ .dbx_entries = 0, .db_exists = true};
+/*
+ * pks_use_keystore: Key Management Modes
+ * False: Static key management (use built-in Keys). This is default.
+ * True: Dynamic key management (use Platform KeySotre).
+ */
+static bool pks_use_keystore = false;
+
+/*
+ * Reads the Globally Unique Identifier (GUID), EFI Signature Database (ESD),
+ * and its size from the Platform KeyStore EFI Signature List (ESL), then
+ * stores them into the PKS Signature Database (SD) (i.e., pks_sd buffer
+ * and pks_sd entries) in the GRUB.
+ */
+static grub_err_t
+_esl_to_esd (const grub_uint8_t *esl_data, grub_size_t esl_size,
+ const grub_size_t signature_size, const grub_packed_guid_t *guid,
+ grub_pks_sd_t **pks_sd, grub_uint32_t *pks_sd_entries)
+{
+ grub_esd_t *esd;
+ grub_pks_sd_t *signature = *pks_sd;
+ grub_uint32_t entries = *pks_sd_entries;
+ grub_size_t data_size, 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_pks_free_data(). */
+ *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->signature_data, 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_uint32_t *pks_sd_entries)
+{
+ grub_packed_guid_t guid;
+ grub_esl_t *esl;
+ grub_size_t offset, esl_size, signature_size, signature_header_size;
+
+ /* Convert the ESL data into the ESL. */
+ esl = (grub_esl_t *) esl_data;
+ if (*next_esl < sizeof (grub_esl_t) || esl == NULL)
+ return grub_error (GRUB_ERR_BUG, "invalid ESL");
+
+ esl_size = grub_le_to_cpu32 (esl->signature_list_size);
+ signature_header_size = grub_le_to_cpu32 (esl->signature_header_size);
+ signature_size = grub_le_to_cpu32 (esl->signature_size);
+ grub_memcpy (&guid, &esl->signature_type, sizeof (grub_packed_guid_t));
+
+ 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 _esl_to_esd (esl_data + offset, esl_size, signature_size, &guid,
+ pks_sd, pks_sd_entries);
+}
+
+/*
+ * Import the EFI Signature Database (ESD) 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_uint32_t *pks_sd_entries)
+{
+ grub_err_t rc;
+ 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_int32_t rc;
+ grub_uint32_t outlen = 0, policy = 0;
+
+ *out = grub_malloc (pks_max_object_size);
+ if (*out == NULL)
+ return grub_error (GRUB_ERR_OUT_OF_MEMORY, "out of memory");
+
+ rc = grub_ieee1275_pks_read_object (GRUB_PKS_CONSUMER_FW, GRUB_SB_VERSION_KEY_NAME,
+ GRUB_SB_VERSION_KEY_LEN, pks_max_object_size, *out,
+ &outlen, &policy);
+ if (rc < 0)
+ {
+ grub_free (*out);
+ return grub_error (GRUB_ERR_READ_ERROR, "SB version read failed (%d)\n", rc);
+ }
+
+ if (outlen != 1 || (**out >= 2))
+ {
+ grub_free (*out);
+ return grub_error (GRUB_ERR_BAD_NUMBER, "found unexpected SB version: %u\n", **out);
+ }
+
+ return GRUB_ERR_NONE;
+}
+
+/*
+ * Reads 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_sbvar_from_pks (const grub_uint32_t sbvarflags, const grub_uint32_t sbvartype,
+ grub_pks_sd_t **pks_sd, grub_uint32_t *pks_sd_entries)
+{
+ grub_int32_t rc;
+ grub_err_t err = GRUB_ERR_NONE;
+ grub_uint8_t *esl_data = NULL;
+ grub_size_t esl_data_size = 0;
+
+ esl_data = grub_malloc (pks_max_object_size);
+ if (esl_data == NULL)
+ return grub_error (GRUB_ERR_OUT_OF_MEMORY, "out of memory");
+
+ rc = grub_ieee1275_pks_read_sbvar (sbvarflags, sbvartype, pks_max_object_size,
+ esl_data, &esl_data_size);
+ if (rc == IEEE1275_CELL_NOT_FOUND)
+ {
+ err = grub_error (GRUB_ERR_FILE_NOT_FOUND, "secure boot variable %s not found (%d)",
+ (sbvartype == GRUB_PKS_SBVAR_DB) ? "db" : "dbx", rc);
+ goto fail;
+ }
+ else if (rc < 0)
+ {
+ err = grub_error (GRUB_ERR_READ_ERROR, "secure boot variable %s reading (%d)",
+ (sbvartype == GRUB_PKS_SBVAR_DB) ? "db" : "dbx", rc);
+ goto fail;
+ }
+
+ if (esl_data_size > 0)
+ err = pks_sd_from_esl (esl_data, esl_data_size, pks_sd, pks_sd_entries);
+ else
+ err = GRUB_ERR_BAD_NUMBER;
+
+ fail:
+ grub_free (esl_data);
+
+ return err;
+}
+
+/*
+ * Test the availability of PKS support. If PKS support is avaialble and objects
+ * present, it reads the secure boot version (SB_VERSION) from PKS.
+ *
+ * SB_VERSION: Key Management Mode
+ * 1 - Enable dynamic key management mode. Read the db and dbx variables from PKS,
+ * and use them for signature verification.
+ * 0 - Enable static key management mode. Read keys from the GRUB ELF Note and use
+ * it for signature verification.
+ */
+static bool
+is_pks_present (void)
+{
+ grub_err_t err;
+ grub_int32_t rc;
+ grub_uint8_t *data = NULL;
+ bool ret = false;
+
+ rc = grub_ieee1275_test (GRUB_PKS_MAX_OBJ_INTERFACE);
+ if (rc < 0)
+ {
+ grub_error (GRUB_ERR_BAD_FIRMWARE, "firmware doesn't have PKS support\n");
+ return ret;
+ }
+ else
+ {
+ rc = grub_ieee1275_pks_max_object_size (&pks_max_object_size);
+ if (rc < 0)
+ {
+ grub_error (GRUB_ERR_BAD_NUMBER, "PKS support is there but it has zero objects\n");
+ return ret;
+ }
+ }
+
+ err = read_sbversion_from_pks (&data);
+ if (err != GRUB_ERR_NONE)
+ return ret;
+
+ /*
+ * If *data == 1, use dynamic key management and read the keys from the PKS.
+ * Else, use static key management and read the keys from the GRUB ELF Note.
+ */
+ ret = ((*data == 1) ? true : false);
+
+ grub_free (data);
+
+ return ret;
+}
+
+/* Free allocated memory. */
+void
+grub_pks_free_data (void)
+{
+ grub_size_t i;
+
+ for (i = 0; i < pks_keystore.db_entries; i++)
+ grub_free (pks_keystore.db[i].data);
+
+ for (i = 0; i < pks_keystore.dbx_entries; i++)
+ grub_free (pks_keystore.dbx[i].data);
+
+ grub_free (pks_keystore.db);
+ grub_free (pks_keystore.dbx);
+ grub_memset (&pks_keystore, 0, sizeof (grub_pks_t));
+}
+
+grub_pks_t *
+grub_pks_get_keystore (void)
+{
+ return (pks_use_keystore == true) ? &pks_keystore : NULL;
+}
+
+/* Initialization of the Platform KeyStore. */
+void
+grub_pks_keystore_init (void)
+{
+ grub_err_t rc_db, rc_dbx;
+
+ grub_dprintf ("ieee1275", "trying to load Platform KeyStore\n");
+
+ if (is_pks_present () == false)
+ {
+ grub_dprintf ("ieee1275", "Platform PKS is not available\n");
+ return;
+ }
+
+ /*
+ * When read db from PKS, there are three scenarios
+ * 1. db fully loaded from PKS
+ * 2. db partially loaded from PKS
+ * 3. no keys are loaded from db (if db does not exist in PKS), default to
+ * built-in keys (static keys)
+ * each of these scenarios, the db keys are checked against dbx.
+ */
+ rc_db = read_sbvar_from_pks (0, GRUB_PKS_SBVAR_DB, &pks_keystore.db, &pks_keystore.db_entries);
+ if (rc_db == GRUB_ERR_FILE_NOT_FOUND)
+ pks_keystore.db_exists = false;
+
+ /*
+ * Read dbx from PKS. If dbx is not completely loaded from PKS, then this
+ * could lead to the loading of vulnerable GRUB modules and kernel binaries.
+ * So, this should be prevented by freeing up loaded dbx and db.
+ */
+ rc_dbx = read_sbvar_from_pks (0, GRUB_PKS_SBVAR_DBX, &pks_keystore.dbx, &pks_keystore.dbx_entries);
+ if (rc_dbx == GRUB_ERR_FILE_NOT_FOUND || rc_dbx == GRUB_ERR_BAD_NUMBER)
+ rc_dbx = GRUB_ERR_NONE;
+
+ if (rc_dbx != GRUB_ERR_NONE)
+ grub_pks_free_data ();
+
+ /*
+ * At this point, it's evident that PKS infrastructure exists, so the PKS
+ * keystore must be used for validating appended signatures.
+ */
+ pks_use_keystore = true;
+}
diff --git a/include/grub/ieee1275/ieee1275.h b/include/grub/ieee1275/ieee1275.h
index db0ec5f..17aecf2 100644
--- a/include/grub/ieee1275/ieee1275.h
+++ b/include/grub/ieee1275/ieee1275.h
@@ -24,6 +24,9 @@
#include <grub/types.h>
#include <grub/machine/ieee1275.h>
+#define IEEE1275_CELL_INVALID ((grub_ieee1275_cell_t) -1)
+#define IEEE1275_CELL_NOT_FOUND ((grub_int32_t) -7)
+
#define GRUB_IEEE1275_CELL_FALSE ((grub_ieee1275_cell_t) 0)
#define GRUB_IEEE1275_CELL_TRUE ((grub_ieee1275_cell_t) -1)
diff --git a/include/grub/powerpc/ieee1275/ieee1275.h b/include/grub/powerpc/ieee1275/ieee1275.h
index 4eb2070..4b9966d 100644
--- a/include/grub/powerpc/ieee1275/ieee1275.h
+++ b/include/grub/powerpc/ieee1275/ieee1275.h
@@ -28,4 +28,40 @@ typedef grub_uint32_t grub_ieee1275_cell_t;
#define PRIxGRUB_IEEE1275_CELL_T PRIxGRUB_UINT32_T
#define PRIuGRUB_IEEE1275_CELL_T PRIuGRUB_UINT32_T
+#ifdef __powerpc__
+/* The maximum object size interface name for a PKS object. */
+#define GRUB_PKS_MAX_OBJ_INTERFACE "pks-max-object-size"
+
+/* PKS read object and read sbvar interface name. */
+#define GRUB_PKS_READ_OBJ_INTERFACE "pks-read-object"
+#define GRUB_PKS_READ_SBVAR_INTERFACE "pks-read-sbvar"
+
+/* PKS read object label for secure boot version. */
+#define GRUB_SB_VERSION_KEY_NAME "SB_VERSION"
+#define GRUB_SB_VERSION_KEY_LEN (sizeof (GRUB_SB_VERSION_KEY_NAME) - 1)
+
+/* PKS consumer type for firmware. */
+#define GRUB_PKS_CONSUMER_FW ((grub_uint32_t) 1)
+
+/* PKS read secure boot variable request type for db and dbx. */
+#define GRUB_PKS_SBVAR_DB ((grub_uint32_t) 1)
+#define GRUB_PKS_SBVAR_DBX ((grub_uint32_t) 2)
+
+extern grub_int32_t
+grub_ieee1275_test (const char *interface_name);
+
+extern grub_int32_t
+grub_ieee1275_pks_max_object_size (grub_uint32_t *result);
+
+extern grub_int32_t
+grub_ieee1275_pks_read_object (const grub_uint32_t consumer, const char *label,
+ const grub_uint32_t label_len, const grub_uint32_t buffer_len,
+ grub_uint8_t *buffer, grub_uint32_t *data_len,
+ grub_uint32_t *policies);
+
+extern grub_int32_t
+grub_ieee1275_pks_read_sbvar (const grub_uint32_t sbvar_flags, const grub_uint32_t sbvar_type,
+ const grub_uint32_t buffer_len, grub_uint8_t *buffer,
+ grub_size_t *data_len);
+#endif /* __powerpc__ */
#endif /* ! GRUB_IEEE1275_MACHINE_HEADER */
diff --git a/include/grub/powerpc/ieee1275/platform_keystore.h b/include/grub/powerpc/ieee1275/platform_keystore.h
new file mode 100644
index 0000000..931ada2
--- /dev/null
+++ b/include/grub/powerpc/ieee1275/platform_keystore.h
@@ -0,0 +1,123 @@
+/*
+ * 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 2022, 2023, 2024, 2025 IBM Corp.
+ */
+
+#ifndef PLATFORM_KEYSTORE_HEADER
+#define PLATFORM_KEYSTORE_HEADER 1
+
+#include <grub/symbol.h>
+#include <grub/mm.h>
+#include <grub/types.h>
+
+/*
+ * 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_packed_guid_t signature_owner;
+ /* The format of the signature is defined by the SignatureType. */
+ grub_uint8_t signature_data[];
+} GRUB_PACKED;
+typedef struct grub_esd grub_esd_t;
+
+/*
+ * 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_packed_guid_t signature_type;
+ /* Total size of the signature list, including this header. */
+ grub_uint32_t signature_list_size;
+ /* Size of the signature header which precedes the array of signatures. */
+ grub_uint32_t signature_header_size;
+ /* Size of each signature.*/
+ grub_uint32_t signature_size;
+} GRUB_PACKED;
+typedef struct grub_esl grub_esl_t;
+
+/* The structure of a PKS Signature Database (SD). */
+struct grub_pks_sd
+{
+ grub_packed_guid_t guid; /* Signature type. */
+ grub_uint8_t *data; /* Signature data. */
+ grub_size_t data_size; /* Size of signature data. */
+} GRUB_PACKED;
+typedef struct grub_pks_sd grub_pks_sd_t;
+
+/* The structure of a Platform KeyStore (PKS). */
+struct grub_pks
+{
+ grub_pks_sd_t *db; /* Signature database. */
+ grub_pks_sd_t *dbx; /* Forbidden signature database. */
+ grub_uint32_t db_entries; /* Size of signature database. */
+ grub_uint32_t dbx_entries;/* Size of forbidden signature database. */
+ bool db_exists; /* Flag to indicate if the db exists or not in PKS. */
+};
+typedef struct grub_pks grub_pks_t;
+
+#if defined(__powerpc__)
+/* Initialization of the Platform Keystore. */
+extern void
+grub_pks_keystore_init (void);
+
+/* Platform KeyStore db and dbx. */
+extern grub_pks_t *
+EXPORT_FUNC (grub_pks_get_keystore) (void);
+
+/* Free allocated memory. */
+extern void
+EXPORT_FUNC (grub_pks_free_data) (void);
+#else
+static inline grub_pks_t *
+grub_pks_get_keystore (void)
+{
+ return NULL;
+}
+
+static inline void
+grub_pks_free_data (void)
+{
+}
+#endif /* __powerpc__ */
+#endif

View File

@ -0,0 +1,144 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Sudhakar Kuppusamy <sudhakar@linux.ibm.com>
Date: Mon, 6 Oct 2025 12:54:57 +0530
Subject: [PATCH] appended signatures: Introducing key management environment
variable
Introducing the appended signature key management environment variable. It is
automatically set to either "static" or "dynamic" based on the Platform KeyStore.
"static": Enforce static key management signature verification. This is the
default. When the GRUB is locked down, user cannot change the value
by setting the appendedsig_key_mgmt variable back to "dynamic".
"dynamic": Enforce dynamic key management signature verification. When the GRUB
is locked down, user cannot change the value by setting the
appendedsig_key_mgmt variable back to "static".
Signed-off-by: Sudhakar Kuppusamy <sudhakar@linux.ibm.com>
Reviewed-by: Avnish Chouhan <avnish@linux.ibm.com>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
---
grub-core/commands/appendedsig/appendedsig.c | 75 ++++++++++++++++++++++++++++
1 file changed, 75 insertions(+)
diff --git a/grub-core/commands/appendedsig/appendedsig.c b/grub-core/commands/appendedsig/appendedsig.c
index e53efd2..ca54c90 100644
--- a/grub-core/commands/appendedsig/appendedsig.c
+++ b/grub-core/commands/appendedsig/appendedsig.c
@@ -33,6 +33,7 @@
#include <libtasn1.h>
#include <grub/env.h>
#include <grub/lockdown.h>
+#include <grub/powerpc/ieee1275/platform_keystore.h>
#include "appendedsig.h"
@@ -94,6 +95,16 @@ static sb_database_t db = {.certs = NULL, .cert_entries = 0};
*/
static bool check_sigs = false;
+/*
+ * append_key_mgmt: Key Management Modes
+ * False: Static key management (use built-in Keys). This is default.
+ * True: Dynamic key management (use Platform KeySotre).
+ */
+static bool append_key_mgmt = false;
+
+/* Platform KeyStore db and dbx. */
+static grub_pks_t *pks_keystore;
+
static grub_ssize_t
pseudo_read (struct grub_file *file, char *buf, grub_size_t len)
{
@@ -469,6 +480,46 @@ grub_env_write_sec (struct grub_env_var *var __attribute__ ((unused)), const cha
return ret;
}
+static const char *
+grub_env_read_key_mgmt (struct grub_env_var *var __attribute__ ((unused)),
+ const char *val __attribute__ ((unused)))
+{
+ if (append_key_mgmt == true)
+ return "dynamic";
+
+ return "static";
+}
+
+static char *
+grub_env_write_key_mgmt (struct grub_env_var *var __attribute__ ((unused)), const char *val)
+{
+ char *ret;
+
+ /*
+ * Do not allow the value to be changed if signature verification is enabled
+ * (check_sigs is set to true) and GRUB is locked down.
+ */
+ if (check_sigs == true && grub_is_lockdown () == GRUB_LOCKDOWN_ENABLED)
+ {
+ ret = grub_strdup (grub_env_read_key_mgmt (NULL, NULL));
+ if (ret == NULL)
+ grub_error (GRUB_ERR_OUT_OF_MEMORY, "out of memory");
+
+ return ret;
+ }
+
+ if (grub_strcmp (val, "dynamic") == 0)
+ append_key_mgmt = true;
+ else if (grub_strcmp (val, "static") == 0)
+ append_key_mgmt = false;
+
+ ret = grub_strdup (grub_env_read_key_mgmt (NULL, NULL));
+ if (ret == NULL)
+ grub_error (GRUB_ERR_OUT_OF_MEMORY, "out of memory");
+
+ return ret;
+}
+
static grub_err_t
appendedsig_init (grub_file_t io __attribute__ ((unused)), enum grub_file_type type,
void **context __attribute__ ((unused)), enum grub_verify_flags *flags)
@@ -540,6 +591,11 @@ GRUB_MOD_INIT (appendedsig)
if (grub_is_lockdown () == GRUB_LOCKDOWN_ENABLED)
check_sigs = true;
+ /* If PKS keystore is available, use dynamic key management. */
+ pks_keystore = grub_pks_get_keystore ();
+ if (pks_keystore != NULL)
+ append_key_mgmt = true;
+
/*
* This is appended signature verification environment variable. It is
* automatically set to either "no" or "yes" based on the ibm,secure-boot
@@ -554,6 +610,23 @@ GRUB_MOD_INIT (appendedsig)
grub_register_variable_hook ("check_appended_signatures", grub_env_read_sec, grub_env_write_sec);
grub_env_export ("check_appended_signatures");
+ /*
+ * This is appended signature key management environment variable. It is
+ * automatically set to either "static" or "dynamic" based on the
+ * Platform KeyStore.
+ *
+ * "static": Enforce static key management signature verification. This is
+ * the default. When the GRUB is locked down, user cannot change
+ * the value by setting the appendedsig_key_mgmt variable back to
+ * "dynamic".
+ *
+ * "dynamic": Enforce dynamic key management signature verification. When the
+ * GRUB is locked down, user cannot change the value by setting the
+ * appendedsig_key_mgmt variable back to "static".
+ */
+ grub_register_variable_hook ("appendedsig_key_mgmt", grub_env_read_key_mgmt, grub_env_write_key_mgmt);
+ grub_env_export ("appendedsig_key_mgmt");
+
rc = grub_asn1_init ();
if (rc != ASN1_SUCCESS)
grub_fatal ("error initing ASN.1 data structures: %d: %s\n", rc, asn1_strerror (rc));
@@ -577,5 +650,7 @@ GRUB_MOD_FINI (appendedsig)
free_db_list ();
grub_register_variable_hook ("check_appended_signatures", NULL, NULL);
grub_env_unset ("check_appended_signatures");
+ grub_register_variable_hook ("appendedsig_key_mgmt", NULL, NULL);
+ grub_env_unset ("appendedsig_key_mgmt");
grub_verifier_unregister (&grub_appendedsig_verifier);
}

View File

@ -0,0 +1,689 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Sudhakar Kuppusamy <sudhakar@linux.ibm.com>
Date: Mon, 6 Oct 2025 12:54:58 +0530
Subject: [PATCH] appended signatures: Create db and dbx lists
If secure boot is enabled with static key management mode, the trusted
certificates will be extracted from the GRUB ELF Note and added to db list.
If secure boot is enabled with dynamic key management mode, the trusted
certificates and certificate/binary hash will be extracted from the PKS
and added to db list. The distrusted certificates, certificate/binary hash
are read from the PKS and added to dbx list. Both dbx and db lists usage is
added by a subsequent patch.
Note:
- If db does not exist in the PKS storage, then read the static keys as a db
default keys from the GRUB ELF Note and add them into the db list.
- If the certificate or the certificate hash exists in the dbx list, then do not
add that certificate/certificate hash to the db list.
Signed-off-by: Sudhakar Kuppusamy <sudhakar@linux.ibm.com>
Reviewed-by: Avnish Chouhan <avnish@linux.ibm.com>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
---
grub-core/commands/appendedsig/appendedsig.c | 407 +++++++++++++++++++++++++--
include/grub/efi/pks.h | 112 ++++++++
include/grub/types.h | 4 +
3 files changed, 506 insertions(+), 17 deletions(-)
create mode 100644 include/grub/efi/pks.h
diff --git a/grub-core/commands/appendedsig/appendedsig.c b/grub-core/commands/appendedsig/appendedsig.c
index ca54c90..0c4c788 100644
--- a/grub-core/commands/appendedsig/appendedsig.c
+++ b/grub-core/commands/appendedsig/appendedsig.c
@@ -34,6 +34,7 @@
#include <grub/env.h>
#include <grub/lockdown.h>
#include <grub/powerpc/ieee1275/platform_keystore.h>
+#include <grub/efi/pks.h>
#include "appendedsig.h"
@@ -46,6 +47,11 @@ GRUB_MOD_LICENSE ("GPLv3+");
#define SIG_MAGIC "~Module signature appended~\n"
#define SIG_MAGIC_SIZE ((sizeof(SIG_MAGIC) - 1))
+/* SHA256, SHA384 and SHA512 hash sizes. */
+#define SHA256_HASH_SIZE 32
+#define SHA384_HASH_SIZE 48
+#define SHA512_HASH_SIZE 64
+
/*
* This structure is extracted from scripts/sign-file.c in the linux kernel
* source. It was licensed as LGPLv2.1+, which is GPLv3+ compatible.
@@ -79,11 +85,23 @@ struct sb_database
{
grub_x509_cert_t *certs; /* Certificates. */
grub_uint32_t cert_entries; /* Number of certificates. */
+ grub_uint8_t **hashes; /* Certificate/binary hashes. */
+ grub_size_t *hash_sizes; /* Sizes of certificate/binary hashes. */
+ grub_uint32_t hash_entries; /* Number of certificate/binary hashes. */
+ bool is_db; /* Flag to indicate the db/dbx list. */
};
typedef struct sb_database sb_database_t;
/* The db list is used to validate appended signatures. */
-static sb_database_t db = {.certs = NULL, .cert_entries = 0};
+static sb_database_t db = {.certs = NULL, .cert_entries = 0, .hashes = NULL,
+ .hash_sizes = NULL, .hash_entries = 0, .is_db = true};
+/*
+ * The dbx list is used to ensure that the distrusted certificates or GRUB
+ * modules/kernel binaries are rejected during appended signatures/hashes
+ * validation.
+ */
+static sb_database_t dbx = {.certs = NULL, .cert_entries = 0, .hashes = NULL,
+ .hash_sizes = NULL, .hash_entries = 0, .is_db = false};
/*
* Signature verification flag (check_sigs).
@@ -118,6 +136,169 @@ static struct grub_fs pseudo_fs = {
.fs_read = pseudo_read
};
+/*
+ * 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_packed_guid_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 not available");
+
+ if (grub_memcmp (guid, &GRUB_PKS_CERT_SHA256_GUID, GRUB_PACKED_GUID_SIZE) == 0 ||
+ grub_memcmp (guid, &GRUB_PKS_CERT_X509_SHA256_GUID, GRUB_PACKED_GUID_SIZE) == 0)
+ hash_func = &_gcry_digest_spec_sha256;
+ else if (grub_memcmp (guid, &GRUB_PKS_CERT_SHA384_GUID, GRUB_PACKED_GUID_SIZE) == 0 ||
+ grub_memcmp (guid, &GRUB_PKS_CERT_X509_SHA384_GUID, GRUB_PACKED_GUID_SIZE) == 0)
+ hash_func = &_gcry_digest_spec_sha384;
+ else if (grub_memcmp (guid, &GRUB_PKS_CERT_SHA512_GUID, GRUB_PACKED_GUID_SIZE) == 0 ||
+ grub_memcmp (guid, &GRUB_PKS_CERT_X509_SHA512_GUID, GRUB_PACKED_GUID_SIZE) == 0)
+ hash_func = &_gcry_digest_spec_sha512;
+ else
+ return grub_error (GRUB_ERR_OUT_OF_RANGE, "unsupported GUID hash");
+
+ grub_crypto_hash (hash_func, hash, data, data_size);
+ *hash_size = hash_func->mdlen;
+
+ return GRUB_ERR_NONE;
+}
+
+static grub_err_t
+generate_cert_hash (const grub_size_t cert_hash_size, const grub_uint8_t *data,
+ const grub_size_t data_size, grub_uint8_t *hash, grub_size_t *hash_size)
+{
+ grub_packed_guid_t guid = { 0 };
+
+ /* support SHA256, SHA384 and SHA512 for certificate hash */
+ if (cert_hash_size == SHA256_HASH_SIZE)
+ grub_memcpy (&guid, &GRUB_PKS_CERT_X509_SHA256_GUID, GRUB_PACKED_GUID_SIZE);
+ else if (cert_hash_size == SHA384_HASH_SIZE)
+ grub_memcpy (&guid, &GRUB_PKS_CERT_X509_SHA384_GUID, GRUB_PACKED_GUID_SIZE);
+ else if (cert_hash_size == SHA512_HASH_SIZE)
+ grub_memcpy (&guid, &GRUB_PKS_CERT_X509_SHA512_GUID, GRUB_PACKED_GUID_SIZE);
+ else
+ {
+ grub_dprintf ("appendedsig", "unsupported hash type (%" PRIuGRUB_SIZE ") and "
+ "skipped\n", cert_hash_size);
+ return GRUB_ERR_UNKNOWN_COMMAND;
+ }
+
+ return get_hash (&guid, data, data_size, hash, hash_size);
+}
+
+/* Check the hash presence in the db/dbx list. */
+static bool
+check_hash_presence (grub_uint8_t *const hash, const grub_size_t hash_size,
+ const sb_database_t *sb_database)
+{
+ grub_uint32_t i;
+
+ for (i = 0; i < sb_database->hash_entries; i++)
+ {
+ if (sb_database->hashes[i] == NULL)
+ continue;
+
+ if (hash_size == sb_database->hash_sizes[i] &&
+ grub_memcmp (sb_database->hashes[i], hash, hash_size) == 0)
+ return true;
+ }
+
+ return false;
+}
+
+/* Add the certificate/binary hash into the db/dbx list. */
+static grub_err_t
+add_hash (grub_uint8_t *const data, const grub_size_t data_size, sb_database_t *sb_database)
+{
+ grub_uint8_t **hashes;
+ grub_size_t *hash_sizes;
+
+ if (data == NULL || data_size == 0)
+ return grub_error (GRUB_ERR_OUT_OF_RANGE, "certificate/binary-hash data or size is not available");
+
+ if (sb_database->is_db == true)
+ {
+ if (check_hash_presence (data, data_size, &dbx) == true)
+ {
+ grub_dprintf ("appendedsig",
+ "cannot add a hash (%02x%02x%02x%02x), as it is present in the dbx list\n",
+ data[0], data[1], data[2], data[3]);
+ return GRUB_ERR_ACCESS_DENIED;
+ }
+ }
+
+ if (check_hash_presence (data, data_size, sb_database) == true)
+ {
+ grub_dprintf ("appendedsig",
+ "cannot add a hash (%02x%02x%02x%02x), as it is present in the %s list\n",
+ data[0], data[1], data[2], data[3], ((sb_database->is_db == true) ? "db" : "dbx"));
+ return GRUB_ERR_EXISTS;
+ }
+
+ hashes = grub_realloc (sb_database->hashes, sizeof (grub_uint8_t *) * (sb_database->hash_entries + 1));
+ if (hashes == NULL)
+ return grub_error (GRUB_ERR_OUT_OF_MEMORY, "out of memory");
+
+ hash_sizes = grub_realloc (sb_database->hash_sizes, sizeof (grub_size_t) * (sb_database->hash_entries + 1));
+ if (hash_sizes == NULL)
+ {
+ /* Allocated memory will be freed by free_db_list()/free_dbx_list(). */
+ hashes[sb_database->hash_entries] = NULL;
+ sb_database->hashes = hashes;
+ sb_database->hash_entries++;
+
+ return grub_error (GRUB_ERR_OUT_OF_MEMORY, "out of memory");
+ }
+
+ hashes[sb_database->hash_entries] = grub_malloc (data_size);
+ if (hashes[sb_database->hash_entries] == NULL)
+ return grub_error (GRUB_ERR_OUT_OF_MEMORY, "out of memory");
+
+ grub_dprintf ("appendedsig",
+ "added the hash %02x%02x%02x%02x... with size of %" PRIuGRUB_SIZE " to the %s list\n",
+ data[0], data[1], data[2], data[3], data_size,
+ ((sb_database->is_db == true) ? "db" : "dbx"));
+
+ grub_memcpy (hashes[sb_database->hash_entries], data, data_size);
+ hash_sizes[sb_database->hash_entries] = data_size;
+ sb_database->hash_sizes = hash_sizes;
+ sb_database->hashes = hashes;
+ sb_database->hash_entries++;
+
+ return GRUB_ERR_NONE;
+}
+
+static bool
+is_hash (const grub_packed_guid_t *guid)
+{
+ /* GUID type of the binary hash. */
+ if (grub_memcmp (guid, &GRUB_PKS_CERT_SHA256_GUID, GRUB_PACKED_GUID_SIZE) == 0 ||
+ grub_memcmp (guid, &GRUB_PKS_CERT_SHA384_GUID, GRUB_PACKED_GUID_SIZE) == 0 ||
+ grub_memcmp (guid, &GRUB_PKS_CERT_SHA512_GUID, GRUB_PACKED_GUID_SIZE) == 0)
+ return true;
+
+ /* GUID type of the certificate hash. */
+ if (grub_memcmp (guid, &GRUB_PKS_CERT_X509_SHA256_GUID, GRUB_PACKED_GUID_SIZE) == 0 ||
+ grub_memcmp (guid, &GRUB_PKS_CERT_X509_SHA384_GUID, GRUB_PACKED_GUID_SIZE) == 0 ||
+ grub_memcmp (guid, &GRUB_PKS_CERT_X509_SHA512_GUID, GRUB_PACKED_GUID_SIZE) == 0)
+ return true;
+
+ return false;
+}
+
+static bool
+is_x509 (const grub_packed_guid_t *guid)
+{
+ if (grub_memcmp (guid, &GRUB_PKS_CERT_X509_GUID, GRUB_PACKED_GUID_SIZE) == 0)
+ return true;
+
+ return false;
+}
+
static bool
is_cert_match (const grub_x509_cert_t *cert1, const grub_x509_cert_t *cert2)
{
@@ -136,7 +317,33 @@ is_cert_match (const grub_x509_cert_t *cert1, const grub_x509_cert_t *cert2)
return false;
}
-/* Check the certificate presence in the db list. */
+/* Check the certificate hash presence in the dbx list. */
+static bool
+is_cert_hash_present_in_dbx (const grub_uint8_t *data, const grub_size_t data_size)
+{
+ grub_err_t rc;
+ grub_uint32_t i;
+ grub_size_t cert_hash_size = 0;
+ grub_uint8_t cert_hash[GRUB_MAX_HASH_LEN] = { 0 };
+
+ for (i = 0; i < dbx.hash_entries; i++)
+ {
+ if (dbx.hashes[i] == NULL)
+ continue;
+
+ rc = generate_cert_hash (dbx.hash_sizes[i], data, data_size, cert_hash, &cert_hash_size);
+ if (rc != GRUB_ERR_NONE)
+ continue;
+
+ if (cert_hash_size == dbx.hash_sizes[i] &&
+ grub_memcmp (dbx.hashes[i], cert_hash, cert_hash_size) == 0)
+ return true;
+ }
+
+ return false;
+}
+
+/* Check the certificate presence in the db/dbx list. */
static bool
check_cert_presence (const grub_x509_cert_t *cert_in, const sb_database_t *sb_database)
{
@@ -149,7 +356,11 @@ check_cert_presence (const grub_x509_cert_t *cert_in, const sb_database_t *sb_da
return false;
}
-/* Add the certificate into the db list */
+/*
+ * Add the certificate into the db list if it is not present in the dbx and db
+ * list when is_db is true. Add the certificate into the dbx list when is_db is
+ * false.
+ */
static grub_err_t
add_certificate (const grub_uint8_t *data, const grub_size_t data_size,
sb_database_t *sb_database)
@@ -167,30 +378,54 @@ add_certificate (const grub_uint8_t *data, const grub_size_t data_size,
rc = grub_x509_cert_parse (data, data_size, cert);
if (rc != GRUB_ERR_NONE)
{
- grub_dprintf ("appendedsig", "cannot add a certificate CN='%s' to the db list\n",
- cert->subject);
+ grub_dprintf ("appendedsig", "cannot add a certificate CN='%s' to the %s list\n",
+ cert->subject, (sb_database->is_db == true) ? "db" : "dbx");
grub_free (cert);
return rc;
}
+ /*
+ * Only checks the certificate against dbx if is_db is true when dynamic key
+ * management is enabled.
+ */
+ if (append_key_mgmt == true)
+ {
+ if (sb_database->is_db == true)
+ {
+ if (is_cert_hash_present_in_dbx (data, data_size) == true ||
+ check_cert_presence (cert, &dbx) == true)
+ {
+ grub_dprintf ("appendedsig",
+ "cannot add a certificate CN='%s', as it is present in the dbx list",
+ cert->subject);
+ rc = GRUB_ERR_ACCESS_DENIED;
+ goto fail;
+ }
+ }
+ }
+
if (check_cert_presence (cert, sb_database) == true)
{
grub_dprintf ("appendedsig",
- "cannot add a certificate CN='%s', as it is present in the db list",
- cert->subject);
- grub_x509_cert_release (cert);
- grub_free (cert);
-
- return GRUB_ERR_EXISTS;
+ "cannot add a certificate CN='%s', as it is present in the %s list",
+ cert->subject, ((sb_database->is_db == true) ? "db" : "dbx"));
+ rc = GRUB_ERR_EXISTS;
+ goto fail;
}
- grub_dprintf ("appendedsig", "added a certificate CN='%s' to the db list\n",
- cert->subject);
+ grub_dprintf ("appendedsig", "added a certificate CN='%s' to the %s list\n",
+ cert->subject, ((sb_database->is_db == true) ? "db" : "dbx"));
cert->next = sb_database->certs;
sb_database->certs = cert;
sb_database->cert_entries++;
+ return rc;
+
+ fail:
+ grub_x509_cert_release (cert);
+ grub_free (cert);
+
return rc;
}
@@ -382,6 +617,68 @@ grub_verify_appended_signature (const grub_uint8_t *buf, grub_size_t bufsize)
return err;
}
+/* Add the X.509 certificates/binary hash to the db list from PKS. */
+static grub_err_t
+load_pks2db (void)
+{
+ grub_err_t rc;
+ grub_uint32_t i;
+
+ for (i = 0; i < pks_keystore->db_entries; i++)
+ {
+ if (is_hash (&pks_keystore->db[i].guid) == true)
+ {
+ rc = add_hash (pks_keystore->db[i].data,
+ pks_keystore->db[i].data_size, &db);
+ if (rc == GRUB_ERR_OUT_OF_MEMORY)
+ return rc;
+ }
+ else if (is_x509 (&pks_keystore->db[i].guid) == true)
+ {
+ rc = add_certificate (pks_keystore->db[i].data,
+ pks_keystore->db[i].data_size, &db);
+ if (rc == GRUB_ERR_OUT_OF_MEMORY)
+ return rc;
+ }
+ else
+ grub_dprintf ("appendedsig", "unsupported signature data type and "
+ "skipped (%u)\n", i + 1);
+ }
+
+ return GRUB_ERR_NONE;
+}
+
+/* Add the certificates and certificate/binary hash to the dbx list from PKS. */
+static grub_err_t
+load_pks2dbx (void)
+{
+ grub_err_t rc;
+ grub_uint32_t i;
+
+ for (i = 0; i < pks_keystore->dbx_entries; i++)
+ {
+ if (is_x509 (&pks_keystore->dbx[i].guid) == true)
+ {
+ rc = add_certificate (pks_keystore->dbx[i].data,
+ pks_keystore->dbx[i].data_size, &dbx);
+ if (rc == GRUB_ERR_OUT_OF_MEMORY)
+ return rc;
+ }
+ else if (is_hash (&pks_keystore->dbx[i].guid) == true)
+ {
+ rc = add_hash (pks_keystore->dbx[i].data,
+ pks_keystore->dbx[i].data_size, &dbx);
+ if (rc != GRUB_ERR_NONE)
+ return rc;
+ }
+ else
+ grub_dprintf ("appendedsig", "unsupported signature data type and "
+ "skipped (%u)\n", i + 1);
+ }
+
+ return GRUB_ERR_NONE;
+}
+
/*
* Extract the X.509 certificates from the ELF Note header, parse it, and add
* it to the db list.
@@ -422,11 +719,45 @@ load_elf2db (void)
}
}
+/*
+ * Extract trusted and distrusted keys from PKS and store them in the db and
+ * dbx list.
+ */
+static void
+create_dbs_from_pks (void)
+{
+ grub_err_t err;
+
+ err = load_pks2dbx ();
+ if (err != GRUB_ERR_NONE)
+ grub_printf ("warning: dbx list might not be fully populated\n");
+
+ /*
+ * If db does not exist in the PKS storage, then read the static keys as a db
+ * default keys from the GRUB ELF Note and add them into the db list.
+ */
+ if (pks_keystore->db_exists == false)
+ load_elf2db ();
+ else
+ {
+ err = load_pks2db ();
+ if (err != GRUB_ERR_NONE)
+ grub_printf ("warning: db list might not be fully populated\n");
+ }
+
+ grub_pks_free_data ();
+ grub_dprintf ("appendedsig", "the db list now has %u keys\n"
+ "the dbx list now has %u keys\n",
+ db.hash_entries + db.cert_entries,
+ dbx.hash_entries + dbx.cert_entries);
+}
+
/* Free db list memory */
static void
free_db_list (void)
{
grub_x509_cert_t *cert;
+ grub_uint32_t i;
while (db.certs != NULL)
{
@@ -436,9 +767,37 @@ free_db_list (void)
grub_free (cert);
}
+ for (i = 0; i < db.hash_entries; i++)
+ grub_free (db.hashes[i]);
+
+ grub_free (db.hashes);
+ grub_free (db.hash_sizes);
grub_memset (&db, 0, sizeof (sb_database_t));
}
+/* Free dbx list memory */
+static void
+free_dbx_list (void)
+{
+ grub_x509_cert_t *cert;
+ grub_uint32_t i;
+
+ while (dbx.certs != NULL)
+ {
+ cert = dbx.certs;
+ dbx.certs = dbx.certs->next;
+ grub_x509_cert_release (cert);
+ grub_free (cert);
+ }
+
+ for (i = 0; i < dbx.hash_entries; i++)
+ grub_free (dbx.hashes[i]);
+
+ grub_free (dbx.hashes);
+ grub_free (dbx.hash_sizes);
+ grub_memset (&dbx, 0, sizeof (sb_database_t));
+}
+
static const char *
grub_env_read_sec (struct grub_env_var *var __attribute__ ((unused)),
const char *val __attribute__ ((unused)))
@@ -631,10 +990,23 @@ GRUB_MOD_INIT (appendedsig)
if (rc != ASN1_SUCCESS)
grub_fatal ("error initing ASN.1 data structures: %d: %s\n", rc, asn1_strerror (rc));
- /* Extract trusted keys from ELF Note and store them in the db. */
- load_elf2db ();
- grub_dprintf ("appendedsig", "the db list now has %u static keys\n",
- db.cert_entries);
+ /*
+ * If signature verification is enabled with the dynamic key management,
+ * extract trusted and distrusted keys from PKS and store them in the db
+ * and dbx list.
+ */
+ if (append_key_mgmt == true)
+ create_dbs_from_pks ();
+ /*
+ * If signature verification is enabled with the static key management,
+ * extract trusted keys from ELF Note and store them in the db list.
+ */
+ else
+ {
+ load_elf2db ();
+ grub_dprintf ("appendedsig", "the db list now has %u static keys\n",
+ db.cert_entries);
+ }
grub_verifier_register (&grub_appendedsig_verifier);
grub_dl_set_persistent (mod);
@@ -648,6 +1020,7 @@ GRUB_MOD_FINI (appendedsig)
*/
free_db_list ();
+ free_dbx_list ();
grub_register_variable_hook ("check_appended_signatures", NULL, NULL);
grub_env_unset ("check_appended_signatures");
grub_register_variable_hook ("appendedsig_key_mgmt", NULL, NULL);
diff --git a/include/grub/efi/pks.h b/include/grub/efi/pks.h
new file mode 100644
index 0000000..ff306f5
--- /dev/null
+++ b/include/grub/efi/pks.h
@@ -0,0 +1,112 @@
+/*
+ * 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 2022, 2023, 2024, 2025 IBM Corp.
+ */
+
+#ifndef PKS_HEADER
+#define PKS_HEADER 1
+
+#include <grub/types.h>
+
+/*
+ * 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_guid_t) \
+ { 0xa159c0a5, 0xe494, 0xa74a, \
+ { 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_guid_t) \
+ { 0x2616c4c1, 0x4c50, 0x9240, \
+ { 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_guid_t) \
+ { 0x07533eff, 0xd09f, 0xc948, \
+ { 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_guid_t) \
+ { 0xae0f3e09, 0xc4a6, 0x504f, \
+ { 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_guid_t) \
+ { 0x92a4d23b, 0xc096, 0x7940, \
+ { 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_guid_t) \
+ { 0x6e877670, 0xc280, 0xe64e, \
+ { 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_guid_t) \
+ { 0x63bf6d44, 0x0225, 0xda4c, \
+ { 0xbc, 0xfa, 0x24, 0x65, 0xd2, 0xb0, 0xfe, 0x9d } \
+ }
+
+#endif
diff --git a/include/grub/types.h b/include/grub/types.h
index 59e0302..5f37adb 100644
--- a/include/grub/types.h
+++ b/include/grub/types.h
@@ -380,6 +380,8 @@ struct grub_guid
} __attribute__ ((aligned(4)));
typedef struct grub_guid grub_guid_t;
+#define GRUB_GUID_SIZE (sizeof (grub_guid_t))
+
struct grub_packed_guid
{
grub_uint32_t data1;
@@ -389,4 +391,6 @@ struct grub_packed_guid
} GRUB_PACKED;
typedef struct grub_packed_guid grub_packed_guid_t;
+#define GRUB_PACKED_GUID_SIZE (sizeof (grub_packed_guid_t))
+
#endif /* ! GRUB_TYPES_HEADER */

View File

@ -0,0 +1,136 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Sudhakar Kuppusamy <sudhakar@linux.ibm.com>
Date: Mon, 6 Oct 2025 12:54:59 +0530
Subject: [PATCH] appended signatures: Using db and dbx lists for signature
verification
Signature verification: verify the kernel against lists of hashes that are
either in dbx or db list. If it is not in the dbx list then the trusted keys
from the db list are used to verify the signature.
Signed-off-by: Sudhakar Kuppusamy <sudhakar@linux.ibm.com>
Reviewed-by: Avnish Chouhan <avnish@linux.ibm.com>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
---
grub-core/commands/appendedsig/appendedsig.c | 94 +++++++++++++++++++++++++++-
1 file changed, 93 insertions(+), 1 deletion(-)
diff --git a/grub-core/commands/appendedsig/appendedsig.c b/grub-core/commands/appendedsig/appendedsig.c
index 0c4c788..9cfa1be 100644
--- a/grub-core/commands/appendedsig/appendedsig.c
+++ b/grub-core/commands/appendedsig/appendedsig.c
@@ -521,6 +521,83 @@ extract_appended_signature (const grub_uint8_t *buf, grub_size_t bufsize,
return grub_pkcs7_data_parse (signed_data, appendedsig_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_packed_guid_t guid = { 0 };
+
+ /* support SHA256, SHA384 and SHA512 for binary hash */
+ if (binary_hash_size == SHA256_HASH_SIZE)
+ grub_memcpy (&guid, &GRUB_PKS_CERT_SHA256_GUID, GRUB_PACKED_GUID_SIZE);
+ else if (binary_hash_size == SHA384_HASH_SIZE)
+ grub_memcpy (&guid, &GRUB_PKS_CERT_SHA384_GUID, GRUB_PACKED_GUID_SIZE);
+ else if (binary_hash_size == SHA512_HASH_SIZE)
+ grub_memcpy (&guid, &GRUB_PKS_CERT_SHA512_GUID, GRUB_PACKED_GUID_SIZE);
+ else
+ {
+ grub_dprintf ("appendedsig", "unsupported hash type (%" PRIuGRUB_SIZE ") and "
+ "skipped\n", binary_hash_size);
+ return GRUB_ERR_UNKNOWN_COMMAND;
+ }
+
+ return get_hash (&guid, data, data_size, hash, hash_size);
+}
+
+/*
+ * Verify binary hash against the db and dbx list.
+ * The following errors can occur:
+ * - GRUB_ERR_BAD_SIGNATURE: indicates that the hash is in dbx list.
+ * - GRUB_ERR_EOF: the hash could not be found in the db and dbx list.
+ * - GRUB_ERR_NONE: the hash is found in db 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_uint32_t i;
+ grub_size_t hash_size = 0;
+ grub_uint8_t hash[GRUB_MAX_HASH_LEN] = { 0 };
+
+ for (i = 0; i < dbx.hash_entries; i++)
+ {
+ if (dbx.hashes[i] == NULL)
+ continue;
+
+ rc = get_binary_hash (dbx.hash_sizes[i], data, data_size, hash, &hash_size);
+ if (rc != GRUB_ERR_NONE)
+ continue;
+
+ if (hash_size == dbx.hash_sizes[i] &&
+ grub_memcmp (dbx.hashes[i], hash, hash_size) == 0)
+ {
+ grub_dprintf ("appendedsig", "the hash (%02x%02x%02x%02x) is present in the dbx list\n",
+ hash[0], hash[1], hash[2], hash[3]);
+ return GRUB_ERR_BAD_SIGNATURE;
+ }
+ }
+
+ for (i = 0; i < db.hash_entries; i++)
+ {
+ if (db.hashes[i] == NULL)
+ continue;
+
+ rc = get_binary_hash (db.hash_sizes[i], data, data_size, hash, &hash_size);
+ if (rc != GRUB_ERR_NONE)
+ continue;
+
+ if (hash_size == db.hash_sizes[i] &&
+ grub_memcmp (db.hashes[i], hash, hash_size) == 0)
+ {
+ grub_dprintf ("appendedsig", "verified with a trusted hash (%02x%02x%02x%02x)\n",
+ hash[0], hash[1], hash[2], hash[3]);
+ return GRUB_ERR_NONE;
+ }
+ }
+
+ return GRUB_ERR_EOF;
+}
+
/*
* Given a hash value 'hval', of hash specification 'hash', prepare the
* S-expressions (sexp) and perform the signature verification.
@@ -565,7 +642,7 @@ grub_verify_appended_signature (const grub_uint8_t *buf, grub_size_t bufsize)
grub_pkcs7_signer_t *si;
grub_int32_t i;
- if (!db.cert_entries)
+ if (!db.cert_entries && !db.hash_entries)
return grub_error (GRUB_ERR_BAD_SIGNATURE, "no trusted keys to verify against");
err = extract_appended_signature (buf, bufsize, &sig);
@@ -574,6 +651,21 @@ grub_verify_appended_signature (const grub_uint8_t *buf, grub_size_t bufsize)
datasize = bufsize - sig.signature_len;
+ /*
+ * If signature verification is enabled with dynamic key management mode,
+ * Verify binary hash against the db and dbx list.
+ */
+ if (append_key_mgmt == true)
+ {
+ err = verify_binary_hash (buf, datasize);
+ if (err == GRUB_ERR_BAD_SIGNATURE)
+ {
+ grub_pkcs7_data_release (&sig.pkcs7);
+ return grub_error (err,
+ "failed to verify the binary hash against a trusted binary hash");
+ }
+ }
+
/* Verify signature using trusted keys from db list. */
for (i = 0; i < sig.pkcs7.signer_count; i++)
{

View File

@ -0,0 +1,406 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Sudhakar Kuppusamy <sudhakar@linux.ibm.com>
Date: Mon, 6 Oct 2025 12:55:00 +0530
Subject: [PATCH] appended signatures: GRUB commands to manage the certificates
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Introducing the following GRUB commands to manage the certificates.
1. append_list_db:
Show the list of trusted certificates from the db list
2. append_add_db_cert:
Add the trusted certificate to the db list
3. append_add_dbx_cert:
Add the distrusted certificate to the dbx list
4. append_verify:
Verify the signed file using db list
Note that if signature verification (check_appended_signatures) is set to yes,
the append_add_db_cert and append_add_dbx_cert commands only accept the file
X509_certificate that is signed with an appended signature.
Signed-off-by: Daniel Axtens <dja@axtens.net>
Signed-off-by: Sudhakar Kuppusamy <sudhakar@linux.ibm.com>
Tested-by: Sridhar Markonda <sridharm@linux.ibm.com>
Reviewed-by: Avnish Chouhan <avnish@linux.ibm.com>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
---
grub-core/commands/appendedsig/appendedsig.c | 316 +++++++++++++++++++++++++++
1 file changed, 316 insertions(+)
diff --git a/grub-core/commands/appendedsig/appendedsig.c b/grub-core/commands/appendedsig/appendedsig.c
index 9cfa1be..614ebee 100644
--- a/grub-core/commands/appendedsig/appendedsig.c
+++ b/grub-core/commands/appendedsig/appendedsig.c
@@ -123,6 +123,9 @@ static bool append_key_mgmt = false;
/* Platform KeyStore db and dbx. */
static grub_pks_t *pks_keystore;
+/* Appended signature size. */
+static grub_size_t append_sig_len = 0;
+
static grub_ssize_t
pseudo_read (struct grub_file *file, char *buf, grub_size_t len)
{
@@ -136,6 +139,65 @@ static struct grub_fs pseudo_fs = {
.fs_read = pseudo_read
};
+/*
+ * We cannot use hexdump() to display hash data because it is typically displayed
+ * in hexadecimal format, along with an ASCII representation of the same data.
+ *
+ * Example: sha256 hash data
+ * 00000000 52 b5 90 49 64 de 22 d7 4e 5f 4f b4 1b 51 9c 34 |R..Id.".N_O..Q.4|
+ * 00000010 b1 96 21 7c 91 78 a5 0d 20 8c e9 5c 22 54 53 f7 |..!|.x.. ..\"TS.|
+ *
+ * An appended signature only required to display the hexadecimal of the hash data
+ * by separating each byte with ":". So, we introduced a new method hexdump_colon
+ * to display it.
+ *
+ * Example: Sha256 hash data
+ * 52:b5:90:49:64:de:22:d7:4e:5f:4f:b4:1b:51:9c:34:
+ * b1:96:21:7c:91:78:a5:0d:20:8c:e9:5c:22:54:53:f7
+ */
+static void
+hexdump_colon (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 ");
+ count = 0;
+ }
+ }
+
+ grub_printf ("%02x\n", data[i]);
+}
+
+static void
+print_certificate (const grub_x509_cert_t *cert, const grub_uint32_t cert_num)
+{
+ grub_uint32_t i;
+
+ grub_printf ("\nCertificate: %u\n", cert_num);
+ grub_printf (" Data:\n");
+ grub_printf (" Version: %u (0x%u)\n", cert->version + 1, cert->version);
+ grub_printf (" Serial Number:\n ");
+
+ 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 (" Issuer: %s\n", cert->issuer);
+ grub_printf (" Subject: %s\n", cert->subject);
+ grub_printf (" Subject Public Key Info:\n");
+ grub_printf (" Public Key Algorithm: rsaEncryption\n");
+ grub_printf (" RSA Public-Key: (%d bit)\n", cert->modulus_size);
+ grub_printf (" Fingerprint: sha256\n ");
+ hexdump_colon (&cert->fingerprint[GRUB_FINGERPRINT_SHA256][0],
+ grub_strlen ((char *) cert->fingerprint[GRUB_FINGERPRINT_SHA256]));
+}
+
/*
* GUID can be used to determine the hashing function and generate the hash using
* determined hashing function.
@@ -429,6 +491,61 @@ add_certificate (const grub_uint8_t *data, const grub_size_t data_size,
return rc;
}
+static void
+_remove_cert_from_db (const grub_x509_cert_t *cert)
+{
+ grub_uint32_t i = 1;
+ grub_x509_cert_t *curr_cert, *prev_cert;
+
+ for (curr_cert = prev_cert = db.certs; curr_cert != NULL; curr_cert = curr_cert->next, i++)
+ {
+ if (is_cert_match (curr_cert, cert) == true)
+ {
+ if (i == 1) /* Match with first certificate in the db list. */
+ db.certs = curr_cert->next;
+ else
+ prev_cert->next = curr_cert->next;
+
+ grub_dprintf ("appendedsig",
+ "removed distrusted certificate with CN: %s from the db list\n",
+ curr_cert->subject);
+ curr_cert->next = NULL;
+ grub_x509_cert_release (curr_cert);
+ grub_free (curr_cert);
+ break;
+ }
+ else
+ prev_cert = curr_cert;
+ }
+}
+
+static grub_err_t
+remove_cert_from_db (const grub_uint8_t *data, const grub_size_t data_size)
+{
+ grub_err_t rc;
+ grub_x509_cert_t *cert;
+
+ if (data == NULL || data_size == 0)
+ return grub_error (GRUB_ERR_OUT_OF_RANGE, "certificate data or size is not available");
+
+ cert = grub_zalloc (sizeof (grub_x509_cert_t));
+ if (cert == NULL)
+ return grub_error (GRUB_ERR_OUT_OF_MEMORY, "out of memory");
+
+ rc = grub_x509_cert_parse (data, data_size, cert);
+ if (rc != GRUB_ERR_NONE)
+ {
+ grub_dprintf ("appendedsig", "cannot remove an invalid certificate from the db list\n");
+ grub_free (cert);
+ return rc;
+ }
+
+ /* Remove certificate from the db list. */
+ _remove_cert_from_db (cert);
+
+ return rc;
+}
+
static grub_err_t
file_read_whole (grub_file_t file, grub_uint8_t **buf, grub_size_t *len)
{
@@ -649,6 +766,7 @@ grub_verify_appended_signature (const grub_uint8_t *buf, grub_size_t bufsize)
if (err != GRUB_ERR_NONE)
return err;
+ append_sig_len = sig.signature_len;
datasize = bufsize - sig.signature_len;
/*
@@ -709,6 +827,189 @@ grub_verify_appended_signature (const grub_uint8_t *buf, grub_size_t bufsize)
return err;
}
+static grub_err_t
+grub_cmd_verify_signature (grub_command_t cmd __attribute__ ((unused)), int argc, char **args)
+{
+ grub_file_t signed_file;
+ grub_err_t err;
+ grub_uint8_t *signed_data = NULL;
+ grub_size_t signed_data_size = 0;
+
+ if (argc != 1)
+ return grub_error (GRUB_ERR_BAD_ARGUMENT,
+ "a signed file is expected\nExample:\n\tappend_verify <SIGNED FILE>\n");
+
+ if (!grub_strlen (args[0]))
+ return grub_error (GRUB_ERR_BAD_FILENAME, "missing signed file");
+
+ grub_dprintf ("appendedsig", "verifying %s\n", args[0]);
+
+ signed_file = grub_file_open (args[0], GRUB_FILE_TYPE_VERIFY_SIGNATURE);
+ if (signed_file == NULL)
+ return grub_error (GRUB_ERR_FILE_NOT_FOUND, "could not open %s file", args[0]);
+
+ err = file_read_whole (signed_file, &signed_data, &signed_data_size);
+ if (err == GRUB_ERR_NONE)
+ {
+ err = grub_verify_appended_signature (signed_data, signed_data_size);
+ grub_free (signed_data);
+ }
+
+ grub_file_close (signed_file);
+
+ return err;
+}
+
+/*
+ * Checks the trusted certificate against dbx list if dynamic key management is
+ * enabled. And add it to the db list if it is not already present.
+ *
+ * Note: When signature verification is enabled, this command only accepts the
+ * trusted certificate that is signed with an appended signature.
+ * The signature is verified by the appendedsig module. If verification succeeds,
+ * the certificate is added to the db list. Otherwise, an error is posted and
+ * the certificate is not added.
+ * When signature verification is disabled, it accepts the trusted certificate
+ * without an appended signature and add it to the db list.
+ *
+ * Also, note that the adding of the trusted certificate using this command does
+ * not persist across reboots.
+ */
+static grub_err_t
+grub_cmd_db_cert (grub_command_t cmd __attribute__ ((unused)), int argc, char **args)
+{
+ grub_err_t err;
+ grub_file_t cert_file;
+ grub_uint8_t *cert_data = NULL;
+ grub_size_t cert_data_size = 0;
+
+ if (argc != 1)
+ return grub_error (GRUB_ERR_BAD_ARGUMENT,
+ "a trusted X.509 certificate file is expected in DER format\n"
+ "Example:\n\tappend_add_db_cert <X509_CERTIFICATE>\n");
+
+ if (!grub_strlen (args[0]))
+ return grub_error (GRUB_ERR_BAD_FILENAME, "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_BAD_FILE_TYPE, "could not open %s file", args[0]);
+
+ err = file_read_whole (cert_file, &cert_data, &cert_data_size);
+ grub_file_close (cert_file);
+ if (err != GRUB_ERR_NONE)
+ return err;
+
+ /*
+ * If signature verification is enabled (check_sigs is set to true), obtain
+ * the actual certificate size by subtracting the appended signature size from
+ * the certificate size because the certificate has an appended signature, and
+ * this actual certificate size is used to get the X.509 certificate.
+ */
+ if (check_sigs == true)
+ cert_data_size -= append_sig_len;
+
+ err = add_certificate (cert_data, cert_data_size, &db);
+ grub_free (cert_data);
+
+ return err;
+}
+
+/*
+ * Remove the distrusted certificate from the db list if it is already present.
+ * And add it to the dbx list if not present when dynamic key management is
+ * enabled.
+ *
+ * Note: When signature verification is enabled, this command only accepts the
+ * distrusted certificate that is signed with an appended signature.
+ * The signature is verified by the appended sig module. If verification
+ * succeeds, the certificate is removed from the db list. Otherwise, an error
+ * is posted and the certificate is not removed.
+ * When signature verification is disabled, it accepts the distrusted certificate
+ * without an appended signature and removes it from the db list.
+ *
+ * Also, note that the removal of the distrusted certificate using this command
+ * does not persist across reboots.
+ */
+static grub_err_t
+grub_cmd_dbx_cert (grub_command_t cmd __attribute__ ((unused)), int argc, char **args)
+{
+ grub_err_t err;
+ grub_file_t cert_file;
+ grub_uint8_t *cert_data = NULL;
+ grub_size_t cert_data_size = 0;
+
+ if (argc != 1)
+ return grub_error (GRUB_ERR_BAD_ARGUMENT,
+ "a distrusted X.509 certificate file is expected in DER format\n"
+ "Example:\n\tappend_add_dbx_cert <X509_CERTIFICATE>\n");
+
+ if (!grub_strlen (args[0]))
+ return grub_error (GRUB_ERR_BAD_FILENAME, "missing distrusted 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_BAD_FILE_TYPE, "could not open %s file", args[0]);
+
+ err = file_read_whole (cert_file, &cert_data, &cert_data_size);
+ grub_file_close (cert_file);
+ if (err != GRUB_ERR_NONE)
+ return err;
+
+ /*
+ * If signature verification is enabled (check_sigs is set to true), obtain
+ * the actual certificate size by subtracting the appended signature size from
+ * the certificate size because the certificate has an appended signature, and
+ * this actual certificate size is used to get the X.509 certificate.
+ */
+ if (check_sigs == true)
+ cert_data_size -= append_sig_len;
+
+ /* Remove distrusted certificate from the db list if present. */
+ err = remove_cert_from_db (cert_data, cert_data_size);
+ if (err != GRUB_ERR_NONE)
+ {
+ grub_free (cert_data);
+ return err;
+ }
+
+ /* Only add the certificate to the dbx list if dynamic key management is enabled. */
+ if (append_key_mgmt == true)
+ err = add_certificate (cert_data, cert_data_size, &dbx);
+
+ grub_free (cert_data);
+
+ return err;
+}
+
+static grub_err_t
+grub_cmd_list_db (grub_command_t cmd __attribute__ ((unused)), int argc __attribute__ ((unused)),
+ char **args __attribute__ ((unused)))
+{
+ struct x509_certificate *cert;
+ grub_uint32_t i, cert_num = 1;
+
+ for (cert = db.certs; cert != NULL; cert = cert->next, cert_num++)
+ print_certificate (cert, cert_num);
+
+ if (append_key_mgmt == false)
+ return GRUB_ERR_NONE;
+
+ for (i = 0; i < db.hash_entries; i++)
+ {
+ if (db.hashes[i] != NULL)
+ {
+ grub_printf ("\nBinary hash: %u\n", i + 1);
+ grub_printf (" Hash: sha%" PRIuGRUB_SIZE "\n ", db.hash_sizes[i] * 8);
+ hexdump_colon (db.hashes[i], db.hash_sizes[i]);
+ }
+ }
+
+ return GRUB_ERR_NONE;
+}
+
/* Add the X.509 certificates/binary hash to the db list from PKS. */
static grub_err_t
load_pks2db (void)
@@ -1031,6 +1332,8 @@ struct grub_file_verifier grub_appendedsig_verifier = {
.write = appendedsig_write,
};
+static grub_command_t cmd_verify, cmd_list_db, cmd_dbx_cert, cmd_db_cert;
+
GRUB_MOD_INIT (appendedsig)
{
grub_int32_t rc;
@@ -1100,6 +1403,15 @@ GRUB_MOD_INIT (appendedsig)
db.cert_entries);
}
+ cmd_verify = grub_register_command ("append_verify", grub_cmd_verify_signature, N_("<SIGNED_FILE>"),
+ N_("Verify SIGNED_FILE against the trusted X.509 certificates in the db list"));
+ cmd_list_db = grub_register_command ("append_list_db", grub_cmd_list_db, 0,
+ N_("Show the list of trusted X.509 certificates from the db list"));
+ cmd_db_cert = grub_register_command ("append_add_db_cert", grub_cmd_db_cert, N_("<X509_CERTIFICATE>"),
+ N_("Add trusted X509_CERTIFICATE to the db list"));
+ cmd_dbx_cert = grub_register_command ("append_add_dbx_cert", grub_cmd_dbx_cert, N_("<X509_CERTIFICATE>"),
+ N_("Add distrusted X509_CERTIFICATE to the dbx list"));
+
grub_verifier_register (&grub_appendedsig_verifier);
grub_dl_set_persistent (mod);
}
@@ -1118,4 +1430,8 @@ GRUB_MOD_FINI (appendedsig)
grub_register_variable_hook ("appendedsig_key_mgmt", NULL, NULL);
grub_env_unset ("appendedsig_key_mgmt");
grub_verifier_unregister (&grub_appendedsig_verifier);
+ grub_unregister_command (cmd_verify);
+ grub_unregister_command (cmd_list_db);
+ grub_unregister_command (cmd_db_cert);
+ grub_unregister_command (cmd_dbx_cert);
}

View File

@ -0,0 +1,382 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Sudhakar Kuppusamy <sudhakar@linux.ibm.com>
Date: Mon, 6 Oct 2025 12:55:01 +0530
Subject: [PATCH] appended signatures: GRUB commands to manage the hashes
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Introducing the following GRUB commands to manage certificate/binary
hashes.
1. append_list_dbx:
Show the list of distrusted certificates and binary/certificate
hashes from the dbx list.
2. append_add_db_hash:
Add the trusted binary hash to the db list.
3. append_add_dbx_hash:
Add the distrusted certificate/binary hash to the dbx list.
Note that if signature verification (check_appended_signatures) is set to yes,
the append_add_db_hash and append_add_dbx_hash commands only accept the file
hash_file that is signed with an appended signature.
Signed-off-by: Sudhakar Kuppusamy <sudhakar@linux.ibm.com>
Tested-by: Sridhar Markonda <sridharm@linux.ibm.com>
Reviewed-by: Avnish Chouhan <avnish@linux.ibm.com>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
---
grub-core/commands/appendedsig/appendedsig.c | 279 +++++++++++++++++++++++++++
include/grub/file.h | 2 +
2 files changed, 281 insertions(+)
diff --git a/grub-core/commands/appendedsig/appendedsig.c b/grub-core/commands/appendedsig/appendedsig.c
index 614ebee..5c53f63 100644
--- a/grub-core/commands/appendedsig/appendedsig.c
+++ b/grub-core/commands/appendedsig/appendedsig.c
@@ -52,6 +52,9 @@ GRUB_MOD_LICENSE ("GPLv3+");
#define SHA384_HASH_SIZE 48
#define SHA512_HASH_SIZE 64
+#define OPTION_BINARY_HASH 0
+#define OPTION_CERT_HASH 1
+
/*
* This structure is extracted from scripts/sign-file.c in the linux kernel
* source. It was licensed as LGPLv2.1+, which is GPLv3+ compatible.
@@ -126,6 +129,13 @@ static grub_pks_t *pks_keystore;
/* Appended signature size. */
static grub_size_t append_sig_len = 0;
+static const struct grub_arg_option options[] =
+{
+ {"binary-hash", 'b', 0, N_("hash file of the binary."), 0, ARG_TYPE_PATHNAME},
+ {"cert-hash", 'c', 1, N_("hash file of the certificate."), 0, ARG_TYPE_PATHNAME},
+ {0, 0, 0, 0, 0, 0}
+};
+
static grub_ssize_t
pseudo_read (struct grub_file *file, char *buf, grub_size_t len)
{
@@ -546,6 +556,69 @@ remove_cert_from_db (const grub_uint8_t *data, const grub_size_t data_size)
return rc;
}
+static bool
+cert_fingerprint_match (const grub_uint8_t *hash_data, const grub_size_t hash_data_size,
+ const grub_x509_cert_t *cert)
+{
+ grub_int32_t type;
+
+ if (hash_data_size == SHA256_HASH_SIZE)
+ type = GRUB_FINGERPRINT_SHA256;
+ else if (hash_data_size == SHA384_HASH_SIZE)
+ type = GRUB_FINGERPRINT_SHA384;
+ else if (hash_data_size == SHA512_HASH_SIZE)
+ type = GRUB_FINGERPRINT_SHA512;
+ else
+ {
+ grub_dprintf ("appendedsig", "unsupported fingerprint hash type "
+ "(%" PRIuGRUB_SIZE ") \n", hash_data_size);
+ return false;
+ }
+
+ if (grub_memcmp (cert->fingerprint[type], hash_data, hash_data_size) == 0)
+ return true;
+
+ return false;
+}
+
+static void
+remove_hash_from_db (const grub_uint8_t *hash_data, const grub_size_t hash_data_size,
+ const bool bin_hash)
+{
+ grub_uint32_t i;
+ grub_x509_cert_t *cert;
+
+ if (bin_hash == true)
+ {
+ for (i = 0; i < db.hash_entries; i++)
+ {
+ if (db.hashes[i] == NULL)
+ continue;
+
+ if (grub_memcmp (db.hashes[i], hash_data, hash_data_size) == 0)
+ {
+ grub_dprintf ("appendedsig", "removed distrusted hash %02x%02x%02x%02x.. from the db list\n",
+ db.hashes[i][0], db.hashes[i][1], db.hashes[i][2], db.hashes[i][3]);
+ grub_free (db.hashes[i]);
+ db.hashes[i] = NULL;
+ db.hash_sizes[i] = 0;
+ break;
+ }
+ }
+ }
+ else
+ {
+ for (cert = db.certs; cert != NULL; cert = cert->next)
+ {
+ if (cert_fingerprint_match (hash_data, hash_data_size, cert) == true)
+ {
+ _remove_cert_from_db (cert);
+ break;
+ }
+ }
+ }
+}
+
static grub_err_t
file_read_whole (grub_file_t file, grub_uint8_t **buf, grub_size_t *len)
{
@@ -1010,6 +1083,192 @@ grub_cmd_list_db (grub_command_t cmd __attribute__ ((unused)), int argc __attrib
return GRUB_ERR_NONE;
}
+static grub_err_t
+grub_cmd_list_dbx (grub_command_t cmd __attribute__((unused)),
+ int argc __attribute__((unused)), char **args __attribute__((unused)))
+{
+ struct x509_certificate *cert;
+ grub_uint32_t i, cert_num = 1;
+
+ if (append_key_mgmt == false)
+ return grub_error (GRUB_ERR_ACCESS_DENIED,
+ "append_list_dbx command is unsupported in static key mode");
+
+ for (cert = dbx.certs; cert != NULL; cert = cert->next, cert_num++)
+ print_certificate (cert, cert_num);
+
+ for (i = 0; i < dbx.hash_entries; i++)
+ {
+ if (dbx.hashes[i] != NULL)
+ {
+ grub_printf ("\nCertificate/Binary hash: %u\n", i + 1);
+ grub_printf (" Hash: sha%" PRIuGRUB_SIZE "\n ", dbx.hash_sizes[i] * 8);
+ hexdump_colon (dbx.hashes[i], dbx.hash_sizes[i]);
+ }
+ }
+
+ return GRUB_ERR_NONE;
+}
+
+/*
+ * Remove the trusted binary hash from the dbx list if present. And add them to
+ * the db list if it is not already present.
+ *
+ * Note: When signature verification is enabled, this command only accepts the
+ * binary hash file that is signed with an appended signature. The signature is
+ * verified by the appendedsig module. If verification succeeds, the binary hash
+ * is added to the db list. Otherwise, an error is posted and the binary hash is
+ * not added.
+ * When signature verification is disabled, it accepts the binary hash file
+ * without an appended signature and adds it to the db list.
+ *
+ * Also, note that the adding of the trusted binary hash using this command does
+ * not persist across reboots.
+ */
+static grub_err_t
+grub_cmd_add_db_hash (grub_command_t cmd __attribute__((unused)), int argc, char**args)
+{
+ grub_err_t rc;
+ grub_file_t hash_file;
+ grub_uint8_t *hash_data = NULL;
+ grub_size_t hash_data_size = 0;
+
+ if (append_key_mgmt == false)
+ return grub_error (GRUB_ERR_ACCESS_DENIED,
+ "append_add_db_hash command is unsupported in static key mode");
+
+ if (argc != 1)
+ return grub_error (GRUB_ERR_BAD_ARGUMENT,
+ "a trusted binary hash file is expected in binary format\n"
+ "Example:\n\tappend_add_db_hash <BINARY HASH FILE>\n");
+
+ if (!grub_strlen (args[0]))
+ return grub_error (GRUB_ERR_BAD_FILENAME, "missing trusted binary hash file");
+
+ hash_file = grub_file_open (args[0], GRUB_FILE_TYPE_HASH_TRUST | GRUB_FILE_TYPE_NO_DECOMPRESS);
+ if (hash_file == NULL)
+ return grub_error (GRUB_ERR_FILE_NOT_FOUND, "unable to open %s file", args[0]);
+
+ rc = file_read_whole (hash_file, &hash_data, &hash_data_size);
+ grub_file_close (hash_file);
+ if (rc != GRUB_ERR_NONE)
+ return rc;
+
+ /*
+ * If signature verification is enabled (check_sigs is set to true), obtain
+ * the actual hash data size by subtracting the appended signature size from
+ * the hash data size because the hash has an appended signature, and this
+ * actual hash data size is used to get the hash data.
+ */
+ if (check_sigs == true)
+ hash_data_size -= append_sig_len;
+
+ grub_dprintf ("appendedsig",
+ "adding a trusted binary hash %02x%02x%02x%02x... with size of %" PRIuGRUB_SIZE "\n",
+ hash_data[0], hash_data[1], hash_data[2], hash_data[3], hash_data_size);
+
+ /* Only accept SHA256, SHA384 and SHA512 binary hash */
+ if (hash_data_size != SHA256_HASH_SIZE && hash_data_size != SHA384_HASH_SIZE &&
+ hash_data_size != SHA512_HASH_SIZE)
+ {
+ grub_free (hash_data);
+ return grub_error (GRUB_ERR_BAD_SIGNATURE, "unacceptable trusted binary hash type");
+ }
+
+ rc = add_hash (hash_data, hash_data_size, &db);
+ grub_free (hash_data);
+
+ return rc;
+}
+
+/*
+ * Remove the distrusted binary/certificate hash from the db list if present.
+ * And add them to the dbx list if it is not already present.
+ *
+ * Note: When signature verification is enabled, this command only accepts the
+ * binary/certificate hash file that is signed with an appended signature. The
+ * signature is verified by the appendedsig module. If verification succeeds,
+ * the binary/certificate hash is added to the dbx list. Otherwise, an error is
+ * posted and the binary/certificate hash is not added.
+ * When signature verification is disabled, it accepts the binary/certificate
+ * hash file without an appended signature and adds it to the dbx list.
+ *
+ * Also, note that the adding of the distrusted binary/certificate hash using
+ * this command does not persist across reboots.
+ */
+static grub_err_t
+grub_cmd_add_dbx_hash (grub_extcmd_context_t ctxt, int argc __attribute__ ((unused)),
+ char **args __attribute__ ((unused)))
+{
+ grub_err_t rc;
+ grub_file_t hash_file;
+ grub_uint8_t *hash_data = NULL;
+ grub_size_t hash_data_size = 0;
+ char *file_path;
+
+ if (append_key_mgmt == false)
+ return grub_error (GRUB_ERR_ACCESS_DENIED,
+ "append_add_dbx_hash command is unsupported in static key mode");
+
+ if (!ctxt->state[OPTION_BINARY_HASH].set && !ctxt->state[OPTION_CERT_HASH].set)
+ return grub_error (GRUB_ERR_BAD_ARGUMENT,
+ "a distrusted certificate/binary hash file is expected in binary format\n"
+ "Example:\n\tappend_add_dbx_hash [option] <FILE>\n"
+ "option:\n[-b|--binary-hash] FILE [BINARY HASH FILE]\n"
+ "[-c|--cert-hash] FILE [CERTFICATE HASH FILE]\n");
+
+ if (ctxt->state[OPTION_BINARY_HASH].arg == NULL && ctxt->state[OPTION_CERT_HASH].arg == NULL)
+ return grub_error (GRUB_ERR_BAD_FILENAME, "missing distrusted certificate/binary hash file");
+
+ if (ctxt->state[OPTION_BINARY_HASH].arg != NULL)
+ file_path = ctxt->state[OPTION_BINARY_HASH].arg;
+ else
+ file_path = ctxt->state[OPTION_CERT_HASH].arg;
+
+ hash_file = grub_file_open (file_path, GRUB_FILE_TYPE_HASH_TRUST | GRUB_FILE_TYPE_NO_DECOMPRESS);
+ if (hash_file == NULL)
+ return grub_error (GRUB_ERR_FILE_NOT_FOUND, "unable to open %s file", file_path);
+
+ rc = file_read_whole (hash_file, &hash_data, &hash_data_size);
+ grub_file_close (hash_file);
+ if (rc != GRUB_ERR_NONE)
+ return rc;
+
+ /*
+ * If signature verification is enabled (check_sigs is set to true), obtain
+ * the actual hash data size by subtracting the appended signature size from
+ * the hash data size because the hash has an appended signature, and this
+ * actual hash data size is used to get the hash data.
+ */
+ if (check_sigs == true)
+ hash_data_size -= append_sig_len;
+
+ grub_dprintf ("appendedsig",
+ "adding a distrusted certificate/binary hash %02x%02x%02x%02x..."
+ " with size of %" PRIuGRUB_SIZE "\n", hash_data[0], hash_data[1],
+ hash_data[2], hash_data[3], hash_data_size);
+
+ if (ctxt->state[OPTION_BINARY_HASH].set || ctxt->state[OPTION_CERT_HASH].set)
+ {
+ /* Only accept SHA256, SHA384 and SHA512 certificate/binary hash */
+ if (hash_data_size != SHA256_HASH_SIZE && hash_data_size != SHA384_HASH_SIZE &&
+ hash_data_size != SHA512_HASH_SIZE)
+ {
+ grub_free (hash_data);
+ return grub_error (GRUB_ERR_BAD_SIGNATURE,
+ "unacceptable distrusted certificate/binary hash type");
+ }
+ }
+
+ /* Remove distrusted binary hash/certificate from the db list if present. */
+ remove_hash_from_db (hash_data, hash_data_size,
+ (ctxt->state[OPTION_BINARY_HASH].set) ? true : false);
+ rc = add_hash (hash_data, hash_data_size, &dbx);
+ grub_free (hash_data);
+
+ return rc;
+}
+
/* Add the X.509 certificates/binary hash to the db list from PKS. */
static grub_err_t
load_pks2db (void)
@@ -1292,6 +1551,11 @@ appendedsig_init (grub_file_t io __attribute__ ((unused)), enum grub_file_type t
* verifier, but we lack the hubris required to take this on. Instead,
* require that it have an appended signature.
*/
+ case GRUB_FILE_TYPE_HASH_TRUST:
+ /*
+ * This is a certificate/binary hash to add to db/dbx. This needs to be
+ * verified or blocked.
+ */
case GRUB_FILE_TYPE_LINUX_KERNEL:
case GRUB_FILE_TYPE_GRUB_MODULE:
/*
@@ -1333,6 +1597,8 @@ struct grub_file_verifier grub_appendedsig_verifier = {
};
static grub_command_t cmd_verify, cmd_list_db, cmd_dbx_cert, cmd_db_cert;
+static grub_command_t cmd_list_dbx, cmd_db_hash;
+static grub_extcmd_t cmd_dbx_hash;
GRUB_MOD_INIT (appendedsig)
{
@@ -1412,6 +1678,16 @@ GRUB_MOD_INIT (appendedsig)
cmd_dbx_cert = grub_register_command ("append_add_dbx_cert", grub_cmd_dbx_cert, N_("<X509_CERTIFICATE>"),
N_("Add distrusted X509_CERTIFICATE to the dbx list"));
+ cmd_list_dbx = grub_register_command ("append_list_dbx", grub_cmd_list_dbx, 0,
+ N_("Show the list of distrusted certificates and"
+ " certificate/binary hashes from the dbx list"));
+ cmd_db_hash = grub_register_command ("append_add_db_hash", grub_cmd_add_db_hash, N_("BINARY HASH FILE"),
+ N_("Add trusted BINARY HASH to the db list."));
+ cmd_dbx_hash = grub_register_extcmd ("append_add_dbx_hash", grub_cmd_add_dbx_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 the dbx list."), options);
+
grub_verifier_register (&grub_appendedsig_verifier);
grub_dl_set_persistent (mod);
}
@@ -1434,4 +1710,7 @@ GRUB_MOD_FINI (appendedsig)
grub_unregister_command (cmd_list_db);
grub_unregister_command (cmd_db_cert);
grub_unregister_command (cmd_dbx_cert);
+ grub_unregister_command (cmd_list_dbx);
+ grub_unregister_command (cmd_db_hash);
+ grub_unregister_extcmd (cmd_dbx_hash);
}
diff --git a/include/grub/file.h b/include/grub/file.h
index d678de0..16a4b7d 100644
--- a/include/grub/file.h
+++ b/include/grub/file.h
@@ -115,6 +115,8 @@ enum grub_file_type
GRUB_FILE_TYPE_HASHLIST,
/* File hashed by hashsum. */
GRUB_FILE_TYPE_TO_HASH,
+ /* File holding certificiate/binary hash to add to db/dbx. */
+ GRUB_FILE_TYPE_HASH_TRUST,
/* Keyboard layout. */
GRUB_FILE_TYPE_KEYBOARD_LAYOUT,
/* Picture file. */

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,44 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Daniel Axtens <dja@axtens.net>
Date: Mon, 6 Oct 2025 12:55:03 +0530
Subject: [PATCH] docs/grub: Document signing GRUB under UEFI
Before adding information about how GRUB is signed with an appended
signature scheme, it's worth adding some information about how it
can currently be signed for UEFI.
Signed-off-by: Daniel Axtens <dja@axtens.net>
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>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
---
docs/grub.texi | 15 +++++++++++++++
1 file changed, 15 insertions(+)
diff --git a/docs/grub.texi b/docs/grub.texi
index 2d6d73a..e08aaf5 100644
--- a/docs/grub.texi
+++ b/docs/grub.texi
@@ -6912,6 +6912,21 @@ which increases the risk of password leakage during the process. Moreover, the
superuser list must be well maintained, and the password used cannot be
synchronized with LUKS key rotation.
+@node Signing GRUB itself
+@section Signing GRUB itself
+To ensure a complete secure-boot chain, there must be a way for the code that
+loads GRUB to verify the integrity of the core image.
+This is ultimately platform-specific and individual platforms can define their
+own mechanisms. However, there are general-purpose mechanisms that can be used
+with GRUB.
+@section Signing GRUB for UEFI secure boot
+On UEFI platforms, @file{core.img} is a PE binary. Therefore, it can be signed
+with a tool such as @command{pesign} or @command{sbsign}. Refer to the
+suggestions in @pxref{UEFI secure boot and shim} to ensure that the final
+image works under UEFI secure boot and can maintain the secure-boot chain. It
+will also be necessary to enroll the public key used into a relevant firmware
+key database.
+
@node Platform limitations
@chapter Platform limitations

View File

@ -0,0 +1,124 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Sudhakar Kuppusamy <sudhakar@linux.ibm.com>
Date: Mon, 6 Oct 2025 12:55:04 +0530
Subject: [PATCH] docs/grub: Document signing GRUB with an appended signature
Signing GRUB for firmware that verifies an appended signature is a
bit fiddly. I don't want people to have to figure it out from scratch
so document it here.
Signed-off-by: Daniel Axtens <dja@axtens.net>
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>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
---
docs/grub.texi | 95 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 95 insertions(+)
diff --git a/docs/grub.texi b/docs/grub.texi
index e08aaf5..0b1c9d1 100644
--- a/docs/grub.texi
+++ b/docs/grub.texi
@@ -6927,6 +6927,101 @@ image works under UEFI secure boot and can maintain the secure-boot chain. It
will also be necessary to enroll the public key used into a relevant firmware
key database.
+@section Signing GRUB with an appended signature
+The @file{core.elf} itself can be signed with a Linux kernel module-style
+appended signature (@pxref{Using appended signatures}).
+To support IEEE1275 platforms where the boot image is often loaded directly
+from a disk partition rather than from a file system, the @file{core.elf}
+can specify the size and location of the appended signature with an ELF
+Note added by @command{grub-install} or @command{grub-mkimage}.
+An image can be signed this way using the @command{sign-file} command from
+the Linux kernel:
+
+@itemize
+@item Signing a GRUB image using a single signer key. The grub.key is your
+private key used for GRUB signing, grub.der is a corresponding public key
+(certificate) used for GRUB signature verification, and the kernel.der is
+your public key (certificate) used for kernel signature verification.
+@example
+@group
+# Determine the size of the appended signature. It depends on the
+# signing key and the hash algorithm.
+#
+# Signing /dev/null with an appended signature.
+
+sign-file SHA256 grub.key grub.der /dev/null ./empty.sig
+
+# Build a GRUB image for the signature.
+
+grub-mkimage -O powerpc-ieee1275 -o core.elf.unsigned -x kernel.der \
+ -p /grub --appended-signature-size $(stat -c '%s' ./empty.sig) \
+ --modules="appendedsig ..." ...
+
+# Remove the signature file.
+
+rm ./empty.sig
+
+# Signing a GRUB image with an appended signature.
+
+sign-file SHA256 grub.key grub.der core.elf.unsigned core.elf.signed
+
+@end group
+@end example
+@item Signing a GRUB image using more than one signer key. The grub1.key and
+grub2.key are private keys used for GRUB signing, grub1.der and grub2.der
+are corresponding public keys (certificates) used for GRUB signature verification.
+The kernel1.der and kernel2.der are your public keys (certificates) used for
+kernel signature verification.
+@example
+@group
+# Generate a signature by signing /dev/null.
+
+openssl cms -sign -binary -nocerts -in /dev/null -signer \
+ grub1.der -inkey grub1.key -signer grub2.der -inkey grub2.key \
+ -out ./empty.p7s -outform DER -noattr -md sha256
+
+# To be able to determine the size of an appended signature, sign an
+# empty file (/dev/null) to which a signature will be appended to.
+
+sign-file -s ./empty.p7s sha256 /dev/null /dev/null ./empty.sig
+
+# Build a GRUB image for the signature.
+
+grub-mkimage -O powerpc-ieee1275 -o core.elf.unsigned -x kernel1.der \
+ kernel2.der -p /grub --appended-signature-size $(stat -c '%s' ./empty.sig) \
+ --modules="appendedsig ..." ...
+
+# Remove the signature files.
+
+rm ./empty.sig ./empty.p7s
+
+# Generate a raw signature for GRUB image signing using OpenSSL.
+
+openssl cms -sign -binary -nocerts -in core.elf.unsigned -signer \
+ grub1.der -inkey grub1.key -signer grub2.der -inkey grub2.key \
+ -out core.p7s -outform DER -noattr -md sha256
+
+# Sign a GRUB image to get an image file with an appended signature.
+
+sign-file -s core.p7s sha256 /dev/null core.elf.unsigned core.elf.signed
+
+@end group
+@end example
+@item Don't forget to install the signed image as required
+(e.g. on powerpc-ieee1275, to the PReP partition).
+@example
+@group
+# Install signed GRUB image to the PReP partition on powerpc-ieee1275
+
+dd if=core.elf.signed of=/dev/sda1
+
+@end group
+@end example
+@end itemize
+
+As with UEFI secure boot, it is necessary to build-in the required modules,
+or sign them if they are not part of the GRUB image.
+
@node Platform limitations
@chapter Platform limitations

View File

@ -0,0 +1,465 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Sudhakar Kuppusamy <sudhakar@linux.ibm.com>
Date: Mon, 6 Oct 2025 12:55:05 +0530
Subject: [PATCH] docs/grub: Document appended signature
This explains how appended signatures can be used to form part of
a secure boot chain, and documents the commands and variables
introduced.
Signed-off-by: Daniel Axtens <dja@axtens.net>
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>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
---
docs/grub.texi | 355 +++++++++++++++++++++++++++++++++++++++++++++++----------
1 file changed, 293 insertions(+), 62 deletions(-)
diff --git a/docs/grub.texi b/docs/grub.texi
index 0b1c9d1..e4f36df 100644
--- a/docs/grub.texi
+++ b/docs/grub.texi
@@ -3274,6 +3274,7 @@ GRUB. Others may be used freely in GRUB configuration files.
These variables have special meaning to GRUB.
@menu
+* appendedsig_key_mgmt::
* biosnum::
* check_appended_signatures::
* check_signatures::
@@ -3327,6 +3328,19 @@ These variables have special meaning to GRUB.
@end menu
+@node appendedsig_key_mgmt
+@subsection appendedsig_key_mgmt
+
+This variable controls whether GRUB enforces appended signature validation
+using either @code{static} or @code{dynamic} key management. It is automatically
+set by GRUB to either @code{static} or @code{dynamic} based on the
+@strong{'ibm,secure-boot'} device tree property and Platform KeyStore (PKS).
+Also, it can be explicitly set to either @code{static} or @code{dynamic} by
+setting the @code{appendedsig_key_mgmt} variable from the GRUB console
+when the GRUB is not locked down.
+
+@xref{Using appended signatures} for more information.
+
@node biosnum
@subsection biosnum
@@ -3339,13 +3353,17 @@ this.
For an alternative approach which also changes BIOS drive mappings for the
chain-loaded system, @pxref{drivemap}.
-
@node check_appended_signatures
@subsection check_appended_signatures
This variable controls whether GRUB enforces appended signature validation on
-certain loaded files. @xref{Using appended signatures}.
+loaded kernel and GRUB module files. It is automatically set by GRUB
+to either @code{no} or @code{yes} based on the @strong{'ibm,secure-boot'} device
+tree property. Also, it can be explicitly set to either @code{no} or @code{yes} by
+setting the @code{check_appended_signatures} variable from the GRUB console
+when the GRUB is not locked down.
+@xref{Using appended signatures} for more information.
@node check_signatures
@subsection check_signatures
@@ -4350,6 +4368,13 @@ you forget a command, you can run the command @command{help}
@menu
* [:: Check file types and compare values
* acpi:: Load ACPI tables
+* append_add_db_cert:: Add trusted certificate to the db list
+* append_add_db_hash:: Add trusted certificate/binary hash to the db list
+* append_add_dbx_cert:: Add distrusted certificate to the dbx list
+* append_add_dbx_hash:: Add distrusted certificate/binary hash to the dbx list
+* append_list_db:: List all trusted certificates from the db list
+* append_list_dbx:: List all distrusted certificates and binary/certificate hashes from the dbx list
+* append_verify:: Verify appended digital signature using db and dbx lists
* authenticate:: Check whether user is in user list
* background_color:: Set background color for active terminal
* background_image:: Load background image for active terminal
@@ -4469,6 +4494,140 @@ Note: The command is not allowed when lockdown is enforced (@pxref{Lockdown}).
unsigned code.
@end deffn
+@node append_add_db_cert
+@subsection append_add_db_cert
+
+@deffn Command append_add_db_cert <X509_certificate>
+Read an X.509 certificate from the file @var{X509_certificate}
+and add it to GRUB's internal db list of trusted certificates.
+These certificates are used to validate appended signatures when the
+environment variable @code{check_appended_signatures} (@pxref{check_appended_signatures})
+is set to @code{yes} or the @command{append_verify} (@pxref{append_verify})
+command is executed from the GRUB console.
+
+@xref{Using appended signatures} for more information.
+@end deffn
+
+@node append_add_db_hash
+@subsection append_add_db_hash
+
+@deffn Command append_add_db_hash <hash_file>
+Read a binary hash from the file @var{hash_file}
+and add it to GRUB's internal db list of trusted binary hashes. These
+hashes are used to validate the Linux kernel/GRUB module binary hashes when the
+environment variable @code{check_appended_signatures}
+(@pxref{check_appended_signatures}) is set to @code{yes} or the
+@command{append_verify} (@pxref{append_verify}) command is executed
+from the GRUB console.
+
+Here is an example for how to generate a SHA-256 hash for a file. The hash
+will be in binary format:
+
+@example
+
+# The vmlinux (kernel image) file is your binary file, and
+# it should be unsigned.
+#
+# Generate the binary_hash.bin file from the vmlinux file
+# using OpenSSL command
+
+openssl dgst -binary -sha256 -out binary_hash.bin vmlinux
+
+@end example
+
+@xref{Using appended signatures} for more information.
+@end deffn
+
+@node append_add_dbx_cert
+@subsection append_add_dbx_cert
+
+@deffn Command append_add_dbx_cert <X509_certificate>
+Read an X.509 certificate from the file @var{X509_certificate}
+and add it to GRUB's internal dbx list of distrusted certificates.
+These certificates are used to ensure that the distrusted certificates
+are rejected during appended signatures validation when the environment
+variable @code{check_appended_signatures} is set to @code{yes}
+(@pxref{check_appended_signatures}) or the @command{append_verify}
+(@pxref{append_verify}) command is executed from the GRUB console.
+Also, these certificates are used to prevent distrusted certificates from
+being added to the db list later on.
+
+@xref{Using appended signatures} for more information.
+@end deffn
+
+@node append_add_dbx_hash
+@subsection append_add_dbx_hash
+
+@deffn Command append_add_dbx_hash [@option{-b}|@option{-c}] <hash_file>
+Read a binary/certificate hash from the file @var{hash_file}
+and add it to GRUB's internal dbx list of distrusted binary/certificate hashes.
+When the environment variable @code{check_appended_signatures} (@pxref{check_appended_signatures})
+is set to @code{yes} or the @command{append_verify} (@pxref{append_verify}) command
+is executed from the GRUB console, then matching distrusted binary hashes or the signature
+validation with distrusted certificates may lead to the rejection of the Linux kernel or GRUB modules.
+Also, these hashes are used to prevent distrusted certificates and binary hashes from being
+added to the db list later on.
+
+The @option{-b} (@option{--binary-hash}) can be used to specify a binary hash file and
+@option{-c} (@option{--cert-hash}) can be used to specify a certificate hash file.
+
+Here is an example for how to generate a SHA-256 hash for a binary and a
+certificate file. The hash will be in binary format:
+
+@example
+
+# The vmlinux (kernel image) file is your binary file, and
+# it should be unsigned. The kernel.der is your certificate file.
+#
+# Generate the cert_hash.bin file from the kernel.der file
+
+openssl dgst -binary -sha256 -out cert_hash.bin kernel.der
+
+# Generate the binary_hash.bin file from the vmlinux file
+
+openssl dgst -binary -sha256 -out binary_hash.bin vmlinux
+
+@end example
+
+@xref{Using appended signatures} for more information.
+@end deffn
+
+@node append_list_db
+@subsection append_list_db
+
+@deffn Command append_list_db
+List all X.509 certificates and binary hashes trusted by GRUB for validating
+appended signatures. The output is a numbered list of certificates and binary hashes,
+showing the certificate's version, serial number, issuer, subject,
+public key algorithm, RSA public key size, and certificate fingerprint.
+
+@xref{Using appended signatures} for more information.
+@end deffn
+
+@node append_list_dbx
+@subsection append_list_dbx
+
+@deffn Command append_list_dbx
+List all the distrusted X.509 certificates and binary/certificate hashes.
+The output is a numbered list of certificates and binary/certificate hashes,
+showing the certificate's version, serial number, issuer, subject,
+public key algorithm, RSA public key size, and certificate fingerprint.
+
+@xref{Using appended signatures} for more information.
+@end deffn
+
+@node append_verify
+@subsection append_verify
+
+@deffn Command append_verify <signed_file>
+Verifies an appended signature on @var{signed_file} against the trusted X.509 certificates
+and hashes known to GRUB (@pxref{append_list_db},@pxref{append_list_dbx}, @pxref{append_add_db_cert},
+@pxref{append_add_db_hash}, @pxref{append_add_dbx_hash} and @pxref{append_add_dbx_cert}).
+Exit code @code{$?} is set to 0 if the signature validates successfully.
+If validation fails, it is set to a non-zero value.
+
+@xref{Using appended signatures} for more information.
+@end deffn
@node authenticate
@subsection authenticate
@@ -5139,10 +5298,12 @@ configurations, and to enable ``one-shot'' boot attempts and
``savedefault'' behavior. @xref{Using GPG-style digital signatures}, for more
information.
-Extra care should be taken when combining this command with appended signatures
-(@pxref{Using appended signatures}), as this file is not validated by an
-appended signature and could set @code{check_appended_signatures=no} if GRUB is
-not in @pxref{Lockdown} mode.
+If the environment variable @code{check_appended_signatures} value is set to
+@code{yes} and GRUB is in lockeddown mode, the user is not allowed to set
+@code{check_appended_signatures} to @code{no} and @code{appendedsig_key_mgmt}
+to @code{static} or @code{dynamic} either directly using @command{load_env}
+command or via environment block file. @xref{Using appended signatures}, for
+more information.
@end deffn
@@ -6488,6 +6649,7 @@ environment variables and commands are listed in the same order.
* Secure Boot Advanced Targeting:: Embedded information for generation number based revocation
* Measured Boot:: Measuring boot components
* Lockdown:: Lockdown when booting on a secure setup
+* Signing certificate and hash files:: Certificate and hash file signing
* Signing GRUB itself:: Ensuring the integrity of the GRUB core image
@end menu
@@ -6661,8 +6823,8 @@ secure boot chain.
@node Using appended signatures
@section Using appended signatures in GRUB
-GRUB supports verifying Linux-style 'appended signatures' for secure boot.
-Appended signatures are PKCS#7 messages containing a signature over the
+GRUB supports verifying Linux-style 'appended signatures' for Linux on Power LPAR
+secure boot. Appended signatures are PKCS#7 messages containing a signature over the
contents of a file, plus some metadata, appended to the end of a file. A file
with an appended signature ends with the magic string:
@@ -6670,73 +6832,114 @@ with an appended signature ends with the magic string:
~Module signature appended~\n
@end example
-where @code{\n} represents the line-feed character, @code{0x0a}.
+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}.
+Linux on Power LPAR secure boot is controlled by @strong{'ibm,secure-boot'}
+device tree property and if this property is set to @code{2} (@samp{enforce}),
+GRUB enters lockdown mode. There are three secure boot modes. They are
-A file can be explictly verified using the @pxref{verify_appended} command.
+@itemize
+@item @samp{0 - disabled}: Secure boot is disabled. This is the default.
+@item @samp{1 - audit}: Enforce signature verification by setting
+ @code{check_appended_signatures} (@pxref{check_appended_signatures}) to
+ @code{yes} and do not enter lockdown mode. Signature verification
+ is performed and if signature verification fails, display the errors and
+ allow the boot to continue.
+@item @samp{2 - enforce}: Enter lockdown mode and enforce signature verification by setting
+ @code{check_appended_signatures} (@pxref{check_appended_signatures}) to @code{yes}.
+@end itemize
-Only signatures made with the SHA-256 or SHA-512 hash algorithm are supported,
-and only RSA signatures are supported.
+Note that Linux on Power LPAR only supports @samp{0 - disabled} and @samp{2 - enforce},
+and @samp{1 - audit} is considered as secure boot being disabled.
+
+Enforcement of signature verification is controlled by the environment variable
+@code{check_appended_signatures} (@pxref{check_appended_signatures}).
+
+@itemize
+@item @samp{no}: No verification is performed. This is the default.
+@item @samp{yes}: Signature verification is performed and if signature verification fails,
+ display the errors and stop the boot. Signature verification cannot be disabled by setting
+ the @code{check_appended_signatures} variable back to @samp{no}.
+@end itemize
+
+To enable appended signature verification, load the appendedsig module and an
+X.509 certificate for verification. It is recommended to build the appendedsig module
+into the core GRUB image.
+
+Key management is controlled by the environment variable @code{appendedsig_key_mgmt}
+(@pxref{appendedsig_key_mgmt}).
+
+@itemize
+@item @samp{static}: Enforce static key management signature verification. This is the default.
+ When GRUB is in lockdown mode, then the user cannot change the value of the
+ @code{appendedsig_key_mgmt}.
+@item @samp{dynamic}: Enforce dynamic key management signature verification. When GRUB is in
+ lockdown mode, then the user cannot change the value of the @code{appendedsig_key_mgmt}.
+@end itemize
+
+In static key management mode, certificates will be built into the core image using
+the @code{--x509} parameter to @command{grub-mkimage}. The list of trusted certificates
+available at boot time can be shown using @command{append_list_db} (@pxref{append_list_db}).
+Distrusted certificates can be explicitly removed from the db using @command{append_add_dbx_cert}
+(@pxref{append_add_dbx_cert}). Also, trusted certificates can be explicitly added to the db using
+@command{append_add_db_cert} (@pxref{append_add_db_cert}).
+
+In dynamic key management mode, db and dbx are read from the Platform KeyStore (PKS). If
+db does not exist in PKS, static keys (built-in keys) are used as the default keys.
+The list of trusted certificates and binary hashes available at boot time can be shown using
+@command{append_list_db} (@pxref{append_list_db}) and the list of distrusted certificates and
+binary/certificate hashes available at boot time can be shown using @command{append_list_dbx}
+(@pxref{append_list_dbx}). The trusted certificates and binary hashes can be explicitly added
+to the db using @command{append_add_db_cert} (@pxref{append_add_db_cert}) and
+@command{append_add_db_hash} (@pxref{append_add_db_hash}). Distrusted certificates can be explicitly
+added to the dbx using @command{append_add_dbx_cert} (@pxref{append_add_dbx_cert}) and distrusted
+certificate/binary hashes can be explicitly added to the dbx using @command{append_add_dbx_hash}
+(@pxref{append_add_dbx_hash}).
+
+A file can be explicitly verified using @command{append_verify} (@pxref{append_verify}).
+
+Note that when the environment variable @code{check_appended_signatures} is set to @code{yes},
+the @command{append_add_db_cert} and @command{append_add_dbx_cert} commands only accept
+the file @samp{@var{X509_certificate}} that is signed with an appended signature
+(@pxref{Signing certificate and hash files}), and the @command{append_add_db_hash} and
+@command{append_add_dbx_hash} commands only accept the file @samp{@var{hash_file}} that is
+signed with an appended signature (@pxref{Signing certificate and hash files}).
+The signature is verified by the appendedsig module.
+When the environment variable @code{check_appended_signatures} is set to @code{no},
+these commands accept files without an appended signature.
+
+Also, note that @samp{@var{X509_certificate}} should be in DER-format and @samp{@var{hash_file}}
+should be in binary format. Only SHA-256, SHA-384, or SHA-512 hashes of binary/certificate are allowed.
+Certificates/hashes of certificates/binaries added through @command{append_add_db_cert},
+@command{append_add_dbx_cert}, @command{append_add_db_hash}, and @command{append_add_dbx_hash}
+will not be persisted across boots.
+
+Only signatures created using SHA-256 or SHA-512 hash algorithm along with RSA keys of size 2048,
+3072, or 4096 bits are supported.
A file can be signed with the @command{sign-file} utility supplied with the
Linux kernel source. For example, if you have @code{signing.key} as the private
-key and @code{certificate.der} as the x509 certificate containing the public key:
+key and @code{certificate.der} as the X.509 certificate containing the public key:
@example
sign-file SHA256 signing.key certificate.der vmlinux vmlinux.signed
@end example
-Enforcement of signature verification is controlled by the
-@code{check_appended_signatures} variable.
+Once signature verification is turned on, the following file types must carry
+appended signatures:
-@itemize
-@item @samp{no}: no verification is performed. This is the default when GRUB
- is not in @pxref{Lockdown} mode.
-@item @samp{enforce}: verification is performed. Verification can be disabled
- by setting the variable back to @samp{no}.
-@item @samp{forced}: verification is performed and cannot be disabled. This is
- set when GRUB is in Lockdown when the appendedsig module is loaded.
-@end itemize
-
-Unlike GPG-style signatures, not all files loaded by GRUB are required to be
-signed. Once verification is turned on, the following file types will have
-appended signatures verified:
-
-@itemize
+@enumerate
@item Linux kernels
-@item GRUB modules, except those built into the core image
-@item Any new certificate files to be trusted
-@end itemize
-
-ACPI tables and Device Tree images will not be checked for appended signatures
-but must be verified by another mechanism such as GPG-style signatures before
-they will be loaded.
-
-Unless lockdown mode is enabled, signature checking does @strong{not}
-stop an attacker with console access from dropping manually to the GRUB
-console and executing:
-
-@example
-set check_appended_signatures=no
-@end example
-
-Refer to the section on password-protecting GRUB (@pxref{Authentication
-and authorisation}) for more information on preventing this.
-
-Additionally, unless lockdown mode is enabled:
-
-@itemize
-@item Special care must be taken around the @command{loadenv} command, which
- can be used to turn off @code{check_appended_signature}.
-
-@item If the grub configuration file is loaded from the disk, anyone who can
- modify the file on disk can turn off @code{check_appended_signature}.
- Consider embedding the configuration into the core grub image.
-@end itemize
+@item GRUB modules, except those built in to the core image
+@item Any new certificate or binary hash files to be trusted
+@item Any new certificate/binary hash files to be distrusted
+@end enumerate
+
+When GRUB is in lockdown mode (when secure boot mode is set to @code{enforce}),
+signature verification cannot be @strong{disabled} by setting the
+@code{check_appended_signatures} (@pxref{check_appended_signatures}) variable
+to @code{no} or using the @command{load_env} (@pxref{load_env}) command from
+the GRUB console.
@node UEFI secure boot and shim
@section UEFI secure boot and shim support
@@ -6912,6 +7115,34 @@ which increases the risk of password leakage during the process. Moreover, the
superuser list must be well maintained, and the password used cannot be
synchronized with LUKS key rotation.
+@node Signing certificate and hash files
+@section Signing certificate and hash files
+X.509 certificate (public key) files and hash files (binary/certificate hash files)
+can be signed with a Linux kernel module-style appended signature.
+
+The signer.key is a private key used for signing and signer.der is the corresponding
+public key (certificate) used for appended signature verification. Note that the
+signer.der (certificate) should exist in the db (@pxref{Using appended signatures}).
+
+@itemize
+@item Signing the X.509 certificate file using @file{sign-file}.
+The kernel.der is an X.509 certificate file.
+@example
+
+sign-file SHA256 signer.key signer.der kernel.der \
+ kernel.der.signed
+
+@end example
+@item Signing the hash file using @file{sign-file}.
+The binary_hash.bin is a binary hash file.
+@example
+
+sign-file SHA256 signer.key signer.der binary_hash.bin \
+ binary_hash.signed
+
+@end example
+@end itemize
+
@node Signing GRUB itself
@section Signing GRUB itself
To ensure a complete secure-boot chain, there must be a way for the code that

View File

@ -0,0 +1,89 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Nicolas Frayer <nfrayer@redhat.com>
Date: Wed, 19 Nov 2025 13:33:12 +0100
Subject: [PATCH] libtasn1: Fix include path for grub
Signed-off-by: Nicolas Frayer <nfrayer@redhat.com>
---
grub-core/commands/appendedsig/appendedsig.c | 2 +-
grub-core/commands/appendedsig/appendedsig.h | 2 +-
grub-core/commands/appendedsig/asn1util.c | 2 +-
grub-core/commands/appendedsig/gnutls_asn1_tab.c | 2 +-
grub-core/commands/appendedsig/pkix_asn1_tab.c | 2 +-
grub-core/commands/appendedsig/x509.c | 2 +-
6 files changed, 6 insertions(+), 6 deletions(-)
diff --git a/grub-core/commands/appendedsig/appendedsig.c b/grub-core/commands/appendedsig/appendedsig.c
index 5c53f63..1c74554 100644
--- a/grub-core/commands/appendedsig/appendedsig.c
+++ b/grub-core/commands/appendedsig/appendedsig.c
@@ -30,7 +30,7 @@
#include <grub/kernel.h>
#include <grub/extcmd.h>
#include <grub/verify.h>
-#include <libtasn1.h>
+#include <grub/libtasn1.h>
#include <grub/env.h>
#include <grub/lockdown.h>
#include <grub/powerpc/ieee1275/platform_keystore.h>
diff --git a/grub-core/commands/appendedsig/appendedsig.h b/grub-core/commands/appendedsig/appendedsig.h
index c874654..cb0fe19 100644
--- a/grub-core/commands/appendedsig/appendedsig.h
+++ b/grub-core/commands/appendedsig/appendedsig.h
@@ -18,7 +18,7 @@
*/
#include <grub/crypto.h>
-#include <libtasn1.h>
+#include <grub/libtasn1.h>
extern asn1_node grub_gnutls_gnutls_asn;
extern asn1_node grub_gnutls_pkix_asn;
diff --git a/grub-core/commands/appendedsig/asn1util.c b/grub-core/commands/appendedsig/asn1util.c
index 9dd7898..1f50a74 100644
--- a/grub-core/commands/appendedsig/asn1util.c
+++ b/grub-core/commands/appendedsig/asn1util.c
@@ -17,7 +17,7 @@
* along with GRUB. If not, see <http://www.gnu.org/licenses/>.
*/
-#include <libtasn1.h>
+#include <grub/libtasn1.h>
#include <grub/types.h>
#include <grub/err.h>
#include <grub/mm.h>
diff --git a/grub-core/commands/appendedsig/gnutls_asn1_tab.c b/grub-core/commands/appendedsig/gnutls_asn1_tab.c
index efc0c14..16998f2 100644
--- a/grub-core/commands/appendedsig/gnutls_asn1_tab.c
+++ b/grub-core/commands/appendedsig/gnutls_asn1_tab.c
@@ -1,5 +1,5 @@
#include <grub/mm.h>
-#include <libtasn1.h>
+#include <grub/libtasn1.h>
/*
* Imported from gnutls.asn.
diff --git a/grub-core/commands/appendedsig/pkix_asn1_tab.c b/grub-core/commands/appendedsig/pkix_asn1_tab.c
index ec5f87b..fdc989a 100644
--- a/grub-core/commands/appendedsig/pkix_asn1_tab.c
+++ b/grub-core/commands/appendedsig/pkix_asn1_tab.c
@@ -1,5 +1,5 @@
#include <grub/mm.h>
-#include <libtasn1.h>
+#include <grub/libtasn1.h>
/*
* Imported from pkix.asn.
diff --git a/grub-core/commands/appendedsig/x509.c b/grub-core/commands/appendedsig/x509.c
index bc15266..08846aa 100644
--- a/grub-core/commands/appendedsig/x509.c
+++ b/grub-core/commands/appendedsig/x509.c
@@ -17,7 +17,7 @@
* along with GRUB. If not, see <http://www.gnu.org/licenses/>.
*/
-#include <libtasn1.h>
+#include <grub/libtasn1.h>
#include <grub/types.h>
#include <grub/err.h>
#include <grub/mm.h>

View File

@ -0,0 +1,81 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Nicolas Frayer <nfrayer@redhat.com>
Date: Wed, 19 Nov 2025 14:17:51 +0100
Subject: [PATCH] docs: fix duplicated entries
Signed-off-by: Nicolas Frayer <nfrayer@redhat.com>
---
docs/grub.texi | 60 ----------------------------------------------------------
1 file changed, 60 deletions(-)
diff --git a/docs/grub.texi b/docs/grub.texi
index e4f36df..9f5eb68 100644
--- a/docs/grub.texi
+++ b/docs/grub.texi
@@ -7025,66 +7025,6 @@ GRUB will be restricted and some operations/commands cannot be executed.
The @samp{lockdown} variable is set to @samp{y} when the GRUB is locked down.
Otherwise it does not exit.
-@node Signing GRUB itself
-@section Signing GRUB itself
-
-To ensure a complete secure-boot chain, there must be a way for the code that
-loads GRUB to verify the integrity of the core image.
-
-This is ultimately platform-specific and individual platforms can define their
-own mechanisms. However, there are general-purpose mechanisms that can be used
-with GRUB.
-
-@section Signing GRUB for UEFI secure boot
-
-On UEFI platforms, @file{core.img} is a PE binary. Therefore, it can be signed
-with a tool such as @command{pesign} or @command{sbsign}. Refer to the
-suggestions in @pxref{UEFI secure boot and shim} to ensure that the final
-image works under UEFI secure boot and can maintain the secure-boot chain. It
-will also be necessary to enrol the public key used into a relevant firmware
-key database.
-
-@section Signing GRUB with an appended signature
-
-The @file{core.elf} itself can be signed with a Linux kernel module-style
-appended signature.
-
-To support IEEE1275 platforms where the boot image is often loaded directly
-from a disk partition rather than from a file system, the @file{core.elf}
-can specify the size and location of the appended signature with an ELF
-note added by @command{grub-install}.
-
-An image can be signed this way using the @command{sign-file} command from
-the Linux kernel:
-
-@example
-@group
-# grub.key is your private key and certificate.der is your public key
-
-# Determine the size of the appended signature. It depends on the signing
-# certificate and the hash algorithm
-touch empty
-sign-file SHA256 grub.key certificate.der empty empty.sig
-SIG_SIZE=`stat -c '%s' empty.sig`
-rm empty empty.sig
-
-# Build a grub image with $SIG_SIZE reserved for the signature
-grub-install --appended-signature-size $SIG_SIZE --modules="..." ...
-
-# Replace the reserved size with a signature:
-# cut off the last $SIG_SIZE bytes with truncate's minus modifier
-truncate -s -$SIG_SIZE /boot/grub/powerpc-ieee1275/core.elf core.elf.unsigned
-# sign the trimmed file with an appended signature, restoring the correct size
-sign-file SHA256 grub.key certificate.der core.elf.unsigned core.elf.signed
-
-# Don't forget to install the signed image as required
-# (e.g. on powerpc-ieee1275, to the PReP partition)
-@end group
-@end example
-
-As with UEFI secure boot, it is necessary to build in the required modules,
-or sign them separately.
-
@subsection Command line and menuentry editor protection
The TPM key protector provides full disk encryption support on servers or

View File

@ -0,0 +1,345 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Sudhakar Kuppusamy <sudhakar@linux.ibm.com>
Date: Mon, 6 Oct 2025 12:54:46 +0530
Subject: [PATCH] powerpc/ieee1275: Add support for signing GRUB with an
appended signature
Add infrastructure to allow firmware to verify the integrity of GRUB
by use of a Linux-kernel-module-style appended signature. We initially
target powerpc-ieee1275, but the code should be extensible to other
platforms.
Usually these signatures are appended to a file without modifying the
ELF file itself. (This is what the 'sign-file' tool does, for example.)
The verifier loads the signed file from the file system and looks at the
end of the file for the appended signature. However, on powerpc-ieee1275
platforms, the bootloader is often stored directly in the PReP partition
as raw bytes without a file-system. This makes determining the location
of an appended signature more difficult.
To address this, we add a new ELF Note.
The name field of shall be the string "Appended-Signature", zero-padded
to 4 byte alignment. The type field shall be 0x41536967 (the ASCII values
for the string "ASig"). It must be the final section in the ELF binary.
The description shall contain the appended signature structure as defined
by the Linux kernel. The description will also be padded to be a multiple
of 4 bytes. The padding shall be added before the appended signature
structure (not at the end) so that the final bytes of a signed ELF file
are the appended signature magic.
A subsequent patch documents how to create a GRUB core.img validly signed
under this scheme.
Signed-off-by: Rashmica Gupta <rashmica.g@gmail.com>
Signed-off-by: Daniel Axtens <dja@axtens.net>
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>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
---
include/grub/util/install.h | 2 +-
include/grub/util/mkimage.h | 4 +--
util/grub-install-common.c | 28 ++++++++++-----------
util/grub-mkimage.c | 19 +++++++-------
util/grub-mkimagexx.c | 61 +++++++++++++++++++++++----------------------
util/mkimage.c | 20 ++++++++-------
6 files changed, 68 insertions(+), 66 deletions(-)
diff --git a/include/grub/util/install.h b/include/grub/util/install.h
index 93c1f0e..14f4489 100644
--- a/include/grub/util/install.h
+++ b/include/grub/util/install.h
@@ -70,7 +70,7 @@
{ "disable-cli", GRUB_INSTALL_OPTIONS_DISABLE_CLI, 0, 0, \
N_("disabled command line interface access"), 0 }, \
{ "x509key", 'x', N_("FILE"), 0, \
- N_("embed FILE as an x509 certificate for appended signature checking"), 0}, \
+ N_("embed FILE as an x509 certificate for appended signature checking"), 0}, \
{ "appended-signature-size", GRUB_INSTALL_OPTIONS_APPENDED_SIGNATURE_SIZE, \
"SIZE", 0, N_("Add a note segment reserving SIZE bytes for an appended signature"), 1}, \
{ "verbose", 'v', 0, 0, \
diff --git a/include/grub/util/mkimage.h b/include/grub/util/mkimage.h
index 881e303..244e39d 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 *sbat, char **core_img, size_t *core_size,
+ int note, char *sbat, size_t appsig_size, char **core_img, size_t *core_size,
Elf32_Addr target_addr,
struct grub_mkimage_layout *layout);
void
grub_mkimage_generate_elf64 (const struct grub_install_image_target_desc *image_target,
- int note, size_t appsig_size, char *sbat, char **core_img, size_t *core_size,
+ int note, char *sbat, size_t appsig_size, char **core_img, size_t *core_size,
Elf64_Addr target_addr,
struct grub_mkimage_layout *layout);
diff --git a/util/grub-install-common.c b/util/grub-install-common.c
index 41251ce..c4b5cb3 100644
--- a/util/grub-install-common.c
+++ b/util/grub-install-common.c
@@ -475,6 +475,7 @@ int
grub_install_parse (int key, char *arg)
{
const char *end;
+
switch (key)
{
case GRUB_INSTALL_OPTIONS_INSTALL_CORE_COMPRESS:
@@ -580,10 +581,11 @@ grub_install_parse (int key, char *arg)
case GRUB_INSTALL_OPTIONS_GRUB_MKIMAGE:
return 1;
case GRUB_INSTALL_OPTIONS_APPENDED_SIGNATURE_SIZE:
- grub_errno = 0;
- appsig_size = grub_strtol(arg, &end, 10);
- if (grub_errno)
- return 0;
+ appsig_size = grub_strtoul (arg, &end, 10);
+ if (*arg == '\0' || *end != '\0')
+ grub_util_error (_("non-numeric or invalid appended signature size `%s'"), arg);
+ else if (appsig_size == 0)
+ grub_util_error (_("appended signature size `%s', and it should not be zero"), arg);
return 1;
default:
return 0;
@@ -709,14 +711,12 @@ grub_install_make_image_wrap_file (const char *dir, const char *prefix,
grub_util_info ("grub-mkimage --directory '%s' --prefix '%s' --output '%s'"
" --format '%s' --compression '%s'"
- " --appended-signture-size %zu %s%s%s\n",
- " --format '%s' --compression '%s'%s%s%s%s\n",
- dir, prefix, outname,
- mkimage_target, compnames[compression],
- appsig_size,
- note ? " --note" : "",
- disable_shim_lock ? " --disable-shim-lock" : "",
- disable_cli ? " --disable-cli" : "", s);
+ " --appended-signature-size %zu %s %s %s %s\n",
+ dir, prefix, outname,
+ mkimage_target, compnames[compression], appsig_size,
+ note ? " --note" : "",
+ disable_shim_lock ? " --disable-shim-lock" : "",
+ disable_cli ? " --disable-cli" : "", s);
free (s);
tgt = grub_install_get_image_target (mkimage_target);
@@ -725,9 +725,7 @@ grub_install_make_image_wrap_file (const char *dir, const char *prefix,
grub_install_generate_image (dir, prefix, fp, outname,
modules.entries, memdisk_path,
- pubkeys, npubkeys,
- x509keys, nx509keys,
- config_path, tgt,
+ pubkeys, npubkeys, x509keys, nx509keys, config_path, tgt,
note, appsig_size, compression, dtb, sbat,
disable_shim_lock, disable_cli);
while (dc--)
diff --git a/util/grub-mkimage.c b/util/grub-mkimage.c
index 89ca81c..e3511b0 100644
--- a/util/grub-mkimage.c
+++ b/util/grub-mkimage.c
@@ -85,8 +85,8 @@ static struct argp_option options[] = {
{"sbat", 's', N_("FILE"), 0, N_("SBAT metadata"), 0},
{"disable-shim-lock", GRUB_INSTALL_OPTIONS_DISABLE_SHIM_LOCK, 0, 0, N_("disable shim_lock verifier"), 0},
{"disable-cli", GRUB_INSTALL_OPTIONS_DISABLE_CLI, 0, 0, N_("disable command line interface access"), 0},
- {"verbose", 'v', 0, 0, N_("print verbose messages."), 0},
{"appended-signature-size", 'S', N_("SIZE"), 0, N_("Add a note segment reserving SIZE bytes for an appended signature"), 0},
+ {"verbose", 'v', 0, 0, N_("print verbose messages."), 0},
{ 0, 0, 0, 0, 0, 0 }
};
@@ -133,8 +133,8 @@ struct arguments
char *sbat;
int note;
int disable_shim_lock;
- size_t appsig_size;
int disable_cli;
+ size_t appsig_size;
const struct grub_install_image_target_desc *image_target;
grub_compression_t comp;
};
@@ -179,10 +179,11 @@ argp_parser (int key, char *arg, struct argp_state *state)
break;
case 'S':
- grub_errno = 0;
- arguments->appsig_size = grub_strtol(arg, &end, 10);
- if (grub_errno)
- return 0;
+ arguments->appsig_size = grub_strtoul (arg, &end, 10);
+ if (*arg == '\0' || *end != '\0')
+ grub_util_error (_("non-numeric or invalid appended signature size `%s'"), arg);
+ else if (arguments->appsig_size == 0)
+ grub_util_error (_("appended signature size `%s', and it should not be zero"), arg);
break;
case 'm':
@@ -351,9 +352,9 @@ main (int argc, char *argv[])
arguments.npubkeys, arguments.x509keys,
arguments.nx509keys, arguments.config,
arguments.image_target, arguments.note,
- arguments.appsig_size, arguments.comp,
- arguments.dtb, arguments.sbat,
- arguments.disable_shim_lock,
+ arguments.appsig_size,
+ arguments.comp, arguments.dtb,
+ arguments.sbat, arguments.disable_shim_lock,
arguments.disable_cli);
if (grub_util_file_sync (fp) < 0)
diff --git a/util/grub-mkimagexx.c b/util/grub-mkimagexx.c
index b993054..d185246 100644
--- a/util/grub-mkimagexx.c
+++ b/util/grub-mkimagexx.c
@@ -85,15 +85,6 @@ struct grub_ieee1275_note
struct grub_ieee1275_note_desc descriptor;
};
-#define GRUB_APPENDED_SIGNATURE_NOTE_NAME "Appended-Signature"
-#define GRUB_APPENDED_SIGNATURE_NOTE_TYPE 0x41536967 /* "ASig" */
-
-struct grub_appended_signature_note
-{
- Elf32_Nhdr header;
- char name[ALIGN_UP(sizeof (GRUB_APPENDED_SIGNATURE_NOTE_NAME), 4)];
-};
-
#define GRUB_XEN_NOTE_NAME "Xen"
struct fixup_block_list
@@ -124,6 +115,14 @@ struct grub_sbat_note {
char name[ALIGN_UP(sizeof(GRUB_SBAT_NOTE_NAME), 4)];
};
+#define GRUB_APPENDED_SIGNATURE_NOTE_NAME "Appended-Signature"
+#define GRUB_APPENDED_SIGNATURE_NOTE_TYPE 0x41536967 /* "ASig" */
+struct grub_appended_signature_note
+{
+ Elf32_Nhdr header;
+ char name[ALIGN_UP (sizeof (GRUB_APPENDED_SIGNATURE_NOTE_NAME), 4)];
+};
+
static int
is_relocatable (const struct grub_install_image_target_desc *image_target)
{
@@ -225,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 *sbat, char **core_img, size_t *core_size,
+ int note, char *sbat, size_t appsig_size, char **core_img, size_t *core_size,
Elf_Addr target_addr,
struct grub_mkimage_layout *layout)
{
@@ -249,7 +248,7 @@ SUFFIX (grub_mkimage_generate_elf) (const struct grub_install_image_target_desc
if (appsig_size)
{
phnum++;
- footer_size += ALIGN_UP(sizeof (struct grub_appended_signature_note) + appsig_size, 4);
+ footer_size += ALIGN_UP (sizeof (struct grub_appended_signature_note), 4);
}
if (image_target->id != IMAGE_LOONGSON_ELF)
@@ -542,29 +541,31 @@ 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_offset);
+ footer += note_size;
+ footer_offset += note_size;
}
- if (appsig_size) {
- int note_size = ALIGN_UP(sizeof (struct grub_appended_signature_note) + appsig_size, 4);
- struct grub_appended_signature_note *note_ptr = (struct grub_appended_signature_note *)
- (elf_img + program_size + header_size + (note ? sizeof (struct grub_ieee1275_note) : 0));
+ if (appsig_size)
+ {
+ int note_size = ALIGN_UP (sizeof (struct grub_appended_signature_note) + appsig_size, 4);
+ struct grub_appended_signature_note *note_ptr = (struct grub_appended_signature_note *) footer;
- note_ptr->header.n_namesz = grub_host_to_target32 (sizeof (GRUB_APPENDED_SIGNATURE_NOTE_NAME));
- /* needs to sit at the end, so we round this up and sign some zero padding */
- note_ptr->header.n_descsz = grub_host_to_target32 (ALIGN_UP(appsig_size, 4));
- note_ptr->header.n_type = grub_host_to_target32 (GRUB_APPENDED_SIGNATURE_NOTE_TYPE);
- strcpy (note_ptr->name, GRUB_APPENDED_SIGNATURE_NOTE_NAME);
+ note_ptr->header.n_namesz = grub_host_to_target32 (sizeof (GRUB_APPENDED_SIGNATURE_NOTE_NAME));
+ /* Needs to sit at the end, so we round this up and sign some zero padding. */
+ note_ptr->header.n_descsz = grub_host_to_target32 (ALIGN_UP (appsig_size, 4));
+ note_ptr->header.n_type = grub_host_to_target32 (GRUB_APPENDED_SIGNATURE_NOTE_TYPE);
+ strcpy (note_ptr->name, GRUB_APPENDED_SIGNATURE_NOTE_NAME);
- phdr++;
- phdr->p_type = grub_host_to_target32 (PT_NOTE);
- phdr->p_flags = grub_host_to_target32 (PF_R);
- phdr->p_align = grub_host_to_target32 (image_target->voidp_sizeof);
- phdr->p_vaddr = 0;
- phdr->p_paddr = 0;
- phdr->p_filesz = grub_host_to_target32 (note_size);
- phdr->p_memsz = 0;
- phdr->p_offset = grub_host_to_target32 (header_size + program_size + (note ? sizeof (struct grub_ieee1275_note) : 0));
- }
+ 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);
+ }
{
char *str_start = (elf_img + sizeof (*ehdr) + phnum * sizeof (*phdr)
diff --git a/util/mkimage.c b/util/mkimage.c
index cc4c79d..15cfd4b 100644
--- a/util/mkimage.c
+++ b/util/mkimage.c
@@ -883,12 +883,11 @@ void
grub_install_generate_image (const char *dir, const char *prefix,
FILE *out, const char *outname, char *mods[],
char *memdisk_path, char **pubkey_paths,
- size_t npubkeys, char **x509key_paths,
- size_t nx509keys, char *config_path,
+ size_t npubkeys, char **x509key_paths, size_t nx509keys, char *config_path,
const struct grub_install_image_target_desc *image_target,
- int note, size_t appsig_size, grub_compression_t comp,
- const char *dtb_path, const char *sbat_path,
- int disable_shim_lock, int disable_cli)
+ int note, size_t appsig_size, grub_compression_t comp, const char *dtb_path,
+ const char *sbat_path, int disable_shim_lock,
+ int disable_cli)
{
char *kernel_img, *core_img;
size_t total_module_size, core_size;
@@ -978,6 +977,9 @@ grub_install_generate_image (const char *dir, const char *prefix,
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 (appsig_size != 0 && image_target->id != IMAGE_PPC)
+ grub_util_error (_("appended signature can be support only to powerpc-ieee1275 images"));
+
if (disable_shim_lock)
total_module_size += sizeof (struct grub_module_header);
@@ -1884,11 +1886,11 @@ 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, sbat, &core_img,
- &core_size, target_addr, &layout);
+ grub_mkimage_generate_elf32 (image_target, note, sbat, appsig_size, &core_img, &core_size,
+ target_addr, &layout);
else
- grub_mkimage_generate_elf64 (image_target, note, appsig_size, sbat, &core_img,
- &core_size, target_addr, &layout);
+ grub_mkimage_generate_elf64 (image_target, note, sbat, appsig_size, &core_img, &core_size,
+ target_addr, &layout);
}
break;
}

View File

@ -0,0 +1,43 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Sudhakar Kuppusamy <sudhakar@linux.ibm.com>
Date: Wed, 3 Dec 2025 13:19:57 +0530
Subject: [PATCH] appendedsig: Fix grub-mkimage with an unaligned appended
signature size
The grub-mkimage does not add zero padding when creating core.elf with an
appended signature size that is not aligned to a multiple of 4 bytes.
Firmware is unable to read the magic string "~Module signature appended~"
from core.elf.
To fix this, round an appended signature size + appended signature ELF note
size up to the nearest multiple of a 4-byte alignment and truncate it to the
appended signature size.
Example:
grub-mkimage -O powerpc-ieee1275 -o core.elf -d grub-core -p /grub2 -x \
kernel.der --appended-signature-size 490 ...
Signed-off-by: Sudhakar Kuppusamy <sudhakar@linux.ibm.com>
---
util/grub-mkimagexx.c | 8 +++++++-
1 file changed, 7 insertions(+), 1 deletion(-)
diff --git a/util/grub-mkimagexx.c b/util/grub-mkimagexx.c
index d185246f1010..c99c7f99c787 100644
--- a/util/grub-mkimagexx.c
+++ b/util/grub-mkimagexx.c
@@ -248,7 +248,13 @@ SUFFIX (grub_mkimage_generate_elf) (const struct grub_install_image_target_desc
if (appsig_size)
{
phnum++;
- footer_size += ALIGN_UP (sizeof (struct grub_appended_signature_note), 4);
+ /*
+ * Rounds a appended signature size + appended signature note size up to
+ * the nearest multiple of a 4-byte alignment.
+ */
+ footer_size += ALIGN_UP (sizeof (struct grub_appended_signature_note) + appsig_size, 4);
+ /* Truncating to appended signature size. */
+ footer_size -= appsig_size;
}
if (image_target->id != IMAGE_LOONGSON_ELF)

View File

@ -0,0 +1,109 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Alec Brown <alec.r.brown@oracle.com>
Date: Tue, 12 Aug 2025 03:45:32 +0000
Subject: [PATCH] kern/misc: Implement grub_strtok()
Add the functions grub_strtok() and grub_strtok_r() to help parse strings into
tokens separated by characters in the "delim" parameter. These functions are
present in gnulib but calling them directly from the gnulib code is quite
challenging since the call "#include <string.h>" would include the header file
grub-core/lib/posix_wrap/string.h instead of grub-core/lib/gnulib/string.h,
where strtok() and strtok_r() are declared. Since this overlap is quite
problematic, the simpler solution was to implement the code in the GRUB based
on gnulib's implementation. For more information on these functions, visit the
Linux Programmer's Manual, man strtok.
Signed-off-by: Alec Brown <alec.r.brown@oracle.com>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
---
grub-core/kern/misc.c | 62 +++++++++++++++++++++++++++++++++++++++++++++++++++
include/grub/misc.h | 3 +++
2 files changed, 65 insertions(+)
diff --git a/grub-core/kern/misc.c b/grub-core/kern/misc.c
index 69bd655f3d..c69fe7fb19 100644
--- a/grub-core/kern/misc.c
+++ b/grub-core/kern/misc.c
@@ -453,6 +453,68 @@ grub_strword (const char *haystack, const char *needle)
return 0;
}
+char *
+grub_strtok_r (char *s, const char *delim, char **save_ptr)
+{
+ char *token;
+ const char *c;
+ bool is_delim;
+
+ if (s == NULL)
+ s = *save_ptr;
+
+ /* Scan leading delimiters. */
+ while (*s != '\0')
+ {
+ is_delim = false;
+ for (c = delim; *c != '\0'; c++)
+ {
+ if (*s == *c)
+ {
+ is_delim = true;
+ break;
+ }
+ }
+ if (is_delim == true)
+ s++;
+ else
+ break;
+ }
+
+ if (*s == '\0')
+ {
+ *save_ptr = s;
+ return NULL;
+ }
+
+ /* Find the end of the token. */
+ token = s;
+ while (*s != '\0')
+ {
+ for (c = delim; *c != '\0'; c++)
+ {
+ if (*s == *c)
+ {
+ *s = '\0';
+ *save_ptr = s + 1;
+ return token;
+ }
+ }
+ s++;
+ }
+
+ *save_ptr = s;
+ return token;
+}
+
+char *
+grub_strtok (char *s, const char *delim)
+{
+ static char *last;
+
+ return grub_strtok_r (s, delim, &last);
+}
+
int
grub_isspace (int c)
{
diff --git a/include/grub/misc.h b/include/grub/misc.h
index 0429339ef3..626f0c3535 100644
--- a/include/grub/misc.h
+++ b/include/grub/misc.h
@@ -134,6 +134,9 @@ char *EXPORT_FUNC(grub_strchr) (const char *s, int c);
char *EXPORT_FUNC(grub_strrchr) (const char *s, int c);
int EXPORT_FUNC(grub_strword) (const char *s, const char *w);
+char *EXPORT_FUNC(grub_strtok_r) (char *s, const char *delim, char **save_ptr);
+char *EXPORT_FUNC(grub_strtok) (char *s, const char *delim);
+
/* Copied from gnulib.
Written by Bruno Haible <bruno@clisp.org>, 2005. */
static inline char *

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,43 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Alec Brown <alec.r.brown@oracle.com>
Date: Tue, 12 Aug 2025 03:45:34 +0000
Subject: [PATCH] util/misc.c: Change offset type for
grub_util_write_image_at()
Adding filevercmp support to grub-core/commands/blsuki.c from gnulib will cause
issues with the type of the offset parameter for grub_util_write_image_at() for
emu builds. To fix this issue, we can change the type from off_t to grub_off_t.
Signed-off-by: Alec Brown <alec.r.brown@oracle.com>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
---
include/grub/util/misc.h | 2 +-
util/misc.c | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/include/grub/util/misc.h b/include/grub/util/misc.h
index e9e0a6724a..bfce065583 100644
--- a/include/grub/util/misc.h
+++ b/include/grub/util/misc.h
@@ -36,7 +36,7 @@ char *grub_util_read_image (const char *path);
void grub_util_load_image (const char *path, char *buf);
void grub_util_write_image (const char *img, size_t size, FILE *out,
const char *name);
-void grub_util_write_image_at (const void *img, size_t size, off_t offset,
+void grub_util_write_image_at (const void *img, size_t size, grub_off_t offset,
FILE *out, const char *name);
char *make_system_path_relative_to_its_root (const char *path);
diff --git a/util/misc.c b/util/misc.c
index 0f928e5b49..6e16a68d9a 100644
--- a/util/misc.c
+++ b/util/misc.c
@@ -101,7 +101,7 @@ grub_util_read_image (const char *path)
}
void
-grub_util_write_image_at (const void *img, size_t size, off_t offset, FILE *out,
+grub_util_write_image_at (const void *img, size_t size, grub_off_t offset, FILE *out,
const char *name)
{
grub_util_info ("writing 0x%" GRUB_HOST_PRIxLONG_LONG " bytes at offset 0x%"

View File

@ -0,0 +1,342 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Robbie Harwood <rharwood@redhat.com>
Date: Tue, 12 Aug 2025 03:45:35 +0000
Subject: [PATCH] blsuki: Check for mounted /boot in emu
Irritatingly, BLS defines paths relative to the mountpoint of the
filesystem which contains its snippets, not / or any other fixed
location. So grub-emu needs to know whether /boot is a separate
filesystem from / and conditionally prepend a path.
Signed-off-by: Robbie Harwood <rharwood@redhat.com>
Signed-off-by: Alec Brown <alec.r.brown@oracle.com>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
---
grub-core/Makefile.core.def | 3 ++
grub-core/commands/blsuki.c | 83 +++++++++++++++++++++++++++++++++++++----
grub-core/osdep/linux/getroot.c | 8 ++++
grub-core/osdep/unix/getroot.c | 4 +-
include/grub/emu/misc.h | 2 +-
5 files changed, 91 insertions(+), 9 deletions(-)
diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def
index 78fafdd8fa..ddc5e71bbb 100644
--- a/grub-core/Makefile.core.def
+++ b/grub-core/Makefile.core.def
@@ -378,6 +378,9 @@ kernel = {
emu = kern/emu/cache_s.S;
emu = kern/emu/hostdisk.c;
emu = osdep/unix/hostdisk.c;
+ emu = osdep/relpath.c;
+ emu = osdep/getroot.c;
+ emu = osdep/unix/getroot.c;
emu = osdep/exec.c;
extra_dist = osdep/unix/exec.c;
emu = osdep/devmapper/hostdisk.c;
diff --git a/grub-core/commands/blsuki.c b/grub-core/commands/blsuki.c
index 9440adb100..ed93a150b1 100644
--- a/grub-core/commands/blsuki.c
+++ b/grub-core/commands/blsuki.c
@@ -32,6 +32,13 @@
#include <grub/lib/envblk.h>
#include <filevercmp.h>
+#ifdef GRUB_MACHINE_EMU
+#include <grub/emu/misc.h>
+#define GRUB_BOOT_DEVICE "/boot"
+#else
+#define GRUB_BOOT_DEVICE ""
+#endif
+
GRUB_MOD_LICENSE ("GPLv3+");
#define GRUB_BLS_CONFIG_PATH "/loader/entries/"
@@ -79,6 +86,34 @@ static grub_blsuki_entry_t *entries;
#define FOR_BLSUKI_ENTRIES(var) FOR_LIST_ELEMENTS (var, entries)
+/*
+ * BLS appears to make paths relative to the filesystem that snippets are
+ * on, not /. Attempt to cope.
+ */
+static char *blsuki_update_boot_device (char *tmp)
+{
+#ifdef GRUB_MACHINE_EMU
+ static int separate_boot = -1;
+ char *ret;
+
+ if (separate_boot != -1)
+ goto probed;
+
+ separate_boot = 0;
+
+ ret = grub_make_system_path_relative_to_its_root (GRUB_BOOT_DEVICE);
+
+ if (ret != NULL && ret[0] == '\0')
+ separate_boot = 1;
+
+ probed:
+ if (separate_boot == 0)
+ return tmp;
+#endif
+
+ return grub_stpcpy (tmp, GRUB_BOOT_DEVICE);
+}
+
/*
* This function will add a new keyval pair to a list of keyvals stored in the
* entry parameter.
@@ -526,7 +561,7 @@ bls_get_linux (grub_blsuki_entry_t *entry)
linux_path = blsuki_get_val (entry, "linux", NULL);
options = blsuki_expand_val (blsuki_get_val (entry, "options", NULL));
- if (grub_add (sizeof ("linux "), grub_strlen (linux_path), &size))
+ if (grub_add (sizeof ("linux " GRUB_BOOT_DEVICE), grub_strlen (linux_path), &size))
{
grub_error (GRUB_ERR_OUT_OF_RANGE, "overflow detected while calculating linux buffer size");
goto finish;
@@ -548,6 +583,7 @@ bls_get_linux (grub_blsuki_entry_t *entry)
tmp = linux_cmd;
tmp = grub_stpcpy (tmp, "linux ");
+ tmp = blsuki_update_boot_device (tmp);
tmp = grub_stpcpy (tmp, linux_path);
if (options != NULL)
{
@@ -582,7 +618,7 @@ bls_get_initrd (grub_blsuki_entry_t *entry)
for (i = 0; initrd_list != NULL && initrd_list[i] != NULL; i++)
{
- if (grub_add (size, 1, &size) ||
+ if (grub_add (size, sizeof (" " GRUB_BOOT_DEVICE) - 1, &size) ||
grub_add (size, grub_strlen (initrd_list[i]), &size))
{
grub_error (GRUB_ERR_OUT_OF_RANGE, "overflow detected calculating initrd buffer size");
@@ -605,6 +641,7 @@ bls_get_initrd (grub_blsuki_entry_t *entry)
{
grub_dprintf ("blsuki", "adding initrd %s\n", initrd_list[i]);
tmp = grub_stpcpy (tmp, " ");
+ tmp = blsuki_update_boot_device (tmp);
tmp = grub_stpcpy (tmp, initrd_list[i]);
}
tmp = grub_stpcpy (tmp, "\n");
@@ -630,7 +667,7 @@ bls_get_devicetree (grub_blsuki_entry_t *entry)
dt_path = blsuki_expand_val (blsuki_get_val (entry, "devicetree", NULL));
if (dt_path != NULL)
{
- if (grub_add (sizeof ("devicetree "), grub_strlen (dt_path), &size) ||
+ if (grub_add (sizeof ("devicetree " GRUB_BOOT_DEVICE), grub_strlen (dt_path), &size) ||
grub_add (size, 1, &size))
{
grub_error (GRUB_ERR_OUT_OF_RANGE, "overflow detected calculating device tree buffer size");
@@ -643,6 +680,7 @@ bls_get_devicetree (grub_blsuki_entry_t *entry)
tmp = dt_cmd;
tmp = grub_stpcpy (dt_cmd, "devicetree ");
+ tmp = blsuki_update_boot_device (tmp);
tmp = grub_stpcpy (tmp, dt_path);
tmp = grub_stpcpy (tmp, "\n");
}
@@ -757,7 +795,11 @@ blsuki_set_find_entry_info (struct find_entry_info *info, const char *dirname, c
if (devid == NULL)
{
+#ifdef GRUB_MACHINE_EMU
+ devid = "host";
+#else
devid = grub_env_get ("root");
+#endif
if (devid == NULL)
return grub_error (GRUB_ERR_FILE_NOT_FOUND, N_("variable '%s' isn't set"), "root");
}
@@ -799,10 +841,13 @@ blsuki_set_find_entry_info (struct find_entry_info *info, const char *dirname, c
* parameter. If the fallback option is enabled, the default location will be
* checked for BLS config files if the first attempt fails.
*/
-static void
+static grub_err_t
blsuki_find_entry (struct find_entry_info *info, bool enable_fallback)
{
struct read_entry_info read_entry_info;
+ char *default_dir = NULL;
+ char *tmp;
+ grub_size_t default_size;
grub_fs_t dir_fs = NULL;
grub_device_t dir_dev = NULL;
bool fallback = false;
@@ -833,7 +878,15 @@ blsuki_find_entry (struct find_entry_info *info, bool enable_fallback)
*/
if (entries == NULL && fallback == false && enable_fallback == true)
{
- blsuki_set_find_entry_info (info, GRUB_BLS_CONFIG_PATH, NULL);
+ default_size = sizeof (GRUB_BOOT_DEVICE) + sizeof (GRUB_BLS_CONFIG_PATH) - 1;
+ default_dir = grub_malloc (default_size);
+ if (default_dir == NULL)
+ return grub_errno;
+
+ tmp = blsuki_update_boot_device (default_dir);
+ tmp = grub_stpcpy (tmp, GRUB_BLS_CONFIG_PATH);
+
+ blsuki_set_find_entry_info (info, default_dir, NULL);
grub_dprintf ("blsuki", "Entries weren't found in %s, fallback to %s\n",
read_entry_info.dirname, info->dirname);
fallback = true;
@@ -842,6 +895,9 @@ blsuki_find_entry (struct find_entry_info *info, bool enable_fallback)
fallback = false;
}
while (fallback == true);
+
+ grub_free (default_dir);
+ return GRUB_ERR_NONE;
}
static grub_err_t
@@ -851,6 +907,9 @@ blsuki_load_entries (char *path, bool enable_fallback)
static grub_err_t r;
const char *devid = NULL;
char *dir = NULL;
+ char *default_dir = NULL;
+ char *tmp;
+ grub_size_t dir_size;
struct find_entry_info info = {
.dev = NULL,
.fs = NULL,
@@ -892,15 +951,25 @@ blsuki_load_entries (char *path, bool enable_fallback)
}
if (dir == NULL)
- dir = (char *) GRUB_BLS_CONFIG_PATH;
+ {
+ dir_size = sizeof (GRUB_BOOT_DEVICE) + sizeof (GRUB_BLS_CONFIG_PATH) - 2;
+ default_dir = grub_malloc (dir_size);
+ if (default_dir == NULL)
+ return grub_errno;
+
+ tmp = blsuki_update_boot_device (default_dir);
+ tmp = grub_stpcpy (tmp, GRUB_BLS_CONFIG_PATH);
+ dir = default_dir;
+ }
r = blsuki_set_find_entry_info (&info, dir, devid);
if (r == GRUB_ERR_NONE)
- blsuki_find_entry (&info, enable_fallback);
+ r = blsuki_find_entry (&info, enable_fallback);
if (info.dev != NULL)
grub_device_close (info.dev);
+ grub_free (default_dir);
return r;
}
diff --git a/grub-core/osdep/linux/getroot.c b/grub-core/osdep/linux/getroot.c
index b832593213..a60cf18a01 100644
--- a/grub-core/osdep/linux/getroot.c
+++ b/grub-core/osdep/linux/getroot.c
@@ -139,6 +139,7 @@ struct mountinfo_entry
char fstype[ESCAPED_PATH_MAX + 1], device[ESCAPED_PATH_MAX + 1];
};
+#ifdef GRUB_UTIL
static char **
grub_util_raid_getmembers (const char *name, int bootable)
{
@@ -199,6 +200,7 @@ grub_util_raid_getmembers (const char *name, int bootable)
return devicelist;
}
+#endif
/* Statting something on a btrfs filesystem always returns a virtual device
major/minor pair rather than the real underlying device, because btrfs
@@ -700,6 +702,7 @@ out:
return ret;
}
+#ifdef GRUB_UTIL
static char *
get_mdadm_uuid (const char *os_dev)
{
@@ -757,6 +760,7 @@ out:
return name;
}
+#endif
static int
grub_util_is_imsm (const char *os_dev)
@@ -1089,6 +1093,7 @@ grub_util_part_to_disk (const char *os_dev, struct stat *st,
return path;
}
+#ifdef GRUB_UTIL
static char *
grub_util_get_raid_grub_dev (const char *os_dev)
{
@@ -1191,6 +1196,7 @@ grub_util_get_raid_grub_dev (const char *os_dev)
}
return grub_dev;
}
+#endif
enum grub_dev_abstraction_types
grub_util_get_dev_abstraction_os (const char *os_dev)
@@ -1207,6 +1213,7 @@ grub_util_get_dev_abstraction_os (const char *os_dev)
return GRUB_DEV_ABSTRACTION_NONE;
}
+#ifdef GRUB_UTIL
int
grub_util_pull_device_os (const char *os_dev,
enum grub_dev_abstraction_types ab)
@@ -1263,6 +1270,7 @@ grub_util_get_grub_dev_os (const char *os_dev)
return grub_dev;
}
+#endif
static void *mp = NULL;
static void
diff --git a/grub-core/osdep/unix/getroot.c b/grub-core/osdep/unix/getroot.c
index ee11b02fb6..62581ba601 100644
--- a/grub-core/osdep/unix/getroot.c
+++ b/grub-core/osdep/unix/getroot.c
@@ -16,8 +16,8 @@
* along with GRUB. If not, see <http://www.gnu.org/licenses/>.
*/
-#include <config.h>
#include <config-util.h>
+#include <config.h>
#include <sys/stat.h>
#include <sys/types.h>
@@ -567,6 +567,7 @@ grub_guess_root_devices (const char *dir_in)
#endif
+#ifdef GRUB_UTIL
void
grub_util_pull_lvm_by_command (const char *os_dev)
{
@@ -663,6 +664,7 @@ out:
free (buf);
free (vgid);
}
+#endif
/* ZFS has similar problems to those of btrfs (see above). */
void
diff --git a/include/grub/emu/misc.h b/include/grub/emu/misc.h
index f3a712a8b2..59b8038c60 100644
--- a/include/grub/emu/misc.h
+++ b/include/grub/emu/misc.h
@@ -39,7 +39,7 @@ void grub_fini_all (void);
void grub_find_zpool_from_dir (const char *dir,
char **poolname, char **poolfs);
-char *grub_make_system_path_relative_to_its_root (const char *path)
+char *EXPORT_FUNC (grub_make_system_path_relative_to_its_root) (const char *path)
WARN_UNUSED_RESULT;
int
grub_util_device_is_mapped (const char *dev);

View File

@ -0,0 +1,822 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Alec Brown <alec.r.brown@oracle.com>
Date: Tue, 12 Aug 2025 03:45:36 +0000
Subject: [PATCH] blsuki: Add uki command to load Unified Kernel Image entries
A Unified Kernel Image (UKI) is a single UEFI PE file that combines
a UEFI boot stub, a Linux kernel image, an initrd, and further resources.
The uki command will locate where the UKI file is and create a GRUB menu
entry to load it.
The Unified Kernel Image Specification: https://uapi-group.org/specifications/specs/unified_kernel_image/
Signed-off-by: Alec Brown <alec.r.brown@oracle.com>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
---
docs/grub.texi | 36 +++-
grub-core/commands/blsuki.c | 476 ++++++++++++++++++++++++++++++++++++++++----
include/grub/menu.h | 2 +
3 files changed, 474 insertions(+), 40 deletions(-)
diff --git a/docs/grub.texi b/docs/grub.texi
index e795719abe..cd8390213d 100644
--- a/docs/grub.texi
+++ b/docs/grub.texi
@@ -3358,7 +3358,8 @@ chain-loaded system, @pxref{drivemap}.
@subsection blsuki_save_default
If this variable is set, menu entries generated from BLS config files
-(@pxref{blscfg}) will be set as the default boot entry when selected.
+(@pxref{blscfg}) or UKI files (@pxref{uki}) will be set as the default boot
+entry when selected.
@node check_appended_signatures
@subsection check_appended_signatures
@@ -4460,6 +4461,7 @@ you forget a command, you can run the command @command{help}
* 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
+* uki:: Load Unified Kernel Image menu entries
* unset:: Unset an environment variable
@comment * vbeinfo:: List available video modes
* verify_appended:: Verify appended digital signature
@@ -6198,6 +6200,38 @@ Unset the environment variable @var{envvar}.
@end deffn
+@node uki
+@subsection uki
+
+@deffn Command uki [@option{-p|--path} dir] [@option{-f|--enable-fallback}] [@option{-d|--show-default}] [@option{-n|--show-non-default}] [@option{-e|--entry} file]
+Load Unified Kernel Image (UKI) files into the GRUB menu. Boot entries
+generated from @command{uki} won't interfere with entries from @file{grub.cfg} appearing in the
+GRUB menu. Also, entries generated from @command{uki} exists only in memory and don't
+update @file{grub.cfg}.
+
+By default, the UKI files are stored in the @file{/EFI/Linux} directory in the EFI
+system partition. If UKI files are stored elsewhere, the @option{--path} option can be
+used to check a different directory instead of the default location. If no UKI
+files are found while using the @option{--path} option, the @option{--enable-fallback} option can
+be used to check for files in the default location.
+
+The @option{--show-default} option allows the default boot entry to be added to the
+GRUB menu from the UKI files.
+
+The @option{--show-non-default} option allows non-default boot entries to be added to
+the GRUB menu from the UKI files.
+
+The @option{--entry} option allows specific boot entries to be added to the GRUB menu
+from the UKI files.
+
+The @option{--entry}, @option{--show-default}, and @option{--show-non-default} options
+are used to filter which UKI files are added to the GRUB menu. If none are
+used, all files in the default location or the location specified by @option{--path}
+will be added to the GRUB menu.
+
+For more information on UKI, see: @uref{https://uapi-group.org/specifications/specs/unified_kernel_image/, The Unified Kernel Image Specification}
+@end deffn
+
@ignore
@node vbeinfo
@subsection vbeinfo
diff --git a/grub-core/commands/blsuki.c b/grub-core/commands/blsuki.c
index ed93a150b1..cb00f936a7 100644
--- a/grub-core/commands/blsuki.c
+++ b/grub-core/commands/blsuki.c
@@ -32,6 +32,12 @@
#include <grub/lib/envblk.h>
#include <filevercmp.h>
+#ifdef GRUB_MACHINE_EFI
+#include <grub/efi/efi.h>
+#include <grub/efi/disk.h>
+#include <grub/efi/pe32.h>
+#endif
+
#ifdef GRUB_MACHINE_EMU
#include <grub/emu/misc.h>
#define GRUB_BOOT_DEVICE "/boot"
@@ -42,14 +48,28 @@
GRUB_MOD_LICENSE ("GPLv3+");
#define GRUB_BLS_CONFIG_PATH "/loader/entries/"
+#define GRUB_UKI_CONFIG_PATH "/EFI/Linux"
#define BLS_EXT_LEN (sizeof (".conf") - 1)
+#define UKI_EXT_LEN (sizeof (".efi") - 1)
/*
* It is highly unlikely to ever receive a large amount of keyval pairs. A
* limit of 10000 is more than enough.
*/
#define BLSUKI_KEYVALS_MAX 10000
+/*
+ * The only sections we read are ".cmdline" and ".osrel". The ".cmdline"
+ * section has a size limit of 4096 and it would be very unlikely for the size
+ * of the ".osrel" section to be 5 times larger than 4096.
+ */
+#define UKI_SECTION_SIZE_MAX (5 * 4096)
+
+enum blsuki_cmd_type
+ {
+ BLSUKI_BLS_CMD,
+ BLSUKI_UKI_CMD,
+ };
static const struct grub_arg_option bls_opt[] =
{
@@ -61,6 +81,18 @@ static const struct grub_arg_option bls_opt[] =
{0, 0, 0, 0, 0, 0}
};
+#ifdef GRUB_MACHINE_EFI
+static const struct grub_arg_option uki_opt[] =
+ {
+ {"path", 'p', 0, N_("Specify path to find UKI entries."), N_("DIR"), ARG_TYPE_PATHNAME},
+ {"enable-fallback", 'f', 0, "Fallback to the default BLS path if --path fails to find UKI entries.", 0, ARG_TYPE_NONE},
+ {"show-default", 'd', 0, N_("Allow the default UKI entry to be added to the GRUB menu."), 0, ARG_TYPE_NONE},
+ {"show-non-default", 'n', 0, N_("Allow the non-default UKI entries to be added to the GRUB menu."), 0, ARG_TYPE_NONE},
+ {"entry", 'e', 0, N_("Allow specificUKII entries to be added to the GRUB menu."), N_("FILE"), ARG_TYPE_FILE},
+ {0, 0, 0, 0, 0, 0}
+ };
+#endif
+
struct keyval
{
const char *key;
@@ -71,6 +103,7 @@ struct read_entry_info
{
const char *devid;
const char *dirname;
+ enum blsuki_cmd_type cmd_type;
grub_file_t file;
};
@@ -82,7 +115,7 @@ struct find_entry_info
grub_fs_t fs;
};
-static grub_blsuki_entry_t *entries;
+static grub_blsuki_entry_t *entries = NULL;
#define FOR_BLSUKI_ENTRIES(var) FOR_LIST_ELEMENTS (var, entries)
@@ -181,7 +214,7 @@ blsuki_add_keyval (grub_blsuki_entry_t *entry, char *key, char *val)
* Find the value of the key named by keyname. If there are allowed to be
* more than one, pass a pointer set to -1 to the last parameter the first
* time, and pass the same pointer through each time after, and it'll return
- * them in sorted order as defined in the BLS fragment file.
+ * them in sorted order.
*/
static char *
blsuki_get_val (grub_blsuki_entry_t *entry, const char *keyname, int *last)
@@ -310,20 +343,212 @@ bls_parse_keyvals (grub_file_t f, grub_blsuki_entry_t *entry)
return err;
}
+#ifdef GRUB_MACHINE_EFI
+/*
+ * This function searches for the .cmdline, .osrel, and .linux sections of a
+ * UKI. We only need to store the data for the .cmdline and .osrel sections,
+ * but we also need to verify that the .linux section exists.
+ */
+static grub_err_t
+uki_parse_keyvals (grub_file_t f, grub_blsuki_entry_t *entry)
+{
+ struct grub_msdos_image_header *dos = NULL;
+ struct grub_pe_image_header *pe = NULL;
+ grub_off_t section_offset = 0;
+ struct grub_pe32_section_table *section = NULL;
+ struct grub_pe32_coff_header *coff_header = NULL;
+ char *val = NULL;
+ char *key = NULL;
+ const char *target[] = {".cmdline", ".osrel", ".linux", NULL};
+ bool has_linux = false;
+ grub_err_t err = GRUB_ERR_NONE;
+
+ dos = grub_zalloc (sizeof (*dos));
+ if (dos == NULL)
+ return grub_errno;
+ if (grub_file_read (f, dos, sizeof (*dos)) < (grub_ssize_t) sizeof (*dos))
+ {
+ err = grub_error (GRUB_ERR_FILE_READ_ERROR, "failed to read UKI image header");
+ goto finish;
+ }
+ if (dos->msdos_magic != GRUB_DOS_MAGIC)
+ {
+ err = grub_error (GRUB_ERR_BAD_FILE_TYPE, "plain image kernel is not supported");
+ goto finish;
+ }
+
+ grub_dprintf ("blsuki", "PE/COFF header @ %08x\n", dos->pe_image_header_offset);
+ pe = grub_zalloc (sizeof (*pe));
+ if (pe == NULL)
+ {
+ err = grub_errno;
+ goto finish;
+ }
+ if (grub_file_seek (f, dos->pe_image_header_offset) == (grub_off_t) -1 ||
+ grub_file_read (f, pe, sizeof (*pe)) != sizeof (*pe))
+ {
+ err = grub_error (GRUB_ERR_FILE_READ_ERROR, "failed to read COFF image header");
+ goto finish;
+ }
+ if (pe->optional_header.magic != GRUB_PE32_NATIVE_MAGIC)
+ {
+ err = grub_error (GRUB_ERR_BAD_FILE_TYPE, "non-native image not supported");
+ goto finish;
+ }
+
+ coff_header = &(pe->coff_header);
+ section_offset = dos->pe_image_header_offset + sizeof (*pe);
+
+ for (int i = 0; i < coff_header->num_sections; i++)
+ {
+ section = grub_zalloc (sizeof (*section));
+ if (section == NULL)
+ {
+ err = grub_errno;
+ goto finish;
+ }
+
+ if (grub_file_seek (f, section_offset) == (grub_off_t) -1 ||
+ grub_file_read (f, section, sizeof (*section)) != sizeof (*section))
+ {
+ err = grub_error (GRUB_ERR_FILE_READ_ERROR, "failed to read section header");
+ goto finish;
+ }
+
+ key = grub_strndup (section->name, 8);
+ if (key == NULL)
+ {
+ err = grub_errno;
+ goto finish;
+ }
+
+ for (int j = 0; target[j] != NULL; j++)
+ {
+ if (grub_strcmp (key, target[j]) == 0)
+ {
+ /*
+ * We don't need to read the contents of the .linux PE section, but we
+ * should verify that the section exists.
+ */
+ if (grub_strcmp (key, ".linux") == 0)
+ {
+ has_linux = true;
+ break;
+ }
+
+ if (section->raw_data_size > UKI_SECTION_SIZE_MAX)
+ {
+ err = grub_error (GRUB_ERR_BAD_NUMBER, "UKI section size is larger than expected");
+ goto finish;
+ }
+
+ val = grub_zalloc (section->raw_data_size);
+ if (val == NULL)
+ {
+ err = grub_errno;
+ goto finish;
+ }
+
+ if (grub_file_seek (f, section->raw_data_offset) == (grub_off_t) -1 ||
+ grub_file_read (f, val, section->raw_data_size) != (grub_ssize_t) section->raw_data_size)
+ {
+ err = grub_error (GRUB_ERR_FILE_READ_ERROR, "failed to read section");
+ goto finish;
+ }
+
+ err = blsuki_add_keyval (entry, key, val);
+ if (err != GRUB_ERR_NONE)
+ goto finish;
+
+ break;
+ }
+ }
+
+ section_offset += sizeof (*section);
+ grub_free (section);
+ grub_free (val);
+ grub_free (key);
+ section = NULL;
+ val = NULL;
+ key = NULL;
+ }
+
+ if (has_linux == false)
+ err = grub_error (GRUB_ERR_NO_KERNEL, "UKI is missing the '.linux' section");
+
+ finish:
+ grub_free (dos);
+ grub_free (pe);
+ grub_free (section);
+ grub_free (val);
+ grub_free (key);
+ return err;
+}
+
+/*
+ * This function obtains the keyval pairs when the .osrel data is input into
+ * the osrel_ptr parameter and returns the keyval pair. Since we are using
+ * grub_strtok_r(), the osrel_ptr will be updated to the following line of
+ * osrel. This function returns NULL when it reaches the end of osrel.
+ */
+static char *
+uki_read_osrel (char **osrel_ptr, char **val_ret)
+{
+ char *key, *val;
+ grub_size_t val_size;
+
+ for (;;)
+ {
+ key = grub_strtok_r (NULL, "\n\r", osrel_ptr);
+ if (key == NULL)
+ return NULL;
+
+ /* Remove leading white space */
+ while (*key == ' ' || *key == '\t')
+ key++;
+
+ /* Skip commented lines */
+ if (*key == '#')
+ continue;
+
+ /* Split key/value */
+ key = grub_strtok_r (key, "=", &val);
+ if (key == NULL || *val == '\0')
+ continue;
+
+ /* Remove quotes from value */
+ val_size = grub_strlen (val);
+ if ((*val == '\"' && val[val_size - 1] == '\"') ||
+ (*val == '\'' && val[val_size - 1] == '\''))
+ {
+ val[val_size - 1] = '\0';
+ val++;
+ }
+
+ *val_ret = val;
+ break;
+ }
+
+ return key;
+}
+#endif
+
/*
* If a file hasn't already been opened, this function opens a BLS config file
- * and initializes entry data before parsing keyvals and adding the entry to
- * the list of BLS entries.
+ * or UKI and initializes entry data before parsing keyvals and adding the entry
+ * to the list of BLS or UKI entries.
*/
static int
blsuki_read_entry (const char *filename,
const struct grub_dirhook_info *dirhook_info __attribute__ ((__unused__)),
void *data)
{
- grub_size_t path_len = 0, filename_len;
- grub_err_t err;
+ grub_size_t path_len = 0, ext_len = 0, filename_len;
+ grub_err_t err = GRUB_ERR_NONE;
char *p = NULL;
+ const char *ext = NULL;
grub_file_t f = NULL;
+ enum grub_file_type file_type = 0;
grub_blsuki_entry_t *entry;
struct read_entry_info *info = (struct read_entry_info *) data;
@@ -331,17 +556,31 @@ blsuki_read_entry (const char *filename,
filename_len = grub_strlen (filename);
+ if (info->cmd_type == BLSUKI_BLS_CMD)
+ {
+ ext = ".conf";
+ ext_len = BLS_EXT_LEN;
+ file_type = GRUB_FILE_TYPE_CONFIG;
+ }
+#ifdef GRUB_MACHINE_EFI
+ else if (info->cmd_type == BLSUKI_UKI_CMD)
+ {
+ ext = ".efi";
+ ext_len = UKI_EXT_LEN;
+ file_type = GRUB_FILE_TYPE_EFI_CHAINLOADED_IMAGE;
+ }
+#endif
+
if (info->file != NULL)
f = info->file;
else
{
- if (filename_len < BLS_EXT_LEN ||
- grub_strcmp (filename + filename_len - BLS_EXT_LEN, ".conf") != 0)
+ if (filename_len < ext_len ||
+ grub_strcmp (filename + filename_len - ext_len, ext) != 0)
return 0;
p = grub_xasprintf ("(%s)%s/%s", info->devid, info->dirname, filename);
-
- f = grub_file_open (p, GRUB_FILE_TYPE_CONFIG);
+ f = grub_file_open (p, file_type);
grub_free (p);
if (f == NULL)
goto finish;
@@ -373,7 +612,26 @@ blsuki_read_entry (const char *filename,
goto finish;
}
- err = bls_parse_keyvals (f, entry);
+ entry->dirname = grub_strdup (info->dirname);
+ if (entry->dirname == NULL)
+ {
+ grub_free (entry);
+ goto finish;
+ }
+
+ entry->devid = grub_strdup (info->devid);
+ if (entry->devid == NULL)
+ {
+ grub_free (entry);
+ goto finish;
+ }
+
+ if (info->cmd_type == BLSUKI_BLS_CMD)
+ err = bls_parse_keyvals (f, entry);
+#ifdef GRUB_MACHINE_EFI
+ else if (info->cmd_type == BLSUKI_UKI_CMD)
+ err = uki_parse_keyvals (f, entry);
+#endif
if (err == GRUB_ERR_NONE)
blsuki_add_entry (entry);
@@ -389,7 +647,7 @@ blsuki_read_entry (const char *filename,
/*
* This function returns a list of values that had the same key in the BLS
- * config file. The number of entries in this list is returned by the len
+ * config file or UKI. The number of entries in this list is returned by the len
* parameter.
*/
static char **
@@ -764,7 +1022,7 @@ bls_create_entry (grub_blsuki_entry_t *entry)
linux_cmd, initrd_cmd ? initrd_cmd : "",
dt_cmd ? dt_cmd : "");
- grub_normal_add_menu_entry (argc, argv, classes, id, users, hotkey, NULL, src, 0, entry);
+ grub_normal_add_menu_entry (argc, argv, classes, id, users, hotkey, NULL, src, 0, NULL, NULL, entry);
finish:
grub_free (linux_cmd);
@@ -776,6 +1034,70 @@ bls_create_entry (grub_blsuki_entry_t *entry)
grub_free (src);
}
+#ifdef GRUB_MACHINE_EFI
+/*
+ * This function puts together the section data received from the UKI and
+ * generates a new entry in the GRUB boot menu.
+ */
+static void
+uki_create_entry (grub_blsuki_entry_t *entry)
+{
+ const char **argv = NULL;
+ char *id = entry->filename;
+ char *title = NULL;
+ char *options = NULL;
+ char *osrel, *osrel_line;
+ char *key = NULL;
+ char *value = NULL;
+ char *src = NULL;
+ bool blsuki_save_default;
+
+ /*
+ * Although .osrel is listed as optional in the UKI specification, the .osrel
+ * section is needed to generate the GRUB menu entry title.
+ */
+ osrel = blsuki_get_val (entry, ".osrel", NULL);
+ if (osrel == NULL)
+ {
+ grub_dprintf ("blsuki", "Skipping file %s with no '.osrel' key.\n", entry->filename);
+ goto finish;
+ }
+
+ osrel_line = osrel;
+ while ((key = uki_read_osrel (&osrel_line, &value)) != NULL)
+ {
+ if (grub_strcmp ("PRETTY_NAME", key) == 0)
+ {
+ title = value;
+ break;
+ }
+ }
+
+ options = blsuki_get_val (entry, ".cmdline", NULL);
+
+ argv = grub_zalloc (2 * sizeof (char *));
+ if (argv == NULL)
+ goto finish;
+ argv[0] = title;
+
+ blsuki_save_default = grub_env_get_bool ("blsuki_save_default", false);
+ src = grub_xasprintf ("%schainloader (%s)%s/%s%s%s\n",
+ blsuki_save_default ? "savedefault\n" : "",
+ entry->devid, entry->dirname,
+ entry->filename,
+ (options != NULL) ? " " : "",
+ (options != NULL) ? options : "");
+
+ grub_normal_add_menu_entry (1, argv, NULL, id, NULL, NULL, NULL, src, 0, NULL, NULL, entry);
+
+ finish:
+ grub_free (argv);
+ grub_free (src);
+ grub_free (options);
+ grub_free (osrel);
+}
+#endif
+
/*
* This function fills a find_entry_info struct passed in by the info parameter.
* If the dirname or devid parameters are set to NULL, the dirname and devid
@@ -785,7 +1107,7 @@ bls_create_entry (grub_blsuki_entry_t *entry)
* device.
*/
static grub_err_t
-blsuki_set_find_entry_info (struct find_entry_info *info, const char *dirname, const char *devid)
+blsuki_set_find_entry_info (struct find_entry_info *info, const char *dirname, const char *devid, enum blsuki_cmd_type cmd_type)
{
grub_device_t dev;
grub_fs_t fs;
@@ -795,10 +1117,23 @@ blsuki_set_find_entry_info (struct find_entry_info *info, const char *dirname, c
if (devid == NULL)
{
+ if (cmd_type == BLSUKI_BLS_CMD)
+ {
#ifdef GRUB_MACHINE_EMU
- devid = "host";
+ devid = "host";
#else
- devid = grub_env_get ("root");
+ devid = grub_env_get ("root");
+#endif
+ }
+#ifdef GRUB_MACHINE_EFI
+ else if (cmd_type == BLSUKI_UKI_CMD)
+ {
+ grub_efi_loaded_image_t *image = grub_efi_get_loaded_image (grub_efi_image_handle);
+
+ if (image == NULL)
+ return grub_error (GRUB_ERR_BAD_DEVICE, N_("unable to find boot device"));
+ devid = grub_efidisk_get_device_name (image->device_handle);
+ }
#endif
if (devid == NULL)
return grub_error (GRUB_ERR_FILE_NOT_FOUND, N_("variable '%s' isn't set"), "root");
@@ -837,15 +1172,16 @@ blsuki_set_find_entry_info (struct find_entry_info *info, const char *dirname, c
}
/*
- * This function searches for BLS config files based on the data in the info
- * parameter. If the fallback option is enabled, the default location will be
- * checked for BLS config files if the first attempt fails.
+ * This function searches for BLS config files and UKIs based on the data in the
+ * info parameter. If the fallback option is enabled, the default location will
+ * be checked for BLS config files or UKIs if the first attempt fails.
*/
static grub_err_t
-blsuki_find_entry (struct find_entry_info *info, bool enable_fallback)
+blsuki_find_entry (struct find_entry_info *info, bool enable_fallback, enum blsuki_cmd_type cmd_type)
{
struct read_entry_info read_entry_info;
char *default_dir = NULL;
+ const char *cmd_dir = NULL;
char *tmp;
grub_size_t default_size;
grub_fs_t dir_fs = NULL;
@@ -862,6 +1198,7 @@ blsuki_find_entry (struct find_entry_info *info, bool enable_fallback)
dir_dev = info->dev;
dir_fs = info->fs;
read_entry_info.devid = info->devid;
+ read_entry_info.cmd_type = cmd_type;
r = dir_fs->fs_dir (dir_dev, read_entry_info.dirname, blsuki_read_entry,
&read_entry_info);
@@ -874,19 +1211,27 @@ blsuki_find_entry (struct find_entry_info *info, bool enable_fallback)
/*
* If we aren't able to find BLS entries in the directory given by info->dirname,
* we can fallback to the default location "/boot/loader/entries/" and see if we
- * can find the files there.
+ * can find the files there. If we can't find UKI entries, fallback to
+ * "/EFI/Linux" on the EFI system partition.
*/
if (entries == NULL && fallback == false && enable_fallback == true)
{
- default_size = sizeof (GRUB_BOOT_DEVICE) + sizeof (GRUB_BLS_CONFIG_PATH) - 1;
+ if (cmd_type == BLSUKI_BLS_CMD)
+ cmd_dir = GRUB_BLS_CONFIG_PATH;
+#ifdef GRUB_MACHINE_EFI
+ else if (cmd_type == BLSUKI_UKI_CMD)
+ cmd_dir = GRUB_UKI_CONFIG_PATH;
+#endif
+
+ default_size = sizeof (GRUB_BOOT_DEVICE) + grub_strlen (cmd_dir);
default_dir = grub_malloc (default_size);
if (default_dir == NULL)
return grub_errno;
tmp = blsuki_update_boot_device (default_dir);
- tmp = grub_stpcpy (tmp, GRUB_BLS_CONFIG_PATH);
+ tmp = grub_stpcpy (tmp, cmd_dir);
- blsuki_set_find_entry_info (info, default_dir, NULL);
+ blsuki_set_find_entry_info (info, default_dir, NULL, cmd_type);
grub_dprintf ("blsuki", "Entries weren't found in %s, fallback to %s\n",
read_entry_info.dirname, info->dirname);
fallback = true;
@@ -901,15 +1246,17 @@ blsuki_find_entry (struct find_entry_info *info, bool enable_fallback)
}
static grub_err_t
-blsuki_load_entries (char *path, bool enable_fallback)
+blsuki_load_entries (char *path, bool enable_fallback, enum blsuki_cmd_type cmd_type)
{
- grub_size_t len;
+ grub_size_t len, ext_len = 0;
static grub_err_t r;
const char *devid = NULL;
char *dir = NULL;
char *default_dir = NULL;
char *tmp;
+ const char *cmd_dir = NULL;
grub_size_t dir_size;
+ const char *ext = NULL;
struct find_entry_info info = {
.dev = NULL,
.fs = NULL,
@@ -918,12 +1265,26 @@ blsuki_load_entries (char *path, bool enable_fallback)
struct read_entry_info rei = {
.devid = NULL,
.dirname = NULL,
+ .cmd_type = cmd_type,
};
if (path != NULL)
{
+ if (cmd_type == BLSUKI_BLS_CMD)
+ {
+ ext = ".conf";
+ ext_len = BLS_EXT_LEN;
+ }
+#ifdef GRUB_MACHINE_EFI
+ else if (cmd_type == BLSUKI_UKI_CMD)
+ {
+ ext = ".efi";
+ ext_len = UKI_EXT_LEN;
+ }
+#endif
+
len = grub_strlen (path);
- if (len >= BLS_EXT_LEN && grub_strcmp (path + len - BLS_EXT_LEN, ".conf") == 0)
+ if (len >= ext_len && grub_strcmp (path + len - ext_len, ext) == 0)
{
rei.file = grub_file_open (path, GRUB_FILE_TYPE_CONFIG);
if (rei.file == NULL)
@@ -952,19 +1313,26 @@ blsuki_load_entries (char *path, bool enable_fallback)
if (dir == NULL)
{
- dir_size = sizeof (GRUB_BOOT_DEVICE) + sizeof (GRUB_BLS_CONFIG_PATH) - 2;
+ if (cmd_type == BLSUKI_BLS_CMD)
+ cmd_dir = GRUB_BLS_CONFIG_PATH;
+#ifdef GRUB_MACHINE_EFI
+ else if (cmd_type == BLSUKI_UKI_CMD)
+ cmd_dir = GRUB_UKI_CONFIG_PATH;
+#endif
+
+ dir_size = sizeof (GRUB_BOOT_DEVICE) + grub_strlen (cmd_dir);
default_dir = grub_malloc (dir_size);
if (default_dir == NULL)
return grub_errno;
tmp = blsuki_update_boot_device (default_dir);
- tmp = grub_stpcpy (tmp, GRUB_BLS_CONFIG_PATH);
+ tmp = grub_stpcpy (tmp, cmd_dir);
dir = default_dir;
}
- r = blsuki_set_find_entry_info (&info, dir, devid);
+ r = blsuki_set_find_entry_info (&info, dir, devid, cmd_type);
if (r == GRUB_ERR_NONE)
- r = blsuki_find_entry (&info, enable_fallback);
+ r = blsuki_find_entry (&info, enable_fallback, cmd_type);
if (info.dev != NULL)
grub_device_close (info.dev);
@@ -1002,11 +1370,11 @@ blsuki_is_default_entry (const char *def_entry, grub_blsuki_entry_t *entry, int
}
/*
- * This function creates a GRUB boot menu entry for each BLS entry in the
- * entries list.
+ * This function creates a GRUB boot menu entry for each BLS or UKI entry in
+ * the entries list.
*/
static grub_err_t
-blsuki_create_entries (bool show_default, bool show_non_default, char *entry_id)
+blsuki_create_entries (bool show_default, bool show_non_default, char *entry_id, enum blsuki_cmd_type cmd_type)
{
const char *def_entry = NULL;
grub_blsuki_entry_t *entry = NULL;
@@ -1025,7 +1393,12 @@ blsuki_create_entries (bool show_default, bool show_non_default, char *entry_id)
(show_non_default == true && blsuki_is_default_entry (def_entry, entry, idx) == false) ||
(entry_id != NULL && grub_strcmp (entry_id, entry->filename) == 0))
{
- bls_create_entry (entry);
+ if (cmd_type == BLSUKI_BLS_CMD)
+ bls_create_entry (entry);
+#ifdef GRUB_MACHINE_EFI
+ else if (cmd_type == BLSUKI_UKI_CMD)
+ uki_create_entry (entry);
+#endif
entry->visible = true;
}
@@ -1036,8 +1409,7 @@ blsuki_create_entries (bool show_default, bool show_non_default, char *entry_id)
}
static grub_err_t
-grub_cmd_blscfg (grub_extcmd_context_t ctxt, int argc __attribute__ ((unused)),
- char **args __attribute__ ((unused)))
+blsuki_cmd (grub_extcmd_context_t ctxt, enum blsuki_cmd_type cmd_type)
{
grub_err_t err;
struct grub_arg_list *state = ctxt->state;
@@ -1074,24 +1446,50 @@ grub_cmd_blscfg (grub_extcmd_context_t ctxt, int argc __attribute__ ((unused)),
show_non_default = true;
}
- err = blsuki_load_entries (path, enable_fallback);
+ err = blsuki_load_entries (path, enable_fallback, cmd_type);
if (err != GRUB_ERR_NONE)
return err;
- return blsuki_create_entries (show_default, show_non_default, entry_id);
+ return blsuki_create_entries (show_default, show_non_default, entry_id, cmd_type);
+}
+
+static grub_err_t
+grub_cmd_blscfg (grub_extcmd_context_t ctxt, int argc __attribute__ ((unused)),
+ char **args __attribute__ ((unused)))
+{
+ return blsuki_cmd (ctxt, BLSUKI_BLS_CMD);
}
static grub_extcmd_t bls_cmd;
+#ifdef GRUB_MACHINE_EFI
+static grub_err_t
+grub_cmd_uki (grub_extcmd_context_t ctxt, int argc __attribute__ ((unused)),
+ char **args __attribute__ ((unused)))
+{
+ return blsuki_cmd (ctxt, BLSUKI_UKI_CMD);
+}
+
+static grub_extcmd_t uki_cmd;
+#endif
+
GRUB_MOD_INIT(blsuki)
{
bls_cmd = grub_register_extcmd ("blscfg", grub_cmd_blscfg, 0,
N_("[-p|--path] [-f|--enable-fallback] DIR [-d|--show-default] [-n|--show-non-default] [-e|--entry] FILE"),
N_("Import Boot Loader Specification snippets."),
bls_opt);
+#ifdef GRUB_MACHINE_EFI
+ uki_cmd = grub_register_extcmd ("uki", grub_cmd_uki, 0,
+ N_("[-p|--path] DIR [-f|--enable-fallback] [-d|--show-default] [-n|--show-non-default] [-e|--entry] FILE"),
+ N_("Import Unified Kernel Images"), uki_opt);
+#endif
}
GRUB_MOD_FINI(blsuki)
{
grub_unregister_extcmd (bls_cmd);
+#ifdef GRUB_MACHINE_EFI
+ grub_unregister_extcmd (uki_cmd);
+#endif
}
diff --git a/include/grub/menu.h b/include/grub/menu.h
index 43a3c5809b..0e4978dc3b 100644
--- a/include/grub/menu.h
+++ b/include/grub/menu.h
@@ -39,6 +39,8 @@ struct grub_blsuki_entry
grub_size_t keyvals_size;
int nkeyvals;
char *filename;
+ char *dirname;
+ char *devid;
bool visible;
};
typedef struct grub_blsuki_entry grub_blsuki_entry_t;

View File

@ -0,0 +1,168 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Daniel Axtens <dja@axtens.net>
Date: Fri, 15 Nov 2024 15:34:29 +0800
Subject: [PATCH] posix_wrap: Tweaks in preparation for libtasn1
Cc: Vladimir Serbinenko <phcoder@gmail.com>
Signed-off-by: Daniel Axtens <dja@axtens.net>
Signed-off-by: Gary Lin <glin@suse.com>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
Tested-by: Stefan Berger <stefanb@linux.ibm.com>
---
grub-core/lib/posix_wrap/c-ctype.h | 114 +++++++++++++++++++++++++++++++++++++
grub-core/lib/posix_wrap/string.h | 21 +++++++
2 files changed, 135 insertions(+)
create mode 100644 grub-core/lib/posix_wrap/c-ctype.h
diff --git a/grub-core/lib/posix_wrap/c-ctype.h b/grub-core/lib/posix_wrap/c-ctype.h
new file mode 100644
index 0000000000..5f8fc8ce3f
--- /dev/null
+++ b/grub-core/lib/posix_wrap/c-ctype.h
@@ -0,0 +1,114 @@
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2024 Free Software Foundation, Inc.
+ *
+ * GRUB is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GRUB is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GRUB. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef GRUB_POSIX_C_CTYPE_H
+#define GRUB_POSIX_C_CTYPE_H 1
+
+#include <grub/misc.h>
+
+static inline bool
+c_isspace (int c)
+{
+ return !!grub_isspace (c);
+}
+
+static inline bool
+c_isdigit (int c)
+{
+ return !!grub_isdigit (c);
+}
+
+static inline bool
+c_islower (int c)
+{
+ return !!grub_islower (c);
+}
+
+static inline bool
+c_isascii (int c)
+{
+ return !(c & ~0x7f);
+}
+
+static inline bool
+c_isupper (int c)
+{
+ return !!grub_isupper (c);
+}
+
+static inline bool
+c_isxdigit (int c)
+{
+ return !!grub_isxdigit (c);
+}
+
+static inline bool
+c_isprint (int c)
+{
+ return !!grub_isprint (c);
+}
+
+static inline bool
+c_iscntrl (int c)
+{
+ return !grub_isprint (c);
+}
+
+static inline bool
+c_isgraph (int c)
+{
+ return grub_isprint (c) && !grub_isspace (c);
+}
+
+static inline bool
+c_isalnum (int c)
+{
+ return grub_isalpha (c) || grub_isdigit (c);
+}
+
+static inline bool
+c_ispunct (int c)
+{
+ return grub_isprint (c) && !grub_isspace (c) && !c_isalnum (c);
+}
+
+static inline bool
+c_isalpha (int c)
+{
+ return !!grub_isalpha (c);
+}
+
+static inline bool
+c_isblank (int c)
+{
+ return c == ' ' || c == '\t';
+}
+
+static inline int
+c_tolower (int c)
+{
+ return grub_tolower (c);
+}
+
+static inline int
+c_toupper (int c)
+{
+ return grub_toupper (c);
+}
+
+#endif
diff --git a/grub-core/lib/posix_wrap/string.h b/grub-core/lib/posix_wrap/string.h
index 1adb450b5a..d3e400d500 100644
--- a/grub-core/lib/posix_wrap/string.h
+++ b/grub-core/lib/posix_wrap/string.h
@@ -84,6 +84,27 @@ memchr (const void *s, int c, grub_size_t n)
return grub_memchr (s, c, n);
}
+static inline char *
+strncat (char *dest, const char *src, grub_size_t n)
+{
+ const char *end;
+ char *str = dest;
+ grub_size_t src_len;
+
+ dest += grub_strlen (dest);
+
+ end = grub_memchr (src, '\0', n);
+ if (end != NULL)
+ src_len = (grub_size_t) (end - src);
+ else
+ src_len = n;
+
+ dest[src_len] = '\0';
+ grub_memcpy (dest, src, src_len);
+
+ return str;
+}
+
#define memcmp grub_memcmp
#define memcpy grub_memcpy
#define memmove grub_memmove

View File

@ -0,0 +1,43 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Leo Sandoval <lsandova@redhat.com>
Date: Thu, 13 Nov 2025 11:57:52 -0600
Subject: [PATCH] blsuki: do not register blscfg command
The blscfg command is already defined on commands/blscfg.c so do not
register it on blsuki.c. Also, the 'uki' command is only intended for
EFI system so remove the other platforms from the module.
Signed-off-by: Leo Sandoval <lsandova@redhat.com>
---
grub-core/Makefile.core.def | 2 --
grub-core/commands/blsuki.c | 4 ----
2 files changed, 6 deletions(-)
diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def
index ddc5e71bbb..4677c843a0 100644
--- a/grub-core/Makefile.core.def
+++ b/grub-core/Makefile.core.def
@@ -893,8 +893,6 @@ module = {
common = lib/gnulib/filevercmp.c;
enable = powerpc_ieee1275;
enable = efi;
- enable = i386_pc;
- enable = emu;
cflags = '$(CFLAGS_POSIX) $(CFLAGS_GNULIB)';
cppflags = '$(CPPFLAGS_POSIX) $(CPPFLAGS_GNULIB)';
};
diff --git a/grub-core/commands/blsuki.c b/grub-core/commands/blsuki.c
index cb00f936a7..bcd0114d85 100644
--- a/grub-core/commands/blsuki.c
+++ b/grub-core/commands/blsuki.c
@@ -1475,10 +1475,6 @@ static grub_extcmd_t uki_cmd;
GRUB_MOD_INIT(blsuki)
{
- bls_cmd = grub_register_extcmd ("blscfg", grub_cmd_blscfg, 0,
- N_("[-p|--path] [-f|--enable-fallback] DIR [-d|--show-default] [-n|--show-non-default] [-e|--entry] FILE"),
- N_("Import Boot Loader Specification snippets."),
- bls_opt);
#ifdef GRUB_MACHINE_EFI
uki_cmd = grub_register_extcmd ("uki", grub_cmd_uki, 0,
N_("[-p|--path] DIR [-f|--enable-fallback] [-d|--show-default] [-n|--show-non-default] [-e|--entry] FILE"),

View File

@ -0,0 +1,31 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Thomas Frauendorfer | Miray Software <tf@miray.de>
Date: Fri, 9 May 2025 13:51:08 +0200
Subject: [PATCH] commands/test: Fix error in recursion depth calculation
The commit c68b7d236 (commands/test: Stack overflow due to unlimited
recursion depth) added recursion depth tests to the test command. But in
the error case it decrements the pointer to the depth value instead of
the value itself. Fix it.
Fixes: c68b7d236 (commands/test: Stack overflow due to unlimited recursion depth)
Signed-off-by: Thomas Frauendorfer | Miray Software <tf@miray.de>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
---
grub-core/commands/test.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/grub-core/commands/test.c b/grub-core/commands/test.c
index b585c3d70316..ee47ab2641a6 100644
--- a/grub-core/commands/test.c
+++ b/grub-core/commands/test.c
@@ -403,7 +403,7 @@ test_parse (char **args, int *argn, int argc, int *depth)
if (++(*depth) > MAX_TEST_RECURSION_DEPTH)
{
grub_error (GRUB_ERR_OUT_OF_RANGE, N_("max recursion depth exceeded"));
- depth--;
+ (*depth)--;
return ctx.or || ctx.and;
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -0,0 +1,29 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Jamie <volticks@gmail.com>
Date: Mon, 14 Jul 2025 10:07:47 +0100
Subject: [PATCH] commands/usbtest: Ensure string length is sufficient in usb
string processing
If descstrp->length is less than 2 this will result in underflow in
"descstrp->length / 2 - 1" math. Let's fix the check to make sure the
value is sufficient.
Signed-off-by: Jamie <volticks@gmail.com>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
---
grub-core/commands/usbtest.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/grub-core/commands/usbtest.c b/grub-core/commands/usbtest.c
index 8ef187a9ae76..3184ac9afd37 100644
--- a/grub-core/commands/usbtest.c
+++ b/grub-core/commands/usbtest.c
@@ -90,7 +90,7 @@ grub_usb_get_string (grub_usb_device_t dev, grub_uint8_t index, int langid,
0x06, (3 << 8) | index,
langid, descstr.length, (char *) descstrp);
- if (descstrp->length == 0)
+ if (descstrp->length < 2)
{
grub_free (descstrp);
*string = grub_strdup ("");

View File

@ -0,0 +1,24 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Leo Sandoval <lsandova@redhat.com>
Date: Wed, 11 Feb 2026 15:12:10 -0600
Subject: [PATCH] commands/search.c: check possible NULL pointer before
dereference
Signed-off-by: Leo Sandoval <lsandova@redhat.com>
---
grub-core/commands/search.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/grub-core/commands/search.c b/grub-core/commands/search.c
index 9dd937e6df..4677f009cd 100644
--- a/grub-core/commands/search.c
+++ b/grub-core/commands/search.c
@@ -213,7 +213,7 @@ iterate_device (const char *name, void *data)
int ret = 0;
get_device_uuid(name, &quid_name);
- if (!grub_strcmp(quid_name, ctx->key))
+ if (quid_name && !grub_strcmp(quid_name, ctx->key))
{
uuid_ctx.name = name;
uuid_ctx.uuid = quid_name;

View File

@ -0,0 +1,81 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Sudhakar Kuppusamy <sudhakar@linux.ibm.com>
Date: Fri, 2 Jan 2026 16:13:13 +0530
Subject: [PATCH] util/grub-mkimagexx: Stop generating unaligned appended
signatures
When creating the core image with an unaligned appended signature size,
e.g. 479, for PowerPC, the grub-mkimage aligns the appended signature
size to a multiple of 4 bytes, but it does not add a padding needed to
align to multiple of 4 bytes appended signature size in the appended
signature ELF note. Therefore, after signing and installing this core
image, the firmware tries to read the magic string "~Module signature
appended~" from the appended signature ELF note but gets the partial
magic string like "Module signature appended~". It leads to the appended
signature magic string match failure.
Example:
grub-mkimage -O powerpc-ieee1275 -o core.elf -p /grub -x \
kernel.der --appended-signature-size 479 ...
sign-file SHA256 ./grub.key ./grub.pem ./core.elf ./core.elf.signed
Without padding: hexdump -C ./core.elf.signed
...
00383550 00 00 00 13 00 00 01 e0 41 53 69 67 41 70 70 65 |........ASigAppe|
00383560 6e 64 65 64 2d 53 69 67 6e 61 74 75 72 65 00 00 |nded-Signature..|
...
003836f0 dd 47 cd ed 02 8e 15 af 5b 09 2e 44 6f da 67 88 |.G......[..Do.g.|
00383700 4d 94 17 31 26 9d 47 95 d8 7c ad 36 00 d2 9c 53 |M..1&.G..|.6...S|
00383710 20 e0 af 60 78 cd 22 e6 ed 45 1e b1 e7 7e cf b5 | ..`x."..E...~..|
00383720 fc 58 ec df 1b ab 7a 00 00 02 00 00 00 00 00 00 |.X....z.........|
00383730 00 01 b7 7e 4d 6f 64 75 6c 65 20 73 69 67 6e 61 |...~Module signa|
00383740 74 75 72 65 20 61 70 70 65 6e 64 65 64 7e 0a |ture appended~.|
Fix this by adding a padding required to align appended signature size in the
appended signature ELF note to multiple of 4 bytes.
Example:
grub-mkimage -O powerpc-ieee1275 -o core.elf -p /grub -x \
kernel.der --appended-signature-size 479 ...
sign-file SHA256 ./grub.key ./grub.pem ./core.elf ./core.elf.signed
With padding: hexdump -C ./core.elf.signed
...
00137460 62 00 00 00 00 00 00 13 00 00 01 ec 41 53 69 67 |b...........ASig|
00137470 41 70 70 65 6e 64 65 64 2d 53 69 67 6e 61 74 75 |Appended-Signatu|
...
00137610 b7 07 cd b6 c8 ca 9a 5b 7c 13 8c 75 1d 1c 54 81 |.......[|..u..T.|
00137620 7f c4 9a 8b bd d7 73 8d 2f 7d d2 e6 d1 3c 52 a9 |......s./}...<R.|
00137630 4e 0b e5 24 ba 0a 82 aa 8e c5 86 fa e1 19 50 ec |N..$..........P.|
00137640 9f a7 9a ed e5 ed 13 35 00 00 02 00 00 00 00 00 |.......5........|
00137650 00 00 01 c2 7e 4d 6f 64 75 6c 65 20 73 69 67 6e |....~Module sign|
00137660 61 74 75 72 65 20 61 70 70 65 6e 64 65 64 7e 0a |ature appended~.|
Signed-off-by: Sudhakar Kuppusamy <sudhakar@linux.ibm.com>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
---
util/grub-mkimagexx.c | 9 ++-------
1 file changed, 2 insertions(+), 7 deletions(-)
diff --git a/util/grub-mkimagexx.c b/util/grub-mkimagexx.c
index c99c7f99c787..debd984ad51d 100644
--- a/util/grub-mkimagexx.c
+++ b/util/grub-mkimagexx.c
@@ -248,13 +248,8 @@ SUFFIX (grub_mkimage_generate_elf) (const struct grub_install_image_target_desc
if (appsig_size)
{
phnum++;
- /*
- * Rounds a appended signature size + appended signature note size up to
- * the nearest multiple of a 4-byte alignment.
- */
- footer_size += ALIGN_UP (sizeof (struct grub_appended_signature_note) + appsig_size, 4);
- /* Truncating to appended signature size. */
- footer_size -= appsig_size;
+ footer_size += ALIGN_UP (sizeof (struct grub_appended_signature_note), 4);
+ footer_size += ALIGN_UP_OVERHEAD (appsig_size, 4);
}
if (image_target->id != IMAGE_LOONGSON_ELF)

View File

@ -0,0 +1,61 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Sudhakar Kuppusamy <sudhakar@linux.ibm.com>
Date: Wed, 24 Dec 2025 17:58:59 +0530
Subject: [PATCH] grub-mkimage: Do not generate empty SBAT metadata
When creating core.elf with SBAT the grub-mkimage does not check if
an SBAT metadata file contains at least an SBAT header or not. It leads to
adding an empty SBAT ELF note for PowerPC and the .sbat section for EFI.
Fix this by checking the SBAT metadata file size against the SBAT header
size before adding SBAT contents to the ELF note or .sbat section.
Signed-off-by: Sudhakar Kuppusamy <sudhakar@linux.ibm.com>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
---
util/mkimage.c | 12 ++++++++++--
1 file changed, 10 insertions(+), 2 deletions(-)
diff --git a/util/mkimage.c b/util/mkimage.c
index 5124cdbf4d01..b2c2b93ef932 100644
--- a/util/mkimage.c
+++ b/util/mkimage.c
@@ -56,6 +56,9 @@
#pragma GCC diagnostic ignored "-Wcast-align"
+#define SBAT_HEADER "sbat,1,SBAT Version,sbat,1,https://github.com/rhboot/shim/blob/main/SBAT.md"
+#define SBAT_HEADER_SIZE (sizeof (SBAT_HEADER))
+
#define TARGET_NO_FIELD 0xffffffff
/* use 2015-01-01T00:00:00+0000 as a stock timestamp */
@@ -963,6 +966,12 @@ grub_install_generate_image (const char *dir, const char *prefix,
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"));
+ else if (sbat_path != NULL)
+ {
+ sbat_size = grub_util_get_image_size (sbat_path);
+ if (sbat_size < SBAT_HEADER_SIZE)
+ grub_util_error (_("%s file should contain at least an SBAT header"), sbat_path);
+ }
if (appsig_size != 0 && image_target->id != IMAGE_PPC)
grub_util_error (_("appended signature can be support only to powerpc-ieee1275 images"));
@@ -1396,7 +1405,7 @@ grub_install_generate_image (const char *dir, const char *prefix,
if (sbat_path != NULL)
{
- sbat_size = ALIGN_ADDR (grub_util_get_image_size (sbat_path));
+ sbat_size = ALIGN_ADDR (sbat_size);
sbat_size = ALIGN_UP (sbat_size, GRUB_PE32_FILE_ALIGNMENT);
}
@@ -1857,7 +1866,6 @@ grub_install_generate_image (const char *dir, const char *prefix,
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;

View File

@ -0,0 +1,72 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Mate Kukri <mate.kukri@canonical.com>
Date: Wed, 12 Jun 2024 16:10:49 +0100
Subject: [PATCH] kern/efi/mm: Change grub_efi_mm_add_regions() to keep track
of map allocation size
If the map was too big for the initial allocation, it was freed and replaced
with a bigger one, but the free call still used the hard-coded size.
Seems like this wasn't hit for a long time, because most firmware maps
fit into 12K.
This bug was triggered on Project Mu firmware with a big memory map, and
results in the heap getting trashed and the firmware ASSERTING on
corrupted heap guard values when GRUB exits.
Signed-off-by: Mate Kukri <mate.kukri@canonical.com>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
---
grub-core/kern/efi/mm.c | 14 +++++++-------
1 file changed, 7 insertions(+), 7 deletions(-)
diff --git a/grub-core/kern/efi/mm.c b/grub-core/kern/efi/mm.c
index 464fe1c3c..e37af445e 100644
--- a/grub-core/kern/efi/mm.c
+++ b/grub-core/kern/efi/mm.c
@@ -687,6 +687,7 @@ grub_efi_mm_add_regions (grub_size_t required_bytes, unsigned int flags)
grub_efi_memory_descriptor_t *memory_map_end;
grub_efi_memory_descriptor_t *filtered_memory_map;
grub_efi_memory_descriptor_t *filtered_memory_map_end;
+ grub_efi_uintn_t alloc_size;
grub_efi_uintn_t map_size;
grub_efi_uintn_t desc_size;
grub_err_t err;
@@ -695,7 +696,8 @@ grub_efi_mm_add_regions (grub_size_t required_bytes, unsigned int flags)
grub_nx_init ();
/* Prepare a memory region to store two memory maps. */
- memory_map = grub_efi_allocate_any_pages (2 * BYTES_TO_PAGES (MEMORY_MAP_SIZE));
+ alloc_size = 2 * BYTES_TO_PAGES (MEMORY_MAP_SIZE);
+ memory_map = grub_efi_allocate_any_pages (alloc_size);
if (! memory_map)
return grub_error (GRUB_ERR_OUT_OF_MEMORY, "cannot allocate memory for memory map");
@@ -706,14 +708,13 @@ grub_efi_mm_add_regions (grub_size_t required_bytes, unsigned int flags)
if (mm_status == 0)
{
- grub_efi_free_pages
- ((grub_efi_physical_address_t) ((grub_addr_t) memory_map),
- 2 * BYTES_TO_PAGES (MEMORY_MAP_SIZE));
+ grub_efi_free_pages ((grub_efi_physical_address_t)(grub_addr_t) memory_map, alloc_size);
/* Freeing/allocating operations may increase memory map size. */
map_size += desc_size * 32;
- memory_map = grub_efi_allocate_any_pages (2 * BYTES_TO_PAGES (map_size));
+ alloc_size = 2 * BYTES_TO_PAGES (map_size);
+ memory_map = grub_efi_allocate_any_pages (alloc_size);
if (! memory_map)
return grub_error (GRUB_ERR_OUT_OF_MEMORY, "cannot allocate memory for new memory map");
@@ -757,8 +758,7 @@ grub_efi_mm_add_regions (grub_size_t required_bytes, unsigned int flags)
#endif
/* Release the memory maps. */
- grub_efi_free_pages ((grub_addr_t) memory_map,
- 2 * BYTES_TO_PAGES (MEMORY_MAP_SIZE));
+ grub_efi_free_pages ((grub_efi_physical_address_t)(grub_addr_t) memory_map, alloc_size);
return GRUB_ERR_NONE;
}

View File

@ -186,6 +186,12 @@ case "$COMMAND" in
;;
remove)
# If the boot entry type is type2, we are not removing the BLS entry
if [[ "x${KERNEL_INSTALL_BOOT_ENTRY_TYPE}" = "xtype2" ]]; then
[ "${KERNEL_INSTALL_VERBOSE}" -gt 0 ] && echo "The boot entry type is type2. Skip removing BLS entry."
exit 0
fi
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"

View File

@ -4,6 +4,12 @@ if ! [[ $KERNEL_INSTALL_MACHINE_ID ]]; then
exit 0
fi
# Run grub2-mkconfig if ENABLE_BLSCFG is false
if grep -s -q '^GRUB_ENABLE_BLSCFG="*false"*\s*$' /etc/default/grub; then
RUN_MKCONFIG=true
DISABLE_BLS=true
fi
# PV and PVH Xen DomU guests boot with pygrub that doesn't have BLS support,
# also Xen Dom0 use the menuentries from 20_linux_xen and not the ones from
# 10_linux. So BLS support needs to be disabled for both Xen Dom0 and DomU.

29
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

@ -401,7 +401,7 @@ install -m 644 %{1}.conf ${RPM_BUILD_ROOT}/etc/dnf/protected.d/ \
rm -f %{1}.conf \
%{nil}
%global grub_modules " all_video boot blscfg \\\
%global grub_modules " all_video boot blscfg blsuki \\\
cat configfile cryptodisk \\\
echo ext2 f2fs fat font \\\
gcry_rijndael gcry_rsa gcry_serpent \\\
@ -469,6 +469,7 @@ if [ -x /usr/bin/rpm-sign ]; then \
fi \
# FIXME: using this prefix is fragile, must be done properly \
./grub-mkimage -O %{1} -o %{2}.orig \\\
-s %{SOURCE14} \\\
-d grub-core \\\
-m memdisk.squashfs \\\
-p '/grub2' \\\
@ -476,7 +477,6 @@ fi \
--appended-signature-size ${APPENDED_SIG_SIZE} \\\
${GRUB_MODULES} \
if [ -x /usr/bin/rpm-sign ]; then \
truncate -s -${APPENDED_SIG_SIZE} %{2}.orig \
rpm-sign --key %{4} \\\
--lkmsign %{2}.orig \\\
--output %{2} \
@ -597,6 +597,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/grub2/fonts/unicode.pf2 \
${RPM_BUILD_ROOT}/%{_bindir}/grub2-editenv \\\
@ -720,6 +722,7 @@ ln -s ../boot/grub2/grub.cfg \\\
%attr(0700,root,root) %verify(not mtime) %{efi_esp_boot}/BOOTARM.EFI \
%endif \
%attr(0700,root,root)/boot/grub2/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/grub2/grub.cfg \
%ghost %config(noreplace) %verify(not mtime) %attr(0700,root,root)%{efi_esp_dir}/grub.cfg \

View File

@ -358,3 +358,71 @@ Patch0358: 0358-loader-i386-linux-Cast-left-shift-to-grub_uint32_t.patch
Patch0359: 0359-loader-i386-bsd-Use-safe-math-to-avoid-underflow.patch
Patch0360: 0360-fs-ext2-Rework-out-of-bounds-read-for-inline-and-ext.patch
Patch0361: 0361-powerpc-increase-MIN-RMA-size-for-CAS-negotiation.patch
Patch0362: 0362-ieee1275-ofnet-Fix-grub_malloc-removed-after-added-s.patch
Patch0363: 0363-grub-mkimage-Create-new-ELF-note-for-SBAT.patch
Patch0364: 0364-grub-mkimage-Add-SBAT-metadata-into-ELF-note-for-Pow.patch
Patch0365: 0365-loader-efi-Fix-RISC-V-build.patch
Patch0366: 0366-kern-riscv-efi-init-Use-time-register-in-grub_efi_ge.patch
Patch0367: 0367-Use-medany-instead-of-large-model-for-RISCV.patch
Patch0368: 0368-10_linux.in-escape-kernel-option-characters-properly.patch
Patch0369: 0369-blscfg-check-if-variable-is-escaped-before-consideri.patch
Patch0370: 0370-Set-correctly-the-memory-attributes-for-the-kernel-P.patch
Patch0371: 0371-script-execute-Don-t-let-trailing-blank-lines-determ.patch
Patch0372: 0372-normal-menu-Check-return-code-of-the-script-when-exe.patch
Patch0373: 0373-Include-license-into-grub-set-password-util.patch
Patch0374: 0374-libgcrypt-Import-libgcrypt-1.11.patch
Patch0375: 0375-b64dec-Import-b64dec-from-gpg-error.patch
Patch0376: 0376-b64dec-Add-harness-for-compilation-in-GRUB-environme.patch
Patch0377: 0377-libgcrypt-Adjust-import-script-definitions-and-API-u.patch
Patch0378: 0378-tests-Add-DSA-and-RSA-SEXP-tests.patch
Patch0379: 0379-keccak-Disable-acceleration-with-SSE-asm.patch
Patch0380: 0380-libgcrypt-Fix-Coverity-warnings.patch
Patch0381: 0381-libgcrypt-Remove-now-unneeded-compilation-flag.patch
Patch0382: 0382-libgcrypt-Ignore-sign-compare-warnings.patch
Patch0383: 0383-libgcrypt-Import-blake-family-of-hashes.patch
Patch0384: 0384-util-import_gcry-Make-compatible-with-Python-3.4.patch
Patch0385: 0385-util-import_gcry-Fix-pylint-warnings.patch
Patch0386: 0386-libgcrypt-Don-t-use-64-bit-division-on-platforms-whe.patch
Patch0387: 0387-libgcrypt-Fix-a-memory-leak.patch
Patch0388: 0388-docs-Write-how-to-import-new-libgcrypt.patch
Patch0389: 0389-pgp-Rename-OBJ_TYPE_PUBKEY-to-OBJ_TYPE_GPG_PUBKEY.patch
Patch0390: 0390-grub-install-Support-embedding-x509-certificates.patch
Patch0391: 0391-appended-signatures-Import-GNUTLS-s-ASN.1-descriptio.patch
Patch0392: 0392-appended-signatures-Parse-ASN1-node.patch
Patch0393: 0393-appended-signatures-Parse-PKCS-7-signed-data.patch
Patch0394: 0394-appended-signatures-Parse-X.509-certificates.patch
Patch0395: 0395-powerpc-ieee1275-Enter-lockdown-based-on-ibm-secure-.patch
Patch0396: 0396-appended-signatures-Support-verifying-appended-signa.patch
Patch0397: 0397-powerpc-ieee1275-Read-the-db-and-dbx-secure-boot-var.patch
Patch0398: 0398-appended-signatures-Introducing-key-management-envir.patch
Patch0399: 0399-appended-signatures-Create-db-and-dbx-lists.patch
Patch0400: 0400-appended-signatures-Using-db-and-dbx-lists-for-signa.patch
Patch0401: 0401-appended-signatures-GRUB-commands-to-manage-the-cert.patch
Patch0402: 0402-appended-signatures-GRUB-commands-to-manage-the-hash.patch
Patch0403: 0403-appended-signatures-Verification-tests.patch
Patch0404: 0404-docs-grub-Document-signing-GRUB-under-UEFI.patch
Patch0405: 0405-docs-grub-Document-signing-GRUB-with-an-appended-sig.patch
Patch0406: 0406-docs-grub-Document-appended-signature.patch
Patch0407: 0407-libtasn1-Fix-include-path-for-grub.patch
Patch0408: 0408-docs-fix-duplicated-entries.patch
Patch0409: 0409-powerpc-ieee1275-Add-support-for-signing-GRUB-with-a.patch
Patch0410: 0410-appendedsig-Fix-grub-mkimage-with-an-unaligned-appen.patch
Patch0411: 0411-kern-misc-Implement-grub_strtok.patch
Patch0412: 0412-blsuki-Add-blscfg-command-to-parse-Boot-Loader-Speci.patch
Patch0413: 0413-util-misc.c-Change-offset-type-for-grub_util_write_i.patch
Patch0414: 0414-blsuki-Check-for-mounted-boot-in-emu.patch
Patch0415: 0415-blsuki-Add-uki-command-to-load-Unified-Kernel-Image-.patch
Patch0416: 0416-posix_wrap-Tweaks-in-preparation-for-libtasn1.patch
Patch0417: 0417-blsuki-do-not-register-blscfg-command.patch
Patch0418: 0418-commands-test-Fix-error-in-recursion-depth-calculati.patch
Patch0419: 0419-kern-file-Call-grub_dl_unref-after-fs-fs_close.patch
Patch0420: 0420-net-net-Unregister-net_set_vlan-command-on-unload.patch
Patch0421: 0421-gettext-gettext-Unregister-gettext-command-on-module.patch
Patch0422: 0422-normal-main-Unregister-commands-on-module-unload.patch
Patch0423: 0423-tests-lib-functional_test-Unregister-commands-on-mod.patch
Patch0424: 0424-commands-usbtest-Use-correct-string-length-field.patch
Patch0425: 0425-commands-usbtest-Ensure-string-length-is-sufficient-.patch
Patch0426: 0426-commands-search.c-check-possible-NULL-pointer-before.patch
Patch0427: 0427-util-grub-mkimagexx-Stop-generating-unaligned-append.patch
Patch0428: 0428-grub-mkimage-Do-not-generate-empty-SBAT-metadata.patch
Patch0429: 0429-kern-efi-mm-Change-grub_efi_mm_add_regions-to-keep-t.patch

View File

@ -17,7 +17,7 @@
Name: grub2
Epoch: 1
Version: 2.12
Release: 13%{?dist}
Release: 44%{?dist}
Summary: Bootloader with support for Linux, Multiboot and more
License: GPL-3.0-or-later
URL: http://www.gnu.org/software/grub/
@ -35,13 +35,19 @@ Source9: strtoull_test.c
Source10: 20-grub.install
Source11: grub.patches
Source12: sbat.csv.in
Source13: gen_grub_cfgstub
Source14: sbat.ppc.csv
%include %{SOURCE1}
%ifarch x86_64 aarch64 ppc64le
%ifarch x86_64 aarch64
%define sb_ca %{_datadir}/pki/sb-certs/secureboot-ca-%{_arch}.cer
%define sb_cer %{_datadir}/pki/sb-certs/secureboot-grub2-%{_arch}.cer
%endif
%ifarch ppc64le
%define sb_ca %{_datadir}/pki/sb-certs/secureboot-ca-%{_arch}.cer
%define sb_cer %{_datadir}/pki/sb-certs/secureboot-kernel-%{_arch}.cer
%endif
%if 0%{?centos}
@ -50,7 +56,7 @@ Source12: sbat.csv.in
%endif
%else
%ifarch x86_64 aarch64
%define sb_key redhatsecureboot502
%define sb_key redhatsecureboot802
%endif
%ifarch ppc64le
%define sb_key redhatsecureboot702
@ -395,23 +401,13 @@ if test -f ${EFI_HOME}/grub.cfg; then
fi
# create a stub grub2 config in EFI
BOOT_UUID=$(grub2-probe --target=fs_uuid ${GRUB_HOME})
GRUB_DIR=$(grub2-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/
@ -583,6 +579,133 @@ mv ${EFI_HOME}/grub.cfg.stb ${EFI_HOME}/grub.cfg
%endif
%changelog
* Mon Mar 09 2026 Josue Hernandez <josherna@redhat.com> 2.12-44
- kern/efi/mm: Change grub_efi_mm_add_regions() to keep track of map allocation size
- Resolves: #RHEL-148309
* Mon Mar 09 2026 Nicolas Frayer <nfrayer@redhat.com> 2.12-43
- Bump release
- Related: #RHEL-146590
* Thu Feb 26 2026 Nicolas Frayer <nfrayer@redhat.com> 2.12-42
- ppc64le/sbat: Add an sbat CSV file for ppc64le
- Resolves: #RHEL-146590
* Fri Feb 13 2026 Marta Lewandowska <mlewando@redhat.com> 2.12-41
- ppc64le: Pointing to the right cert after redhat-release change
- Related: #RHEL-24510
* Fri Feb 13 2026 Nicolas Frayer <nfrayer@redhat.com> - 2.12-40
- ppc/mkimage/appendedsig: Upstream code sync for alignment and sbat
- Related: #RHEL-24510
* Wed Feb 11 2026 Leo Sandoval <lsandova@redhat.com> - 2.12-39
- commands/search.c: check possible NULL pointer before dereference
- Resolves: #RHEL-146317
* Wed Feb 4 2026 Nicolas Frayer <nfrayer@redhat.com> - 2.12-38
- Fix several security issues about module unloading and file handling
- Resolves: #RHEL-141581
- Resolves: #CVE-2025-54770 #CVE-2025-54771 #CVE-2025-61661
- Resolves: #CVE-2025-61662 #CVE-2025-61663 #CVE-2025-61664
* Mon Jan 26 2026 Leo Sandoval <lsandova@redhat.com> - 2.12-37
- Include upstream blsuki related patches
- Resolves: #RHEL-119685
* Fri Dec 05 2025 Leo Sandoval <lsandova@redhat.com> 2.12-36
- rpminspect: disable abidiff inspections
- Resolves: #RHEL-134026
* Wed Dec 03 2025 Nicolas Frayer <nfrayer@redhat.com> 2.12-35
- mkimage/appendedsig: Fix grub-mkimage with an unaligned appended signature size
- Related: #RHEL-24510
* Fri Nov 21 2025 Nicolas Frayer <nfrayer@redhat.com> 2.12-34
- powerpc: Add appended signature feature
- Resolves: #RHEL-24510
* Thu Nov 06 2025 Leo Sandoval <lsandova@redhat.com> 2.12-33
- Include license into grub-set-password util
- Resolves: #RHEL-120704
* Tue Oct 28 2025 Leo Sandoval <lsandova@redhat.com> 2.12-32
- Disable annobin stack protection check
- Resolves: #RHEL-89464
* Tue Oct 7 2025 Nicolas Frayer <nfrayer@redhat.com> 2.12-31
- spec: Update signing key to redhatsecureboot802
- Resolves: #RHEL-116730
* Fri Sep 12 2025 Nicolas Frayer <nfrayer@redhat.com> 2.12-30
- gating.yaml: Update gating tests as there was a change in where
test composes are kept
- Resolves: #RHEL-114488
* Mon Sep 08 2025 Leo Sandoval <lsandova@redhat.com> 2.12-29
- Fix the fallback mechanism when menu entries fail to boot
- Resolves: RHEL-113024
* Thu Aug 21 2025 Leo Sandoval <lsandova@redhat.com> 2.12-28
- Remove strong stack protector on target CFLAGS
- Related: #RHEL-89464
* Fri Aug 15 2025 Leo Sandoval <lsandova@redhat.com> 2.12-27
- Revert annobin's regex removal into cflags_sed
- Resolves: #RHEL-89464
* Thu Jul 31 2025 Leo Sandoval <lsandova@redhat.com> 2.12-26
- Enable strong stack protector on EFI configurations
- Resolves: #RHEL-89464
* Thu Jul 31 2025 Leo Sandoval <lsandova@redhat.com> 2.12-25
- 20-grub.install: Skip BLS removal when entry type is type2
- Resolves: #RHEL-104167
* Tue Jul 29 2025 Nicolas Frayer <nfrayer@redhat.com> 2.12-24
- spec/posttrans: move grub config stub creation out of spec
- Resolves: #RHEL-69943
* Tue Jul 15 2025 Leo Sandoval <lsandova@redhat.com> 2.12-23
- Set correctly the memory attributes for the kernel PE sections
- Resolves: #RHEL-97086
* Tue Jul 15 2025 Leo Sandoval <lsandova@redhat.com> 2.12-22
- workaround: do not update mem attrs even if EFI protocol is present
- Resolves: #RHEL-97086
* Fri Jun 6 2025 Leo Sandoval <lsandova@redhat.com> 2.12-21
- Bump version (see CS-2896)
- Resolves: #RHEL-94342
* Mon Jun 2 2025 Leo Sandoval <lsandova@redhat.com> 2.12-20
- Handle special kernel parameter characters properly
- Resolves: #RHEL-94342
* Wed May 14 2025 Nicolas Frayer <nfrayer@redhat.com> - 2.12-19
- sbat: bump grub sbat for new shim release
- Resolves: #RHEL-91277
* Tue May 13 2025 Nicolas Frayer <nfrayer@redhat.com> - 2.12-18
- sbat: add new sbat entry for centos
- Resolves: #RHEL-91146
* Wed Apr 16 2025 Andrea Bolognani <abologna@redhat.com> - 2.12-17
- Fix riscv64 build
Resolves: RHEL-85987
* Tue Apr 15 2025 Nicolas Frayer <nfrayer@redhat.com> - 2.12-16
- ppc/mkimage: SBAT support on powerpc
- Resolves: #RHEL-87420
* Mon Apr 7 2025 Marta Lewandowska <mlewando@redhat.com> - 2.12-15
- 99-grub-mkconfig.install: Disable BLS and run grub2-mkconfig when GRUB_ENABLE_BLSCFG is disable
- Resolves: #RHEL-86261
* Tue Mar 25 2025 Nicolas Frayer <nfrayer@redhat.com> 2.12-14
- ieee1275/ofnet: Fix grub_malloc() removed after added safe
- Related: #RHEL-80073
* Tue Mar 18 2025 Nicolas Frayer <nfrayer@redhat.com> 2.12-13
- powerpc: increase MIN RMA size for CAS negotiation
- Resolves: #RHEL-76429

View File

@ -1,3 +1,4 @@
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,@@VERSION_RELEASE@@,mailto:secalert@redhat.com
grub.centos,2,Red Hat,grub2,@@VERSION_RELEASE@@,mailto:secalert@redhat.com

1
sbat.ppc.csv Executable file
View File

@ -0,0 +1 @@
sbat,1,SBAT Version,sbat,1,https://github.com/rhboot/shim/blob/main/SBAT.md
1 sbat 1 SBAT Version sbat 1 https://github.com/rhboot/shim/blob/main/SBAT.md