Debrand for AlmaLinux

Build btrfs module
This commit is contained in:
Eduard Abdullin 2026-03-04 15:02:48 +00:00 committed by root
commit 3f1554f76f
21 changed files with 3415 additions and 4 deletions

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

@ -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 btrfs \\\
%global grub_modules " all_video boot blscfg blsuki btrfs \\\
cat configfile cryptodisk \\\
echo ext2 f2fs fat font \\\
gcry_rijndael gcry_rsa gcry_serpent \\\

View File

@ -407,3 +407,21 @@ 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

View File

@ -17,7 +17,7 @@
Name: grub2
Epoch: 1
Version: 2.12
Release: 36%{?dist}.alma.1
Release: 41%{?dist}.alma.1
Summary: Bootloader with support for Linux, Multiboot and more
License: GPL-3.0-or-later
URL: http://www.gnu.org/software/grub/
@ -39,10 +39,14 @@ Source13: gen_grub_cfgstub
%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
%define sb_key almalinuxsecurebootca0
@ -565,10 +569,32 @@ fi
%endif
%changelog
* Wed Dec 10 2025 Eduard Abdullin <eabdullin@almalinux.org> - 1:2.12-36.alma.1
* Wed Mar 04 2026 Eduard Abdullin <eabdullin@almalinux.org> - 1:2.12-41.alma.1
- Debrand for AlmaLinux
- Build btrfs module
* 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