Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package grub2 for openSUSE:Factory checked in at 2026-04-30 20:25:43 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/grub2 (Old) and /work/SRC/openSUSE:Factory/.grub2.new.30200 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "grub2" Thu Apr 30 20:25:43 2026 rev:389 rq:1349907 version:2.14 Changes: -------- --- /work/SRC/openSUSE:Factory/grub2/grub2.changes 2026-04-22 17:12:55.220991292 +0200 +++ /work/SRC/openSUSE:Factory/.grub2.new.30200/grub2.changes 2026-04-30 20:25:51.931687227 +0200 @@ -1,0 +2,75 @@ +Wed Apr 29 01:10:02 UTC 2026 - Michael Chang <[email protected]> + +- Fix incorrect default entry and bump counter for BLS boot counter files + (bsc#1262580) + * 0001-bls-fix-default-entry-and-bumpcounter-for-BLS-boot-c.patch + +------------------------------------------------------------------- +Mon Apr 20 09:03:24 UTC 2026 - Michael Chang <[email protected]> + +- VUL-0: grub: potentially problematic utf8 conversion in bli patches (bsc#1262129) + * 0001-Fix-problematic-utf8-conversion-in-bli-patches.patch + +------------------------------------------------------------------- +Fri Apr 17 07:45:21 UTC 2026 - Radoslav Kolev <[email protected]> + +- Fix build for glibc 2.43 by taking upstream changes (bsc#1257256) + * 0001-osdep-linux-ofpath-Update-strstr-calls.patch + * 0001-util-probe-Save-strrchr-ret-val-to-const-data-ptr.patch + * 0002-util-resolve-Save-str-r-chr-ret-val-to-const-data-pt.patch + +------------------------------------------------------------------- +Tue Apr 14 12:34:01 UTC 2026 - Danilo Spinella <[email protected]> + +- Fix string to integer conversion for LoaderConfigTimeout + * 0004-bli-Add-support-for-LoaderConfigTimeout-and-LoaderCo.patch + +------------------------------------------------------------------- +Tue Apr 14 00:39:13 UTC 2026 - Michael Chang <[email protected]> + +- grub2.spec: When building the grubbls image, do not hardcode the timeout + value in the early config because it is set by bli.mod when it is loaded +- grub2.spec: Remove hardcoded terminal and theme settings from the early + config as they are now applied at runtime + +------------------------------------------------------------------- +Mon Apr 13 07:12:45 UTC 2026 - Michael Chang <[email protected]> + +- Fix missing install device check in grub2-install on PowerPC which could lead + to bootlist corruption (bsc#1221126) + * 0001-Mandatory-install-device-check-for-PowerPC.patch + +------------------------------------------------------------------- +Tue Apr 7 06:45:13 UTC 2026 - Michael Chang <[email protected]> + +- Fix double free in xen booting if root filesystem is Btrfs (bsc#1259543) + * grub2-btrfs-01-add-ability-to-boot-from-subvolumes.patch + * grub2-btrfs-09-get-default-subvolume.patch + +------------------------------------------------------------------- +Mon Mar 23 16:16:32 UTC 2026 - Danilo Spinella <[email protected]> + +- Rewrite BLI patches: + * 0001-blsuki-Add-support-for-LoaderEntries.patch + * 0002-menu-Allow-default-entry-to-have-.conf-suffix.patch + * 0003-bli-Add-support-for-LoaderEntryDefault-and-LoaderEnt.patch + * 0004-bli-Add-support-for-LoaderConfigTimeout-and-LoaderCo.patch + * 0005-bls_bumpcounter-Add-command-to-bump-boot-counter-for.patch + * 0006-bli-Add-support-for-LoaderFeatures.patch + * 0007-blsuki-Fix-sorting-for-entries-with-boot-counting-en.patch + * 0008-blsuki-append-leftover-LoaderEntries.patch + * 0009-blsuki-conservative-UTF-8-buffer-size.patch +- Remove patches: + * 0001-bls-Accept-.conf-suffix-in-setting-default-entry.patch + * grub2-bls-boot-counting.patch + * grub2-bls-boot-assessment.patch + * grub2-blscfg-set-efivars.patch + * grub2-bls-loader-entry-oneshot.patch + * grub2-blsbumpcounter-menu.patch + * grub2-bls-loader-entry-default.patch + * grub2-bls-loader-entries-boot-counting.patch + * grub2-bls-loader-features.patch + * grub2-bls-loader-config-timeout.patch + * grub2-bls-loader-config-timeout-fix.patch + +------------------------------------------------------------------- Old: ---- 0001-bls-Accept-.conf-suffix-in-setting-default-entry.patch grub2-bls-boot-assessment.patch grub2-bls-boot-counting.patch grub2-bls-loader-config-timeout-fix.patch grub2-bls-loader-config-timeout.patch grub2-bls-loader-entries-boot-counting.patch grub2-bls-loader-entry-default.patch grub2-bls-loader-entry-oneshot.patch grub2-bls-loader-features.patch grub2-blsbumpcounter-menu.patch grub2-blscfg-set-efivars.patch New: ---- 0001-Fix-problematic-utf8-conversion-in-bli-patches.patch 0001-Mandatory-install-device-check-for-PowerPC.patch 0001-bls-fix-default-entry-and-bumpcounter-for-BLS-boot-c.patch 0001-blsuki-Add-support-for-LoaderEntries.patch 0001-osdep-linux-ofpath-Update-strstr-calls.patch 0001-util-probe-Save-strrchr-ret-val-to-const-data-ptr.patch 0002-menu-Allow-default-entry-to-have-.conf-suffix.patch 0002-util-resolve-Save-str-r-chr-ret-val-to-const-data-pt.patch 0003-bli-Add-support-for-LoaderEntryDefault-and-LoaderEnt.patch 0004-bli-Add-support-for-LoaderConfigTimeout-and-LoaderCo.patch 0005-bls_bumpcounter-Add-command-to-bump-boot-counter-for.patch 0006-bli-Add-support-for-LoaderFeatures.patch 0007-blsuki-Fix-sorting-for-entries-with-boot-counting-en.patch 0008-blsuki-append-leftover-LoaderEntries.patch 0009-blsuki-conservative-UTF-8-buffer-size.patch ----------(Old B)---------- Old:- Remove patches: * 0001-bls-Accept-.conf-suffix-in-setting-default-entry.patch * grub2-bls-boot-counting.patch Old: * grub2-bls-boot-counting.patch * grub2-bls-boot-assessment.patch * grub2-blscfg-set-efivars.patch Old: * 0001-bls-Accept-.conf-suffix-in-setting-default-entry.patch * grub2-bls-boot-counting.patch * grub2-bls-boot-assessment.patch Old: * grub2-bls-loader-config-timeout.patch * grub2-bls-loader-config-timeout-fix.patch Old: * grub2-bls-loader-features.patch * grub2-bls-loader-config-timeout.patch * grub2-bls-loader-config-timeout-fix.patch Old: * grub2-bls-loader-entry-default.patch * grub2-bls-loader-entries-boot-counting.patch * grub2-bls-loader-features.patch Old: * grub2-blsbumpcounter-menu.patch * grub2-bls-loader-entry-default.patch * grub2-bls-loader-entries-boot-counting.patch Old: * grub2-blscfg-set-efivars.patch * grub2-bls-loader-entry-oneshot.patch * grub2-blsbumpcounter-menu.patch Old: * grub2-bls-loader-entries-boot-counting.patch * grub2-bls-loader-features.patch * grub2-bls-loader-config-timeout.patch Old: * grub2-bls-loader-entry-oneshot.patch * grub2-blsbumpcounter-menu.patch * grub2-bls-loader-entry-default.patch Old: * grub2-bls-boot-assessment.patch * grub2-blscfg-set-efivars.patch * grub2-bls-loader-entry-oneshot.patch ----------(Old E)---------- ----------(New B)---------- New:- VUL-0: grub: potentially problematic utf8 conversion in bli patches (bsc#1262129) * 0001-Fix-problematic-utf8-conversion-in-bli-patches.patch New: to bootlist corruption (bsc#1221126) * 0001-Mandatory-install-device-check-for-PowerPC.patch New: (bsc#1262580) * 0001-bls-fix-default-entry-and-bumpcounter-for-BLS-boot-c.patch New:- Rewrite BLI patches: * 0001-blsuki-Add-support-for-LoaderEntries.patch * 0002-menu-Allow-default-entry-to-have-.conf-suffix.patch New:- Fix build for glibc 2.43 by taking upstream changes (bsc#1257256) * 0001-osdep-linux-ofpath-Update-strstr-calls.patch * 0001-util-probe-Save-strrchr-ret-val-to-const-data-ptr.patch New: * 0001-osdep-linux-ofpath-Update-strstr-calls.patch * 0001-util-probe-Save-strrchr-ret-val-to-const-data-ptr.patch * 0002-util-resolve-Save-str-r-chr-ret-val-to-const-data-pt.patch New: * 0001-blsuki-Add-support-for-LoaderEntries.patch * 0002-menu-Allow-default-entry-to-have-.conf-suffix.patch * 0003-bli-Add-support-for-LoaderEntryDefault-and-LoaderEnt.patch New: * 0001-util-probe-Save-strrchr-ret-val-to-const-data-ptr.patch * 0002-util-resolve-Save-str-r-chr-ret-val-to-const-data-pt.patch New: * 0002-menu-Allow-default-entry-to-have-.conf-suffix.patch * 0003-bli-Add-support-for-LoaderEntryDefault-and-LoaderEnt.patch * 0004-bli-Add-support-for-LoaderConfigTimeout-and-LoaderCo.patch New:- Fix string to integer conversion for LoaderConfigTimeout * 0004-bli-Add-support-for-LoaderConfigTimeout-and-LoaderCo.patch New: * 0004-bli-Add-support-for-LoaderConfigTimeout-and-LoaderCo.patch * 0005-bls_bumpcounter-Add-command-to-bump-boot-counter-for.patch * 0006-bli-Add-support-for-LoaderFeatures.patch New: * 0005-bls_bumpcounter-Add-command-to-bump-boot-counter-for.patch * 0006-bli-Add-support-for-LoaderFeatures.patch * 0007-blsuki-Fix-sorting-for-entries-with-boot-counting-en.patch New: * 0006-bli-Add-support-for-LoaderFeatures.patch * 0007-blsuki-Fix-sorting-for-entries-with-boot-counting-en.patch * 0008-blsuki-append-leftover-LoaderEntries.patch New: * 0007-blsuki-Fix-sorting-for-entries-with-boot-counting-en.patch * 0008-blsuki-append-leftover-LoaderEntries.patch * 0009-blsuki-conservative-UTF-8-buffer-size.patch New: * 0008-blsuki-append-leftover-LoaderEntries.patch * 0009-blsuki-conservative-UTF-8-buffer-size.patch - Remove patches: ----------(New E)---------- ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ grub2.spec ++++++ --- /var/tmp/diff_new_pack.hIjhwA/_old 2026-04-30 20:25:56.163860923 +0200 +++ /var/tmp/diff_new_pack.hIjhwA/_new 2026-04-30 20:25:56.163860923 +0200 @@ -359,7 +359,6 @@ Patch232: 0001-ieee1275-support-added-for-multiple-nvme-bootpaths.patch Patch236: 0001-kern-main-Fix-cmdpath-in-root-directory.patch Patch237: grub2-s390x-secure-execution-support.patch -Patch259: 0001-bls-Accept-.conf-suffix-in-setting-default-entry.patch Patch263: 0001-autofs-Ignore-zfs-not-found.patch Patch264: 0001-s390x-emu-Pass-through-PAES-cipher-as-AES.patch Patch274: 0001-ofpath-Add-error-check-in-NVMEoF-device-translation.patch @@ -367,15 +366,10 @@ Patch277: 0001-prep_loadenv-Measure-the-environment-block-into-PCR-.patch Patch294: 0001-Fix-PowerPC-CAS-reboot-to-evaluate-menu-context.patch Patch295: 0001-blscfg-read-fragments-in-order.patch -Patch296: grub2-bls-boot-counting.patch -Patch297: grub2-bls-boot-assessment.patch Patch298: grub2-bls-boot-show-snapshot.patch -Patch300: grub2-blscfg-set-efivars.patch Patch309: 0001-Improve-TPM-key-protection-on-boot-interruptions.patch Patch310: 0004-Key-revocation-on-out-of-bound-file-access.patch -Patch311: grub2-bls-loader-entry-oneshot.patch Patch312: 0001-mkconfig-Determine-GRUB_DISTRIBUTOR-from-etc-SUSE-br.patch -Patch313: grub2-blsbumpcounter-menu.patch Patch315: 0001-test-Fix-f-test-on-files-over-network.patch Patch316: 0002-http-Return-HTTP-status-code-in-http_establish.patch Patch317: 0003-docs-Clarify-test-for-files-on-TFTP-and-HTTP.patch @@ -385,11 +379,7 @@ Patch336: 0002-linux-fallback-to-direct-PE-entry-boot-on-arm64.patch Patch337: 0003-efi-chainloader-fallback-to-direct-image-execution.patch Patch338: 0004-efi-chainloader-fix-missing-file_path-in-loaded_imag.patch -Patch342: grub2-bls-loader-entry-default.patch Patch344: grub2-i386-pc-no-pageflipping.patch -Patch401: grub2-bls-loader-entries-boot-counting.patch -Patch402: grub2-bls-loader-features.patch -Patch403: grub2-bls-loader-config-timeout.patch Patch404: 0001-editenv-create-health_check_flag-env-var-on-RW-raw-b.patch Patch405: 0001-00_header-Omit-loading-efi_uga-on-non-x86-EFI-platfo.patch Patch406: 0001-Revert-configure-Print-a-more-helpful-error-if-autoc.patch @@ -398,8 +388,22 @@ Patch409: 0001-bls-Allow-configuration-of-active-console-type.patch Patch410: 0002-grubbls-Add-automatic-fwsetup-menu-entry.patch Patch411: 0001-ieee1275-support-dm-multipath-bootlist.patch -Patch412: grub2-bls-loader-config-timeout-fix.patch Patch413: 0001-mdraid1x-fix-raid_disks-decoding-on-big-endian-syste.patch +Patch414: 0001-blsuki-Add-support-for-LoaderEntries.patch +Patch415: 0002-menu-Allow-default-entry-to-have-.conf-suffix.patch +Patch416: 0003-bli-Add-support-for-LoaderEntryDefault-and-LoaderEnt.patch +Patch417: 0004-bli-Add-support-for-LoaderConfigTimeout-and-LoaderCo.patch +Patch418: 0005-bls_bumpcounter-Add-command-to-bump-boot-counter-for.patch +Patch419: 0006-bli-Add-support-for-LoaderFeatures.patch +Patch420: 0007-blsuki-Fix-sorting-for-entries-with-boot-counting-en.patch +Patch421: 0008-blsuki-append-leftover-LoaderEntries.patch +Patch422: 0009-blsuki-conservative-UTF-8-buffer-size.patch +Patch423: 0001-Mandatory-install-device-check-for-PowerPC.patch +Patch424: 0001-osdep-linux-ofpath-Update-strstr-calls.patch +Patch425: 0001-util-probe-Save-strrchr-ret-val-to-const-data-ptr.patch +Patch426: 0002-util-resolve-Save-str-r-chr-ret-val-to-const-data-pt.patch +Patch427: 0001-Fix-problematic-utf8-conversion-in-bli-patches.patch +Patch428: 0001-bls-fix-default-entry-and-bumpcounter-for-BLS-boot-c.patch %if 0%{?suse_version} < 1600 Requires: gettext-runtime @@ -733,7 +737,7 @@ %define _configure ../configure # We don't want to let rpm override *FLAGS with default a.k.a bogus values. -CFLAGS="-fno-strict-aliasing -fno-inline-functions-called-once -Wno-error=discarded-qualifiers" +CFLAGS="-fno-strict-aliasing -fno-inline-functions-called-once" CXXFLAGS=" " FFLAGS=" " export CFLAGS CXXFLAGS FFLAGS @@ -784,7 +788,7 @@ PXE_MODULES="tftp http" CRYPTO_MODULES="luks luks2 gcry_rijndael gcry_sha1 gcry_sha256 gcry_sha512 crypttab" %ifarch %{efi} -CD_MODULES="${CD_MODULES} chain efifwsetup efinet read tpm tss2 tpm2_key_protector memdisk tar squash4 xzio blsuki blsbumpcounter" +CD_MODULES="${CD_MODULES} chain efifwsetup efinet read tpm tss2 tpm2_key_protector memdisk tar squash4 xzio blsuki bls_bumpcounter" PXE_MODULES="${PXE_MODULES} efinet" %else CD_MODULES="${CD_MODULES} net ofnet" @@ -858,23 +862,10 @@ regexp --set 1:root '\((.*)\)' "$cmdpath" -set timeout=8 set gfxmode=auto set gfxpayload=keep set enable_blscfg=1 -terminal_input console -terminal_output console -terminal_output --append gfxterm - -loadfont (memdisk)/boot/grub/themes/DejaVuSans-Bold14.pf2 -loadfont (memdisk)/boot/grub/themes/DejaVuSans10.pf2 -loadfont (memdisk)/boot/grub/themes/DejaVuSans12.pf2 -loadfont (memdisk)/boot/grub/themes/ascii.pf2 - -set theme=(memdisk)/boot/grub/themes/theme.txt -export theme - EOF %if 0%{?suse_version} > 1500 @@ -890,7 +881,7 @@ %{?sbat_generation:--sbat sbat.csv} \ -d grub-core \ all_video boot font gfxmenu gfxterm gzio halt jpeg minicmd normal part_gpt png reboot video \ - fat tpm tss2 tpm2_key_protector memdisk tar squash4 xzio blsuki blsbumpcounter linux bli regexp loadenv test echo true sleep efifwsetup + fat tpm tss2 tpm2_key_protector memdisk tar squash4 xzio blsuki bls_bumpcounter linux bli regexp loadenv test echo true sleep efifwsetup %endif %ifarch x86_64 aarch64 ++++++ 0001-Fix-problematic-utf8-conversion-in-bli-patches.patch ++++++ >From 38b8a8feec4c48d7d4aa6731955b2a96c0d2ec7d Mon Sep 17 00:00:00 2001 From: Michael Chang <[email protected]> Date: Thu, 16 Apr 2026 11:11:10 +0800 Subject: [PATCH] Fix problematic utf8 conversion in bli patches Use UTF-16 code unit counts in grub-core/commands/bli.c when converting EFI variable data to UTF-8. Allocate the UTF-8 buffer with checked size growth, convert using the correct UTF-16 element count, and always append a terminating NUL. This avoids heap overreads, heap overflows, and unterminated strings when EFI variable contents are malformed or larger than expected. Fix filename growth handling in grub-core/commands/bls_bumpcounter.c by accounting for the extra UTF-16 storage needed when appending "-1" to the filename. Use checked size expansion before reallocating the EFI file info buffer, and pass the UTF-16 destination length in code units to grub_utf8_to_utf16(). This prevents writing past FileName when the renamed entry becomes longer. Bound the scan of LoaderEntries in grub-core/commands/blsuki.c by the EFI variable size instead of assuming that the data is always NUL-terminated. If no UTF-16 terminator is found within the reported variable size, treat the variable as malformed and fail cleanly. This avoids out-of-bounds reads on corrupted or malicious EFI variable contents. Signed-off-by: Michael Chang <[email protected]> --- grub-core/commands/bli.c | 26 +++++++++++++++++++++----- grub-core/commands/bls_bumpcounter.c | 13 +++++++++---- grub-core/commands/blsuki.c | 24 +++++++++++++++++++++--- 3 files changed, 51 insertions(+), 12 deletions(-) diff --git a/grub-core/commands/bli.c b/grub-core/commands/bli.c index 72a3a4edc..c90c9b404 100644 --- a/grub-core/commands/bli.c +++ b/grub-core/commands/bli.c @@ -177,19 +177,35 @@ static char* get_efivar (const char* efivar) { grub_efi_status_t status; - grub_size_t size; + grub_size_t size, size16; grub_efi_char16_t *val_efi = NULL; char *val = NULL; + status = grub_efi_get_variable (efivar, &bli_vendor_guid, &size, (void**) &val_efi); - if (status == GRUB_EFI_SUCCESS && size != 0) + + size16 = size / sizeof (*val_efi); + if (status == GRUB_EFI_SUCCESS && size16 > 0) { - val = grub_malloc (size * sizeof (char)); - grub_utf16_to_utf8 ((grub_uint8_t*) val, - (grub_uint16_t*) val_efi, size); + grub_size_t size_utf8; + + if (grub_mul (size16, GRUB_MAX_UTF8_PER_UTF16, &size_utf8) || + grub_add (size_utf8, 1, &size_utf8)) + { + grub_error (GRUB_ERR_OUT_OF_RANGE, "size overflow when converting EFI variable %s to UTF-8", efivar); + goto finish; + } + val = grub_malloc (size_utf8); + if (val == NULL) + goto finish; + *grub_utf16_to_utf8 ((grub_uint8_t*) val, + (grub_uint16_t*) val_efi, size16) = '\0'; } + +finish: + grub_free (val_efi); return val; } diff --git a/grub-core/commands/bls_bumpcounter.c b/grub-core/commands/bls_bumpcounter.c index 014389567..d45fe276c 100644 --- a/grub-core/commands/bls_bumpcounter.c +++ b/grub-core/commands/bls_bumpcounter.c @@ -192,9 +192,13 @@ grub_cmd_bls_bumpcounter (grub_extcmd_context_t ctxt __attribute__ ((unused)), { grub_free(file_info); /* When we bump the counter, it might happen that we increase the filename - length. Add the space for 2 more characters. (i.e. adding the boot done - part "-1") */ - size += 2; + length. Add the space for 2 more characters (4 bytes). (i.e. adding the + boot done part "-1") */ + if (grub_add (size, 4, &size)) + { + grub_error (GRUB_ERR_OUT_OF_RANGE, N_("size overflow")); + goto finish; + } file_info = grub_malloc (size); if (!file_info) { @@ -218,7 +222,8 @@ grub_cmd_bls_bumpcounter (grub_extcmd_context_t ctxt __attribute__ ((unused)), grub_dprintf ("bls_bumpcounter", "renaming entry to %s\n", new_path); grub_utf8_to_utf16 (file_info->FileName, - size - offsetof (grub_efi_file_info_t, FileName), + (size - offsetof (grub_efi_file_info_t, FileName)) + / sizeof (grub_efi_char16_t), (grub_uint8_t*) new_path, grub_strlen (new_path), NULL); err = handle->SetInfo (handle, &grub_efi_file_info_guid, size, file_info); diff --git a/grub-core/commands/blsuki.c b/grub-core/commands/blsuki.c index e692bbe69..4dfc4934e 100644 --- a/grub-core/commands/blsuki.c +++ b/grub-core/commands/blsuki.c @@ -1539,7 +1539,7 @@ set_bli_loader_entries (enum blsuki_cmd_type cmd_type) grub_size_t size = 0, remaining_size, len, written, prev_entries_size = 0, len16; grub_efi_char16_t *prev_entries_start = NULL; grub_size_t prev_entries_start_size = 0; - grub_efi_char16_t *efi_entries = NULL, *prev_entries = NULL, *p = NULL, *tmp16; + grub_efi_char16_t *efi_entries = NULL, *prev_entries = NULL, *p = NULL; char *boot_counting_idx, *prev_entry; const char* env = NULL; grub_efi_status_t status; @@ -1624,12 +1624,30 @@ set_bli_loader_entries (enum blsuki_cmd_type cmd_type) { do { grub_size_t prev_entry_size; + grub_size_t prev_entries_size16 = prev_entries_size / sizeof (*prev_entries); - tmp16 = prev_entries; len16 = 0; - while (*tmp16++ != '\0') + /* + * LoaderEntries comes from EFI variable storage, so it is only + * trusted up to prev_entries_size16 UTF-16 code units. Bound + * the scan in case a malformed variable is missing a + * terminator. + */ + while (len16 < prev_entries_size16 && prev_entries[len16] != '\0') len16++; + /* + * If we reached the end of the buffer without finding a null + * terminator, the variable is malformed and we should bail + * instead of risking an out-of-bounds read. + */ + if (len16 == prev_entries_size16) + { + grub_free (prev_entries_start); + grub_free (efi_entries); + return grub_error (GRUB_ERR_BAD_ARGUMENT, "malformed LoaderEntries variable"); + } + if (grub_mul (len16, GRUB_MAX_UTF8_PER_UTF16, &prev_entry_size) || grub_add (prev_entry_size, 1, &prev_entry_size)) { -- 2.53.0 ++++++ 0001-Mandatory-install-device-check-for-PowerPC.patch ++++++ >From 34de9a5984c9a9e84717dd6ed7a6ba255f09bb0a Mon Sep 17 00:00:00 2001 From: Avnish Chouhan <[email protected]> Date: Tue, 27 Jan 2026 19:18:14 +0530 Subject: [PATCH] Mandatory install device check for PowerPC This patch adds a check on install_device while installing grub for PowerPC. If install_device is not mentioned in grub2-install and machine is detected as PowerPC, the error will be thrown and it will terminates the grub2-install operation. Running grub2-install on PowerPC without the install_device may result in bootlist corruption. When no install device is specified, it attempts to load images from the filesystem, which leads to nvram bootlist corruption. The idea is to fail the operation and avoid creating the invalid boot entry. Signed-off-by: Avnish Chouhan <[email protected]> Link: https://patch.msgid.link/[email protected] --- util/grub-install.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/util/grub-install.c b/util/grub-install.c index 926f49457..226146899 100644 --- a/util/grub-install.c +++ b/util/grub-install.c @@ -1435,6 +1435,19 @@ main (int argc, char *argv[]) is_prep = 0; } } +#if defined(__powerpc__) + else + { + /* + * As the machine has been detected as PowerPC and not a PowerMac. We need to check + * whether the install_device has been mentioned while installing. If no device has been + * mentioned, we need to exit and mark it as an error as the install_device is required for + * PowerPC installation. An installation with no device mentioned may lead to corruptions. + */ + if (!install_device) + grub_util_error ("%s", _("install device isn't specified, required for PowerPC")); + } +#endif /* __powerpc__ */ } if (platform == GRUB_INSTALL_PLATFORM_S390X_EMU) -- 2.53.0 ++++++ 0001-bls-fix-default-entry-and-bumpcounter-for-BLS-boot-c.patch ++++++ >From fb62215386831db2a85b9b73cfb77f1567a24f78 Mon Sep 17 00:00:00 2001 From: Michael Chang <[email protected]> Date: Tue, 28 Apr 2026 13:02:13 +0800 Subject: [PATCH] bls: fix default entry and bumpcounter for BLS boot counter files When BLS boot counting is enabled, entry filenames include counter suffixes such as "+TRIES-DONE". This patch tries to ensure that the default entry selection and bumpcounter operations work correctly with these modified filenames. Signed-off-by: Michael Chang <[email protected]> --- grub-core/commands/bls_bumpcounter.c | 32 +++++++++++++------ grub-core/commands/blsuki.c | 48 ++++++++++++++++++++++++++++ 2 files changed, 71 insertions(+), 9 deletions(-) diff --git a/grub-core/commands/bls_bumpcounter.c b/grub-core/commands/bls_bumpcounter.c index d45fe276c..fe4a9ea92 100644 --- a/grub-core/commands/bls_bumpcounter.c +++ b/grub-core/commands/bls_bumpcounter.c @@ -102,8 +102,9 @@ grub_cmd_bls_bumpcounter (grub_extcmd_context_t ctxt __attribute__ ((unused)), grub_efi_status_t err; char *entry, *new_path = NULL, *old_path; const char *blsdir; - grub_efi_uint64_t size; + grub_efi_uint64_t size, size_info; grub_efi_char16_t *old_path16; + grub_efi_uint64_t len16; if (argc != 1) { grub_dprintf ("bls_bumpcounter", "only one argument should be passed\n"); @@ -160,7 +161,7 @@ grub_cmd_bls_bumpcounter (grub_extcmd_context_t ctxt __attribute__ ((unused)), blsdir = GRUB_BLS_CONFIG_PATH; } - old_path = grub_xasprintf ("%s%s", blsdir, entry); + old_path = grub_xasprintf ("%s%s.conf", blsdir, entry); grub_utf8_to_utf16_alloc (old_path, &old_path16, NULL); err = root->Open (root, &handle, old_path16, @@ -179,14 +180,15 @@ grub_cmd_bls_bumpcounter (grub_extcmd_context_t ctxt __attribute__ ((unused)), most cases, and, if it fails, allocate a new one with the exact size returned from GetInfo. Reference: systemd:src/boot/efi/util.c =*/ - size = offsetof (grub_efi_file_info_t, FileName) + size_info = offsetof (grub_efi_file_info_t, FileName) + 256U * sizeof (grub_efi_char16_t); - file_info = grub_malloc (size); + file_info = grub_malloc (size_info); if (!file_info) { grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("out of memory")); goto finish; } + size = size_info - 4; /* reserve space for 2 more characters (4 bytes) for the boot done part "-1" */ err = handle->GetInfo (handle, &grub_efi_file_info_guid, &size, file_info); if (err == GRUB_EFI_BUFFER_TOO_SMALL) { @@ -194,12 +196,12 @@ grub_cmd_bls_bumpcounter (grub_extcmd_context_t ctxt __attribute__ ((unused)), /* When we bump the counter, it might happen that we increase the filename length. Add the space for 2 more characters (4 bytes). (i.e. adding the boot done part "-1") */ - if (grub_add (size, 4, &size)) + if (grub_add (size, 4, &size_info)) { grub_error (GRUB_ERR_OUT_OF_RANGE, N_("size overflow")); goto finish; } - file_info = grub_malloc (size); + file_info = grub_malloc (size_info); if (!file_info) { grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("out of memory")); @@ -221,12 +223,24 @@ grub_cmd_bls_bumpcounter (grub_extcmd_context_t ctxt __attribute__ ((unused)), goto finish; grub_dprintf ("bls_bumpcounter", "renaming entry to %s\n", new_path); - grub_utf8_to_utf16 (file_info->FileName, - (size - offsetof (grub_efi_file_info_t, FileName)) + len16 = grub_utf8_to_utf16 (file_info->FileName, + (size_info - offsetof (grub_efi_file_info_t, FileName)) / sizeof (grub_efi_char16_t), (grub_uint8_t*) new_path, grub_strlen (new_path), NULL); - err = handle->SetInfo (handle, &grub_efi_file_info_guid, size, file_info); + /* + * Check if the new filename fits in the allocated file_info buffer. If not, + * it means that the entry is too long to be renamed with the bumped counter, + * and we should bail instead of risking an out-of-bounds write. + */ + if (len16 >= (size_info - offsetof (grub_efi_file_info_t, FileName)) / + sizeof (grub_efi_char16_t)) + { + grub_dprintf ("bls_bumpcounter", "new filename is too long\n"); + goto finish; + } + file_info->FileName[len16++] = '\0'; + err = handle->SetInfo (handle, &grub_efi_file_info_guid, size_info, file_info); if (err != GRUB_EFI_SUCCESS) { diff --git a/grub-core/commands/blsuki.c b/grub-core/commands/blsuki.c index 4dfc4934e..8b152b443 100644 --- a/grub-core/commands/blsuki.c +++ b/grub-core/commands/blsuki.c @@ -1091,6 +1091,7 @@ bls_create_entry (grub_blsuki_entry_t *entry) char *initrd_cmd = NULL; char *dt_cmd = NULL; char *id = entry->filename; + char *id_dup = NULL; grub_size_t id_len; char *hotkey = NULL; char *users = NULL; @@ -1111,6 +1112,52 @@ bls_create_entry (grub_blsuki_entry_t *entry) id_len = grub_strlen (id); if (id_len >= BLS_EXT_LEN && grub_strcmp (id + id_len - BLS_EXT_LEN, ".conf") == 0) id[id_len - BLS_EXT_LEN] = '\0'; + id_len = grub_strlen (id); + /* + * The menuentry ID should have the boot assessemnt counters removed, to + * canonicalize that default entry can be correctly matched. + */ + char *tries = grub_strrchr (id, '+'); + if (tries != NULL) + { + char *n; + const char *n_end = NULL; + char *done = grub_strrchr (tries, '-'); + if (done != NULL) + n = grub_strndup (tries + 1, done - tries - 1); + else + n = grub_strdup (tries + 1); + if (n == NULL) + goto finish; + grub_error_push (); + grub_strtol (n, &n_end, 10); + switch (grub_errno) + { + case GRUB_ERR_NONE: + grub_error_pop (); + if (n_end && n_end != n && *n_end == '\0') + { + id_dup = grub_strdup (id); + if (id_dup == NULL) + { + grub_free (n); + goto finish; + } + grub_strrchr (id_dup, '+')[0] = '\0'; + } + break; + default: + grub_error_pop (); + break; + } + grub_free (n); + } + + if (id_dup != NULL) + { + id = id_dup; + id_len = grub_strlen (id); + } title = blsuki_get_val (entry, "title", NULL); if (title != NULL) @@ -1178,6 +1225,7 @@ bls_create_entry (grub_blsuki_entry_t *entry) grub_free (args); grub_free (argv); grub_free (src); + grub_free (id_dup); } #ifdef GRUB_MACHINE_EFI -- 2.53.0 ++++++ 0001-blsuki-Add-support-for-LoaderEntries.patch ++++++ >From c114cc791483dee8f833e9ed303b78b60922551b Mon Sep 17 00:00:00 2001 From: Danilo Spinella <[email protected]> Date: Tue, 10 Mar 2026 16:38:34 +0100 Subject: [PATCH 1/9] blsuki: Add support for LoaderEntries --- grub-core/commands/blsuki.c | 156 ++++++++++++++++++++++++++++++++++++ 1 file changed, 156 insertions(+) diff --git a/grub-core/commands/blsuki.c b/grub-core/commands/blsuki.c index 4133d3111..2664a9fc4 100644 --- a/grub-core/commands/blsuki.c +++ b/grub-core/commands/blsuki.c @@ -33,9 +33,15 @@ #include <filevercmp.h> #ifdef GRUB_MACHINE_EFI +#include <grub/charset.h> #include <grub/efi/efi.h> #include <grub/efi/disk.h> #include <grub/efi/pe32.h> + +static const grub_guid_t bli_vendor_guid = GRUB_EFI_VENDOR_BOOT_LOADER_INTERFACE_GUID; + +#define GRUB_BLSUKI_ENTRIES_BLS "blsuki_entries_bls" +#define GRUB_BLSUKI_ENTRIES_UKI "blsuki_entries_uki" #endif #ifdef GRUB_MACHINE_EMU @@ -1373,6 +1379,152 @@ blsuki_is_default_entry (const char *def_entry, grub_blsuki_entry_t *entry, int return false; } +#ifdef GRUB_MACHINE_EFI +/* Set LoaderEntries for uki and blscfg generated entries */ +static grub_err_t +set_bli_loader_entries (enum blsuki_cmd_type cmd_type) +{ + grub_blsuki_entry_t *entry = NULL; + grub_size_t size = 0, remaining_size, len, written, prev_entries_size = 0, len16; + grub_efi_char16_t *prev_entries_start = NULL; + grub_size_t prev_entries_start_size = 0; + grub_efi_char16_t *efi_entries = NULL, *prev_entries = NULL, *p = NULL, *tmp16; + char *boot_counting_idx, *prev_entry; + const char* env = NULL; + grub_efi_status_t status; + int rc; + + FOR_BLSUKI_ENTRIES (entry) + { + if (entry->visible) + { + /* Calculate the size of LoaderEntries string */ + len = grub_strlen (entry->filename); + /* Skip boot counting if found */ + boot_counting_idx = grub_strrchr(entry->filename, '+'); + if (boot_counting_idx != NULL) + len = boot_counting_idx - entry->filename; + /* Skip ".conf" extension if found */ + else if (len > BLS_EXT_LEN + && grub_strcmp (entry->filename + len - BLS_EXT_LEN, ".conf") == 0) + len -= BLS_EXT_LEN; + else if (len > UKI_EXT_LEN + && grub_strcmp (entry->filename + len - UKI_EXT_LEN, ".efi") == 0) + len -= UKI_EXT_LEN; + + size += len + 1; + } + } + + /* When calling blscfg command, there might be entries generated by uki command, + and viceversa. Use GRUB_BLSUKI_ENTRIES_BLS and GRUB_BLSUKI_ENTRIES_UKI env variables + to check if the current value of LoaderEntries should be appended to the new one */ + if (cmd_type == BLSUKI_BLS_CMD) + { + env = grub_env_get (GRUB_BLSUKI_ENTRIES_UKI); + } else if (cmd_type == BLSUKI_UKI_CMD) { + env = grub_env_get (GRUB_BLSUKI_ENTRIES_BLS); + } + if (env && grub_strcmp (env, "1") == 0) + { + status = grub_efi_get_variable ("LoaderEntries", + &bli_vendor_guid, + &prev_entries_start_size, + (void**) &prev_entries_start); + /* Get the value of the other generated entries */ + if (status != GRUB_EFI_SUCCESS || prev_entries_start_size == 0) + { + prev_entries_start = NULL; + prev_entries_start_size = 0; + } + } + efi_entries = grub_malloc (size * sizeof (grub_efi_char16_t) + prev_entries_start_size); + if (efi_entries == NULL) + return grub_errno; + + prev_entries = prev_entries_start; + prev_entries_size = prev_entries_start_size; + p = efi_entries; + remaining_size = size; + /* Create a null separated list of all entries (with the extension removed) */ + FOR_BLSUKI_ENTRIES (entry) + { + if (entry->visible) + { + len = grub_strlen (entry->filename); + + boot_counting_idx = grub_strrchr(entry->filename, '+'); + if (boot_counting_idx != NULL) + len = boot_counting_idx - entry->filename; + else if ((len > BLS_EXT_LEN) + && grub_strcmp (entry->filename + len - BLS_EXT_LEN, ".conf") == 0) + len -= BLS_EXT_LEN; + else if ((len > UKI_EXT_LEN) + && grub_strcmp (entry->filename + len - UKI_EXT_LEN, ".efi") == 0) + len -= UKI_EXT_LEN; + + if (remaining_size < len + 1) + { + grub_dprintf ("blsuki", "LoaderEntries buffer too small\n"); + break; + } + + if (prev_entries_size != 0 && prev_entries) + { + do { + tmp16 = prev_entries; + len16 = 0; + while (*tmp16++ != '\0') + len16++; + prev_entry = grub_malloc (len16 + 1); + *grub_utf16_to_utf8 ((grub_uint8_t*) prev_entry, prev_entries, len16) = '\0'; + rc = filevercmp (prev_entry, entry->filename); + if (rc == 0) + { + grub_free (prev_entry); + grub_free (prev_entries_start); + grub_free (efi_entries); + return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("duplicate file: `%s'"), entry->filename); + } + + if (rc > 0) + { + grub_memcpy (p, prev_entries, len16 * sizeof (*prev_entries)); + p += len16; + *p++ = (grub_efi_char16_t) '\0'; + remaining_size -= len16 + 1; + prev_entries += len16 + 1; + prev_entries_size -= (len16 + 1) * sizeof (*prev_entries); + } + grub_free (prev_entry); + } while (prev_entries_size > 0 && rc > 0); + } + + written = grub_utf8_to_utf16 (p, remaining_size, + (grub_uint8_t*) entry->filename, len, NULL); + p += written; + *p++ = (grub_efi_char16_t) '\0'; + remaining_size -= written + 1; + } + } + + status = grub_efi_set_variable_with_attributes ("LoaderEntries", &bli_vendor_guid, + efi_entries, + size * sizeof (grub_efi_char16_t) + prev_entries_start_size - prev_entries_size, + GRUB_EFI_VARIABLE_BOOTSERVICE_ACCESS | + GRUB_EFI_VARIABLE_RUNTIME_ACCESS); + /* Record that we set the generated entries by this command to LoaderEntries */ + if (cmd_type == BLSUKI_BLS_CMD) + grub_env_set (GRUB_BLSUKI_ENTRIES_BLS, "1"); + else if (cmd_type == BLSUKI_UKI_CMD) + grub_env_set (GRUB_BLSUKI_ENTRIES_UKI, "1"); + grub_free (efi_entries); + grub_free (prev_entries_start); + + return status; +} +#endif + /* * This function creates a GRUB boot menu entry for each BLS or UKI entry in * the entries list. @@ -1409,6 +1561,10 @@ blsuki_create_entries (bool show_default, bool show_non_default, char *entry_id, idx++; } +#ifdef GRUB_MACHINE_EFI + set_bli_loader_entries (cmd_type); +#endif + return GRUB_ERR_NONE; } -- 2.53.0 ++++++ 0001-osdep-linux-ofpath-Update-strstr-calls.patch ++++++ >From 675d8581037dc8996cf6db21a61d26e28f7d44c1 Mon Sep 17 00:00:00 2001 From: Nicholas Vinson <[email protected]> Date: Tue, 24 Feb 2026 19:48:39 -0500 Subject: [PATCH] osdep/linux/ofpath: Update strstr() calls With C23, strstr() returns a "const char *" if its first argument is "const char *", and these changes are implemented in glibc-2.43. As a result, the first strstr() call in check_sas() now returns a "const char *" instead of "char *" because sysfs_path is a "const char *". This triggers a "discards qualifiers" warning, that is later promoted to an error and ultimately causes the build to fail. To fix the issue, this patch converts "ed", the pointer that stores strstr()'s return value, to a "const char *". Removes the xstrdup() call and cleans up the rest of the function by updating the *printf() calls and using pointer arithmetic to compute lengths instead of strlen(). Signed-off-by: Nicholas Vinson <[email protected]> Reviewed-by: Daniel Kiper <[email protected]> --- grub-core/osdep/linux/ofpath.c | 25 ++++++++++++------------- 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/grub-core/osdep/linux/ofpath.c b/grub-core/osdep/linux/ofpath.c index 24a4d5c8d..0ebfea44c 100644 --- a/grub-core/osdep/linux/ofpath.c +++ b/grub-core/osdep/linux/ofpath.c @@ -488,8 +488,11 @@ check_hba_identifiers (const char *sysfs_path, int *vendor, int *device_id) static void check_sas (const char *sysfs_path, int *tgt, unsigned long int *sas_address) { - char *ed = strstr (sysfs_path, "end_device"); - char *p, *q, *path; + const char *ed = strstr (sysfs_path, "end_device"); + int p_len; + int ed_len; + const char *q; + char *path; char phy[21]; int fd; size_t path_size; @@ -498,20 +501,16 @@ check_sas (const char *sysfs_path, int *tgt, unsigned long int *sas_address) return; /* SAS devices are identified using disk@$PHY_ID */ - p = xstrdup (sysfs_path); - ed = strstr(p, "end_device"); - if (!ed) - return; - q = ed; while (*q && *q != '/') q++; - *q = '\0'; + p_len = (int) (q - sysfs_path); + ed_len = (int) (q - ed); - path_size = (strlen (p) + strlen (ed) - + sizeof ("%s/sas_device/%s/phy_identifier")); + path_size = (p_len + ed_len + sizeof ("%s/sas_device/%s/phy_identifier")); path = xmalloc (path_size); - snprintf (path, path_size, "%s/sas_device/%s/phy_identifier", p, ed); + snprintf (path, path_size, "%.*s/sas_device/%.*s/phy_identifier", p_len, + sysfs_path, ed_len, ed); fd = open (path, O_RDONLY); if (fd < 0) grub_util_error (_("cannot open `%s': %s"), path, strerror (errno)); @@ -524,7 +523,8 @@ check_sas (const char *sysfs_path, int *tgt, unsigned long int *sas_address) sscanf (phy, "%d", tgt); - snprintf (path, path_size, "%s/sas_device/%s/sas_address", p, ed); + snprintf (path, path_size, "%.*s/sas_device/%.*s/sas_address", p_len, + sysfs_path, ed_len, ed); fd = open (path, O_RDONLY); if (fd < 0) grub_util_error (_("cannot open `%s': %s"), path, strerror (errno)); @@ -535,7 +535,6 @@ check_sas (const char *sysfs_path, int *tgt, unsigned long int *sas_address) sscanf (phy, "%lx", sas_address); free (path); - free (p); close (fd); } -- 2.53.0 ++++++ 0001-util-probe-Save-strrchr-ret-val-to-const-data-ptr.patch ++++++ >From 9f4a586f1227a8287e1d6acd95893f6098756ee2 Mon Sep 17 00:00:00 2001 From: Nicholas Vinson <[email protected]> Date: Tue, 24 Feb 2026 19:48:41 -0500 Subject: [PATCH 1/2] util/probe: Save strrchr() ret val to const data ptr With glibc-2.43 implementing the C23 standard, strrchr() now returns "const char *" when its first argument is "const char *". The fix is update all pointers receiving strrchr()'s return value so that they are now "const char *" instead of "char *". Signed-off-by: Nicholas Vinson <[email protected]> Reviewed-by: Daniel Kiper <[email protected]> --- util/probe.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/util/probe.c b/util/probe.c index 81d91cf59..a9158d640 100644 --- a/util/probe.c +++ b/util/probe.c @@ -70,7 +70,7 @@ char * grub_util_guess_bios_drive (const char *orig_path) { char *canon; - char *ptr; + const char *ptr; canon = grub_canonicalize_file_name (orig_path); if (!canon) return NULL; @@ -99,7 +99,7 @@ char * grub_util_guess_efi_drive (const char *orig_path) { char *canon; - char *ptr; + const char *ptr; canon = grub_canonicalize_file_name (orig_path); if (!canon) return NULL; @@ -128,7 +128,7 @@ char * grub_util_guess_baremetal_drive (const char *orig_path) { char *canon; - char *ptr; + const char *ptr; canon = grub_canonicalize_file_name (orig_path); if (!canon) return NULL; -- 2.53.0 ++++++ 0002-menu-Allow-default-entry-to-have-.conf-suffix.patch ++++++ >From 1be3059a7867e97406edaf4c567b5ed1862ded24 Mon Sep 17 00:00:00 2001 From: Danilo Spinella <[email protected]> Date: Wed, 11 Mar 2026 14:23:47 +0100 Subject: [PATCH 2/9] menu: Allow default entry to have ".conf" suffix When setting default entry, accept values that ends in ".conf". Strip the suffix when looking for the corresponding entry. --- grub-core/normal/menu.c | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) Index: grub-2.14/grub-core/normal/menu.c =================================================================== --- grub-2.14.orig/grub-core/normal/menu.c +++ grub-2.14/grub-core/normal/menu.c @@ -571,7 +571,8 @@ static int get_entry_number (grub_menu_t menu, const char *name) { const char *val; - int entry; + char *ext; + int entry, res; val = grub_env_get (name); if (! val) @@ -601,6 +602,23 @@ get_entry_number (grub_menu_t menu, cons entry = i; break; } + + if (e->blsuki) + { + ext = grub_strrchr (val, '.'); + if (ext && grub_strcmp (ext, ".conf") == 0) + { + *ext = '\0'; + res = menuentry_eq (e->id, val); + *ext = '.'; + if (res) + { + entry = i; + break; + } + } + } + e = e->next; /* Skip hidden entries */ ++++++ 0002-util-resolve-Save-str-r-chr-ret-val-to-const-data-pt.patch ++++++ >From ce6f2b57f5450a8239022dcbfb2d750f273b83cb Mon Sep 17 00:00:00 2001 From: Nicholas Vinson <[email protected]> Date: Tue, 24 Feb 2026 19:48:42 -0500 Subject: [PATCH 2/2] util/resolve: Save str[r]chr() ret val to const data ptr With glibc-2.43 implementing the C23 standard, strrchr() and strchr() now return "const char *" when its first argument is "const char *". The fix is update all pointers receiving strrchr() and strchr()'s return values so that they are now "const char *" instead of "char *". Signed-off-by: Nicholas Vinson <[email protected]> Reviewed-by: Daniel Kiper <[email protected]> --- util/resolve.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/util/resolve.c b/util/resolve.c index b6e26312f..254379195 100644 --- a/util/resolve.c +++ b/util/resolve.c @@ -138,12 +138,12 @@ read_dep_list (FILE *fp) static char * get_module_name (const char *str) { - char *base; - char *ext; + const char *base; + const char *ext; base = strrchr (str, '/'); if (! base) - base = (char *) str; + base = str; else base++; @@ -164,9 +164,9 @@ get_module_name (const char *str) static char * get_module_path (const char *prefix, const char *str) { - char *dir; + const char *dir; char *base; - char *ext; + const char *ext; char *ret; ext = strrchr (str, '.'); -- 2.53.0 ++++++ 0003-bli-Add-support-for-LoaderEntryDefault-and-LoaderEnt.patch ++++++ >From 688d4f6be407e5d5669469b1fa166eb50d789a42 Mon Sep 17 00:00:00 2001 From: Danilo Spinella <[email protected]> Date: Wed, 11 Mar 2026 15:06:27 +0100 Subject: [PATCH 3/9] bli: Add support for LoaderEntryDefault and LoaderEntryOneShot --- grub-core/commands/bli.c | 44 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) diff --git a/grub-core/commands/bli.c b/grub-core/commands/bli.c index 38f52f87a..0b4e1259a 100644 --- a/grub-core/commands/bli.c +++ b/grub-core/commands/bli.c @@ -149,6 +149,49 @@ set_loader_active_pcr_banks (void) return status; } +/* Get the value of a EFI variable */ +static char* +get_efivar (const char* efivar) +{ + grub_efi_status_t status; + grub_size_t size; + grub_efi_char16_t *val_efi = NULL; + char *val = NULL; + status = grub_efi_get_variable (efivar, + &bli_vendor_guid, + &size, + (void**) &val_efi); + if (status == GRUB_EFI_SUCCESS && size != 0) + { + val = grub_malloc (size * sizeof (char)); + grub_utf16_to_utf8 ((grub_uint8_t*) val, + (grub_uint16_t*) val_efi, size); + } + return val; +} + +static void +set_loader_default_entry (void) +{ + char* default_entry; + char* oneshot_entry = get_efivar("LoaderEntryOneShot"); + + if (oneshot_entry != NULL) + { + grub_env_set ("default", oneshot_entry); + grub_efi_set_variable_to_string("LoaderEntryOneShot", + &bli_vendor_guid, "", 0); + } + else + { + default_entry = get_efivar("LoaderEntryDefault"); + if (default_entry != NULL) + { + grub_env_set ("default", default_entry); + } + } +} + GRUB_MOD_INIT (bli) { grub_efi_set_variable_to_string ("LoaderInfo", &bli_vendor_guid, PACKAGE_STRING, @@ -156,6 +199,7 @@ GRUB_MOD_INIT (bli) GRUB_EFI_VARIABLE_RUNTIME_ACCESS); set_loader_device_part_uuid (); set_loader_active_pcr_banks (); + set_loader_default_entry (); /* No error here is critical, other than being logged */ grub_print_error (); } -- 2.53.0 ++++++ 0004-bli-Add-support-for-LoaderConfigTimeout-and-LoaderCo.patch ++++++ >From 7f4877566b95db91c0df62fb2bccac1a244c5170 Mon Sep 17 00:00:00 2001 From: Danilo Spinella <[email protected]> Date: Wed, 11 Mar 2026 17:55:47 +0100 Subject: [PATCH 4/9] bli: Add support for LoaderConfigTimeout and LoaderConfigTimeoutOneShot Add new timeout_style "disabled" to match Boot Loader Interface. --- grub-core/commands/bli.c | 79 ++++++++++++++++++++++++++++++++++++++++ grub-core/normal/menu.c | 9 +++-- 2 files changed, 85 insertions(+), 3 deletions(-) diff --git a/grub-core/commands/bli.c b/grub-core/commands/bli.c index 0b4e1259a..b77e393a0 100644 --- a/grub-core/commands/bli.c +++ b/grub-core/commands/bli.c @@ -192,6 +192,84 @@ set_loader_default_entry (void) } } +/* Parse the timeout according to the Boot Loader Interface spec + for LoaderConfigTimeout and LoaderConfigTimeoutOneShot. + Return true when the timeout has been set. */ +static int +parse_timeout_bli (const char* config_timeout, bool is_oneshot) +{ + unsigned int timeout; + /* When the timeout is set to menu-force or LoaderConfigTimeoutOneShot is + set to 0, show the menu indefinitely */ + if (grub_strcmp (config_timeout, "menu-force") == 0 + || (is_oneshot && grub_strcmp (config_timeout, "0") == 0)) + { + grub_env_unset ("timeout"); + grub_env_set ("timeout_style", "menu"); + /* When set to 0 or to menu-hidden, don't show the menu but wait until the + timeout expires. Allow the user to interrupt the boot and show the menu */ + } else if (grub_strcmp (config_timeout, "0") == 0 + || grub_strcmp (config_timeout, "menu-hidden") == 0) + { + grub_menu_set_timeout (3); + grub_env_set ("timeout_style", "hidden"); + /* When set to to menu-disabled, don't show the menu and boot the default + entry directly. Don't allow the user to interrupt the bootloader. */ + } else if (grub_strcmp (config_timeout, "menu-disabled") == 0) + { + grub_env_set ("timeout", "0"); + grub_env_set ("timeout_style", "disabled"); + } else { + timeout = grub_strtoul (config_timeout, 0, 10); + if (grub_errno == GRUB_ERR_NONE) + { + /* In previous versions of bootctl, timeout is set to GRUB_UINT_MAX + instead of menu-force */ + if (timeout == GRUB_UINT_MAX) + grub_env_unset ("timeout"); + else + grub_menu_set_timeout (timeout); + + grub_env_set ("timeout_style", "menu"); + } else { + grub_errno = GRUB_ERR_NONE; + return false; + } + } + + return true; +} + +/* Read LoaderConfigTimeout and LoaderConfigTimeoutOneShot and update + timeout accordingly */ +static void +set_timeout_from_loader_config (void) +{ + bool has_oneshot = false; + char* config_timeout = get_efivar ("LoaderConfigTimeoutOneShot"); + if (config_timeout) + { + /* Remove its value, regardless if it is valid or not */ + grub_efi_set_variable_to_string ("LoaderConfigTimeoutOneShot", + &bli_vendor_guid, "", 0); + + has_oneshot = parse_timeout_bli (config_timeout, true); + grub_free (config_timeout); + } + + if (has_oneshot) + return; + + /* If there was no LoaderConfigTimeoutOneShot value or it was invalid, + read LoaderConfigTimeout */ + config_timeout = get_efivar ("LoaderConfigTimeout"); + if (!config_timeout) + return; + + parse_timeout_bli (config_timeout, false); + grub_free (config_timeout); +} + GRUB_MOD_INIT (bli) { grub_efi_set_variable_to_string ("LoaderInfo", &bli_vendor_guid, PACKAGE_STRING, @@ -200,6 +278,7 @@ GRUB_MOD_INIT (bli) set_loader_device_part_uuid (); set_loader_active_pcr_banks (); set_loader_default_entry (); + set_timeout_from_loader_config (); /* No error here is critical, other than being logged */ grub_print_error (); } diff --git a/grub-core/normal/menu.c b/grub-core/normal/menu.c index 569573011..e9738890a 100644 --- a/grub-core/normal/menu.c +++ b/grub-core/normal/menu.c @@ -44,7 +44,8 @@ grub_err_t (*grub_gfxmenu_try_hook) (int entry, grub_menu_t menu, enum timeout_style { TIMEOUT_STYLE_MENU, TIMEOUT_STYLE_COUNTDOWN, - TIMEOUT_STYLE_HIDDEN + TIMEOUT_STYLE_HIDDEN, + TIMEOUT_STYLE_DISABLED }; struct timeout_style_name { @@ -54,6 +55,7 @@ struct timeout_style_name { {"menu", TIMEOUT_STYLE_MENU}, {"countdown", TIMEOUT_STYLE_COUNTDOWN}, {"hidden", TIMEOUT_STYLE_HIDDEN}, + {"disabled", TIMEOUT_STYLE_DISABLED}, {NULL, 0} }; @@ -672,10 +674,11 @@ run_menu (grub_menu_t menu, int nested, int *auto_boot, int *notify_boot) } /* If timeout is 0, drawing is pointless (and ugly). */ - if (timeout == 0) + if (timeout == 0 || timeout_style == TIMEOUT_STYLE_DISABLED) { *auto_boot = 1; - *notify_boot = timeout_style != TIMEOUT_STYLE_HIDDEN; + *notify_boot = timeout_style != TIMEOUT_STYLE_HIDDEN + && timeout_style != TIMEOUT_STYLE_DISABLED; return default_entry; } -- 2.53.0 ++++++ 0005-bls_bumpcounter-Add-command-to-bump-boot-counter-for.patch ++++++ >From d5ac5c86c4014a6dedc47073ef305d227c38f65c Mon Sep 17 00:00:00 2001 From: Danilo Spinella <[email protected]> Date: Thu, 12 Mar 2026 10:51:06 +0100 Subject: [PATCH 5/9] bls_bumpcounter: Add command to bump boot counter for BLS entries --- grub-core/Makefile.core.def | 6 + grub-core/commands/bls_bumpcounter.c | 275 +++++++++++++++++++++++++++ grub-core/normal/menu.c | 23 +++ include/grub/efi/filesystem.h | 155 +++++++++++++++ 4 files changed, 459 insertions(+) create mode 100644 grub-core/commands/bls_bumpcounter.c create mode 100644 include/grub/efi/filesystem.h Index: grub-2.14/grub-core/Makefile.core.def =================================================================== --- grub-2.14.orig/grub-core/Makefile.core.def +++ grub-2.14/grub-core/Makefile.core.def @@ -868,6 +868,12 @@ module = { cppflags = '$(CPPFLAGS_POSIX) $(CPPFLAGS_GNULIB)'; }; + module = { + name = bls_bumpcounter; + efi = commands/bls_bumpcounter.c; + enable = efi; +}; + module = { name = boot; common = commands/boot.c; Index: grub-2.14/grub-core/commands/bls_bumpcounter.c =================================================================== --- /dev/null +++ grub-2.14/grub-core/commands/bls_bumpcounter.c @@ -0,0 +1,275 @@ +/* bls.c - implementation of the boot loader spec */ + +/* + * GRUB -- GRand Unified Bootloader + * + * 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/err.h" +#include <grub/charset.h> +#include <grub/extcmd.h> +#include <grub/fs.h> +#include <grub/env.h> +#include <grub/lib/envblk.h> +#include <grub/efi/api.h> +#include <grub/efi/efi.h> +#include <grub/efi/filesystem.h> + +#include <stddef.h> + +GRUB_MOD_LICENSE ("GPLv3+"); + +#define GRUB_BLS_CONFIG_PATH "\\loader\\entries\\" + +static const grub_guid_t grub_simple_file_system_guid = + GRUB_EFI_SIMPLE_FILE_SYSTEM_PROTOCOL_GUID; +static const grub_guid_t bli_vendor_guid = + GRUB_EFI_VENDOR_BOOT_LOADER_INTERFACE_GUID; + +/* Replace linux path delimiter (/) with EFI compatible (\) */ +static void +use_efi_delimiter_for_path (char* s) +{ + char* tmp = grub_strchr(s, '/'); + while (tmp != NULL) + { + *tmp++ = '\\'; + tmp = grub_strchr(tmp, '/'); + } +} + +/* Calculate the new filename with the bumped counter */ +static char* +bump_counter (char* entry) +{ + char *tmp = grub_strrchr (entry, '+'); + int tries = -1, tries_left; + *tmp = '\0'; + tries_left = grub_strtol (++tmp, (const char**) &tmp, 10); + /* The parsing succeeded */ + if (tmp != NULL) + { + if (tries_left > 0) + { + tries_left--; + } + if (*tmp == '-') + { + tmp++; + tries = grub_strtol (tmp, (const char**) &tmp, 10); + if (tmp != NULL) + { + tries++; + } else { + tries = -1; + } + } + } else { + return NULL; + } + + if (tries == -1) + { + /* This is the first try, rename accordingly */ + return grub_xasprintf ("%s+%d-1.conf", entry, tries_left); + } else { + return grub_xasprintf ("%s+%d-%d.conf", entry, tries_left, tries); + } +} + +static grub_err_t +grub_cmd_bls_bumpcounter (grub_extcmd_context_t ctxt __attribute__ ((unused)), + int argc, char **args) +{ + grub_efi_loaded_image_t *image; + grub_efi_file_info_t *file_info = NULL; + grub_efi_file_protocol_t *handle, *root; + grub_efi_simple_file_system_protocol_t *volume; + grub_efi_boot_services_t *bs; + grub_guid_t grub_efi_file_info_guid = GRUB_EFI_FILE_INFO_ID; + grub_efi_status_t err; + char *entry, *new_path = NULL, *old_path; + const char *blsdir; + grub_efi_uint64_t size; + grub_efi_char16_t *old_path16; + + if (argc != 1) { + grub_dprintf ("bls_bumpcounter", "only one argument should be passed\n"); + return GRUB_ERR_BAD_ARGUMENT; + } + entry = args[0]; + + grub_efi_set_variable_to_string ("LoaderEntrySelected", + &bli_vendor_guid, entry, + GRUB_EFI_VARIABLE_BOOTSERVICE_ACCESS + | GRUB_EFI_VARIABLE_RUNTIME_ACCESS); + + /* Look for the start of the boot count. + If no '+' symbol has been found, the boot counting isn't enabled for + the selected entry */ + if (grub_strrchr (entry, '+') == NULL) + { + grub_dprintf ("bls_bumpcounter", + "boot counting is not in effect for %s\n", entry); + return GRUB_ERR_NONE; + } + + image = grub_efi_get_loaded_image (grub_efi_image_handle); + + if (!image) + { + grub_dprintf ("bls_bumpcounter", "grub_efi_get_loaded_image failed\n"); + return GRUB_ERR_BUG; + } + + bs = grub_efi_system_table->boot_services; + err = bs->handle_protocol (image->device_handle, + (void *) &grub_simple_file_system_guid, (void *) &volume); + if (err != GRUB_EFI_SUCCESS) + { + grub_dprintf ("bls_bumpcounter", + "Cannot get handle to EFI_SIMPLE_FILE_SYSTEM_PROTOCOL: %lu\n", + (unsigned long) err); + return GRUB_ERR_BAD_DEVICE; + } + err = volume->OpenVolume (volume, &root); + if (err != GRUB_EFI_SUCCESS) + { + grub_dprintf ("bls_bumpcounter", + "Cannot open the volume: %lu\n", (unsigned long) err); + return GRUB_ERR_BAD_DEVICE; + } + + blsdir = grub_env_get ("blsdir"); + if (blsdir) + { + use_efi_delimiter_for_path ((char*) blsdir); + } else { + blsdir = GRUB_BLS_CONFIG_PATH; + } + + old_path = grub_xasprintf ("%s%s", blsdir, entry); + grub_utf8_to_utf16_alloc (old_path, &old_path16, NULL); + + err = root->Open (root, &handle, old_path16, + GRUB_EFI_FILE_MODE_READ|GRUB_EFI_FILE_MODE_WRITE, 0); + grub_free (old_path16); + if (err != GRUB_EFI_SUCCESS) + { + grub_dprintf("bls_bumpcounter", "Cannot open the entry %s: %lu\n", + old_path, (unsigned long) err); + grub_free (old_path); + return GRUB_ERR_BAD_DEVICE; + } + grub_free (old_path); + + /* Get the file_info by allocating a fixed size that should be big enough for + most cases, and, if it fails, allocate a new one with the exact size + returned from GetInfo. + Reference: systemd:src/boot/efi/util.c =*/ + size = offsetof (grub_efi_file_info_t, FileName) + + 256U * sizeof (grub_efi_char16_t); + file_info = grub_malloc (size); + if (!file_info) + { + grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("out of memory")); + goto finish; + } + err = handle->GetInfo (handle, &grub_efi_file_info_guid, &size, file_info); + if (err == GRUB_EFI_BUFFER_TOO_SMALL) + { + grub_free(file_info); + /* When we bump the counter, it might happen that we increase the filename + length. Add the space for 2 more characters. (i.e. adding the boot done + part "-1") */ + size += 2; + file_info = grub_malloc (size); + if (!file_info) + { + grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("out of memory")); + goto finish; + } + err = handle->GetInfo (handle, &grub_efi_file_info_guid, + &size, file_info); + } + + if (err != GRUB_EFI_SUCCESS) + { + grub_dprintf ("bls_bumpcounter", + "Cannot get the file_info of the entry: %lu\n", (unsigned long) err); + goto finish; + } + + new_path = bump_counter (entry); + if (!new_path) + goto finish; + + grub_dprintf ("bls_bumpcounter", "renaming entry to %s\n", new_path); + grub_utf8_to_utf16 (file_info->FileName, + size - offsetof (grub_efi_file_info_t, FileName), + (grub_uint8_t*) new_path, grub_strlen (new_path), NULL); + + err = handle->SetInfo (handle, &grub_efi_file_info_guid, size, file_info); + + if (err != GRUB_EFI_SUCCESS) + { + grub_dprintf ("bls_bumpcounter", "Cannot rename file: %lu\n", + (unsigned long) err); + goto finish; + } + + handle->Flush (handle); + grub_dprintf ("bls_bumpcounter", "entry renamed\n"); + handle->Close (handle); + + char* loader_boot_count_path = grub_xasprintf("%s%s", blsdir, new_path); + grub_free(new_path); + grub_efi_set_variable_to_string("LoaderBootCountPath", &bli_vendor_guid, + loader_boot_count_path, + GRUB_EFI_VARIABLE_BOOTSERVICE_ACCESS + | GRUB_EFI_VARIABLE_RUNTIME_ACCESS); + grub_free(loader_boot_count_path); + + if (err != GRUB_EFI_SUCCESS) + { + goto finish; + } + + grub_free(file_info); + return GRUB_ERR_NONE; + +finish: + grub_free(file_info); + return GRUB_ERR_BUG; +} + + +static grub_extcmd_t cmd; + +GRUB_MOD_INIT(blsbumpcounter) +{ + grub_dprintf ("bls_bumpcounter", "%s got here\n", __func__); + cmd = grub_register_extcmd ("bls_bumpcounter", + grub_cmd_bls_bumpcounter, + 0, + NULL, + N_("Bump the boot entry counting."), + NULL); +} + +GRUB_MOD_FINI(blsbumpcounter) +{ + grub_unregister_extcmd (cmd); +} Index: grub-2.14/grub-core/normal/menu.c =================================================================== --- grub-2.14.orig/grub-core/normal/menu.c +++ grub-2.14/grub-core/normal/menu.c @@ -231,6 +231,10 @@ grub_menu_execute_entry(grub_menu_entry_ char *optr, *buf, *oldchosen = NULL, *olddefault = NULL; const char *ptr, *chosen, *def; grub_size_t sz = 0; +#ifdef GRUB_MACHINE_EFI + char *args[] = { NULL }; + char *filename; +#endif if (entry->restricted) { @@ -324,6 +328,26 @@ grub_menu_execute_entry(grub_menu_entry_ grub_env_set ("default", ptr + 1); else grub_env_unset ("default"); + +#ifdef GRUB_MACHINE_EFI + /* Check if this entry has been generated by blscfg */ + if (entry->blsuki && entry->blsuki->filename) + { + filename = grub_strdup (entry->blsuki->filename); + + if (filename == NULL) + grub_print_error (); + else + { + *args = filename; + + /* Bump the boot counter of the BLS entry */ + grub_command_execute ("bls_bumpcounter", 1, args); + grub_free (filename); + } + } +#endif + #ifdef GRUB_MACHINE_IEEE1275 char *cas_entry_id = NULL; char *cas_entry_source; Index: grub-2.14/include/grub/efi/filesystem.h =================================================================== --- /dev/null +++ grub-2.14/include/grub/efi/filesystem.h @@ -0,0 +1,155 @@ +/* + * GRUB -- GRand Unified Bootloader + * + * 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_EFI_TPM_HEADER +#define GRUB_EFI_TPM_HEADER 1 + +#include <grub/efi/api.h> +#include <grub/env.h> + +struct grub_efi_file_io_token { + grub_efi_event_t Event; + grub_efi_status_t Status; + grub_efi_uint64_t BufferSize; + void *Buffer; +}; + +typedef struct grub_efi_file_io_token grub_efi_file_io_token_t; + + +struct grub_efi_file_protocol +{ + grub_efi_uint64_t Revision; + + grub_efi_status_t + (__grub_efi_api *Open) (struct grub_efi_file_protocol *this, + struct grub_efi_file_protocol **new_handle, + grub_efi_char16_t *filename, + grub_efi_uint64_t open_mode, + grub_efi_uint64_t attributes); + + grub_efi_status_t + (__grub_efi_api *Close) (struct grub_efi_file_protocol *this); + + grub_efi_status_t + (__grub_efi_api *Delete) (struct grub_efi_file_protocol *this); + + grub_efi_status_t + (__grub_efi_api *Read) (struct grub_efi_file_protocol *this, + grub_efi_uint64_t *buffer_size, + void *buffer); + + grub_efi_status_t + (__grub_efi_api *Write) (struct grub_efi_file_protocol *this, + grub_efi_uint64_t *buffer_size, + void *buffer); + + grub_efi_status_t + (__grub_efi_api *GetPosition) (struct grub_efi_file_protocol *this, + grub_efi_uint64_t *position); + + grub_efi_status_t + (__grub_efi_api *SetPosition) (struct grub_efi_file_protocol *this, + grub_efi_uint64_t position); + + grub_efi_status_t + (__grub_efi_api *GetInfo) (struct grub_efi_file_protocol *this, + grub_guid_t *information_type, + grub_efi_uint64_t *buffer_size, + void *buffer); + + grub_efi_status_t + (__grub_efi_api *SetInfo) (struct grub_efi_file_protocol *this, + grub_guid_t *information_type, + grub_efi_uint64_t buffer_size, + void *buffer); + + grub_efi_status_t + (__grub_efi_api *Flush) (struct grub_efi_file_protocol *this); + + grub_efi_status_t + (__grub_efi_api *OpenEx) (struct grub_efi_file_protocol *this, + struct grub_efi_file_protocol **new_handle, + grub_efi_char16_t *filename, + grub_efi_uint64_t open_mode, + grub_efi_uint64_t attributes, + grub_efi_file_io_token_t *token); + + grub_efi_status_t + (__grub_efi_api *ReadEx) (struct grub_efi_file_protocol *this, + grub_efi_file_io_token_t *token); + + grub_efi_status_t + (__grub_efi_api *WriteEx) (struct grub_efi_file_protocol *this, + grub_efi_file_io_token_t *token); + + grub_efi_status_t + (__grub_efi_api *FlushEx) (struct grub_efi_file_protocol *this, + grub_efi_file_io_token_t *token); +}; + +typedef struct grub_efi_file_protocol grub_efi_file_protocol_t; + +/******************************************************* + Open Modes + ******************************************************/ +#define GRUB_EFI_FILE_MODE_READ 0x0000000000000001 +#define GRUB_EFI_FILE_MODE_WRITE 0x0000000000000002 +#define GRUB_EFI_FILE_MODE_CREATE 0x8000000000000000 + +/******************************************************* + File Attributes + ******************************************************/ +#define GRUB_EFI_FILE_READ_ONLY 0x0000000000000001 +#define GRUB_EFI_FILE_HIDDEN 0x0000000000000002 +#define GRUB_EFI_FILE_SYSTEM 0x0000000000000004 +#define GRUB_EFI_FILE_RESERVED 0x0000000000000008 +#define GRUB_EFI_FILE_DIRECTORY 0x0000000000000010 +#define GRUB_EFI_FILE_ARCHIVE 0x0000000000000020 +#define GRUB_EFI_FILE_VALID_ATTR 0x0000000000000037 + +struct grub_efi_file_info { + grub_efi_uint64_t Size; + grub_efi_uint64_t FileSize; + grub_efi_uint64_t PhysicalSize; + grub_efi_time_t CreateTime; + grub_efi_time_t LastAccessTime; + grub_efi_time_t ModificationTime; + grub_efi_uint64_t Attribute; + grub_efi_char16_t FileName[]; +}; + +typedef struct grub_efi_file_info grub_efi_file_info_t; + +#define GRUB_EFI_FILE_INFO_ID \ + {0x09576e92,0x6d3f,0x11d2, \ + {0x8e,0x39,0x00,0xa0,0xc9,0x69,0x72,0x3b} \ + } + +struct grub_efi_simple_file_system_protocol +{ + grub_efi_uint64_t Revision; + + grub_efi_status_t + (__grub_efi_api *OpenVolume) (struct grub_efi_simple_file_system_protocol *this, + struct grub_efi_file_protocol **root); +}; + +typedef struct grub_efi_simple_file_system_protocol grub_efi_simple_file_system_protocol_t; + + +#endif ++++++ 0006-bli-Add-support-for-LoaderFeatures.patch ++++++ >From f7cdf321c11fc10e257cf512bebaabca4d792d82 Mon Sep 17 00:00:00 2001 From: Danilo Spinella <[email protected]> Date: Thu, 19 Mar 2026 10:25:36 +0100 Subject: [PATCH 6/9] bli: Add support for LoaderFeatures --- grub-core/commands/bli.c | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/grub-core/commands/bli.c b/grub-core/commands/bli.c index d0fde76f0..29f9d8ef7 100644 --- a/grub-core/commands/bli.c +++ b/grub-core/commands/bli.c @@ -37,6 +37,29 @@ GRUB_MOD_LICENSE ("GPLv3+"); static const grub_guid_t bli_vendor_guid = GRUB_EFI_VENDOR_BOOT_LOADER_INTERFACE_GUID; +#define GRUB_EFI_LOADER_FEATURE_CONFIG_TIMEOUT (1 << 0) +#define GRUB_EFI_LOADER_FEATURE_CONFIG_TIMEOUT_ONE_SHOT (1 << 1) +#define GRUB_EFI_LOADER_FEATURE_ENTRY_DEFAULT (1 << 2) +#define GRUB_EFI_LOADER_FEATURE_ENTRY_ONESHOT (1 << 3) +#define GRUB_EFI_LOADER_FEATURE_BOOT_COUNTING (1 << 4) +#define GRUB_EFI_LOADER_FEATURE_XBOOTLDR (1 << 5) +#define GRUB_EFI_LOADER_FEATURE_MENU_DISABLE (1 << 13) + +static grub_err_t +set_loader_features (void) +{ + static long loader_features = + GRUB_EFI_LOADER_FEATURE_CONFIG_TIMEOUT | + GRUB_EFI_LOADER_FEATURE_CONFIG_TIMEOUT_ONE_SHOT | + GRUB_EFI_LOADER_FEATURE_ENTRY_DEFAULT | + GRUB_EFI_LOADER_FEATURE_ENTRY_ONESHOT | + GRUB_EFI_LOADER_FEATURE_BOOT_COUNTING | + GRUB_EFI_LOADER_FEATURE_XBOOTLDR | + GRUB_EFI_LOADER_FEATURE_MENU_DISABLE; + + return grub_efi_set_variable("LoaderFeatures", &bli_vendor_guid, &loader_features, sizeof(long)); +} + static grub_err_t get_part_uuid (const char *device_name, char **part_uuid) { @@ -281,6 +304,7 @@ GRUB_MOD_INIT (bli) set_loader_active_pcr_banks (); set_loader_default_entry (); set_timeout_from_loader_config (); + set_loader_features (); /* No error here is critical, other than being logged */ grub_print_error (); } -- 2.53.0 ++++++ 0007-blsuki-Fix-sorting-for-entries-with-boot-counting-en.patch ++++++ >From 5cf5c938a1ed621e5dcd91277ad856552434df98 Mon Sep 17 00:00:00 2001 From: Danilo Spinella <[email protected]> Date: Thu, 19 Mar 2026 12:17:12 +0100 Subject: [PATCH 7/9] blsuki: Fix sorting for entries with boot counting enabled Sort entries with boot counting enabled (ending with +x-y.conf) and with 0 tries left below the rest. --- grub-core/commands/blsuki.c | 46 ++++++++++++++++++++++++++++++++++++- 1 file changed, 45 insertions(+), 1 deletion(-) diff --git a/grub-core/commands/blsuki.c b/grub-core/commands/blsuki.c index 2664a9fc4..8364ba9f4 100644 --- a/grub-core/commands/blsuki.c +++ b/grub-core/commands/blsuki.c @@ -251,6 +251,42 @@ blsuki_get_val (grub_blsuki_entry_t *entry, const char *keyname, int *last) return ret; } +/* Return the tries left of an entry with boot counting enabled. + When boot counting is disabled, return -1. */ +static long +tries_left (const char *filename) +{ + char *tries_left_str; + long ret = -1; + char *str = grub_strdup (filename); + + if (str == NULL) + return -1; + + /* Search for the start of the tries left, as per boot assessment */ + tries_left_str = grub_strrchr (str, '+'); + + if (tries_left_str != NULL) + { + const char *end; + long tries; + + ++tries_left_str; + tries = grub_strtol (tries_left_str, (const char **) &end, 10); + + if (grub_errno == GRUB_ERR_NONE) + { + if (*end == '-' || *end == '.') + ret = tries; + } + else + grub_errno = GRUB_ERR_NONE; + } + + grub_free (str); + return ret; +} + /* * Add a new grub_blsuki_entry_t struct to the entries list and sort it's * position on the list. @@ -259,7 +295,7 @@ static grub_err_t blsuki_add_entry (grub_blsuki_entry_t *entry) { grub_blsuki_entry_t *e, *last = NULL; - int rc; + int rc, t1, t2; if (entries == NULL) { @@ -274,6 +310,14 @@ blsuki_add_entry (grub_blsuki_entry_t *entry) if (rc == 0) return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("duplicate file: `%s'"), entry->filename); + /* Entries with 0 tries left should be put below the rest */ + t1 = tries_left (entry->filename); + t2 = tries_left (e->filename); + if (t2 == 0 && t1 != 0) + rc = 1; + else if (t2 != 0 && t1 == 0) + rc = -1; + if (rc > 0) { grub_dprintf ("blsuki", "Add entry with id \"%s\"\n", entry->filename); -- 2.53.0 ++++++ 0008-blsuki-append-leftover-LoaderEntries.patch ++++++ >From 716f057d6f6addd15d1913d4b3a3f879863c5839 Mon Sep 17 00:00:00 2001 From: Michael Chang <[email protected]> Date: Wed, 1 Apr 2026 12:41:13 +0200 Subject: [PATCH 8/9] blsuki: append leftover LoaderEntries When merging new BLS entries with the previous LoaderEntries value, entries that sort after all new items can remain pending in prev_entries. Those entries were not copied into the output buffer, so the EFI variable could lose trailing previous entries. Append any unconsumed previous entries after the merge, verify that enough UTF-16 space remains, and size the variable from the final write pointer. This keeps the merged list complete and reports the written buffer length correctly. Signed-off-by: Michael Chang <[email protected]> --- grub-core/commands/blsuki.c | 34 ++++++++++++++++++++++++++++++++-- 1 file changed, 32 insertions(+), 2 deletions(-) diff --git a/grub-core/commands/blsuki.c b/grub-core/commands/blsuki.c index 8364ba9f4..298f04a98 100644 --- a/grub-core/commands/blsuki.c +++ b/grub-core/commands/blsuki.c @@ -1489,7 +1489,7 @@ set_bli_loader_entries (enum blsuki_cmd_type cmd_type) prev_entries = prev_entries_start; prev_entries_size = prev_entries_start_size; p = efi_entries; - remaining_size = size; + remaining_size = size + (prev_entries_start_size / sizeof (*efi_entries)); /* Create a null separated list of all entries (with the extension removed) */ FOR_BLSUKI_ENTRIES (entry) { @@ -1552,9 +1552,39 @@ set_bli_loader_entries (enum blsuki_cmd_type cmd_type) } } + /* + * Append any entries left unconsumed in prev_entries after the ordered + * merge above. Previous entries are only emitted immediately when they + * sort before the current new entry; otherwise they remain pending until + * here. + */ + if (prev_entries_size != 0 && prev_entries != NULL) + { + grub_size_t remaining_entries_size; + + remaining_entries_size = prev_entries_size / sizeof (*prev_entries); + /* + * remaining_size is tracked in UTF-16 code units, so compare it + * against the number of UTF-16 elements left in the previous buffer. + */ + if (remaining_size < remaining_entries_size) + { + grub_free (prev_entries_start); + grub_free (efi_entries); + return grub_error ( + GRUB_ERR_OUT_OF_RANGE, + "LoaderEntries buffer too small for previous entries"); + } + + grub_memcpy (p, prev_entries, prev_entries_size); + p += remaining_entries_size; + remaining_size -= remaining_entries_size; + prev_entries_size = 0; + } + status = grub_efi_set_variable_with_attributes ("LoaderEntries", &bli_vendor_guid, efi_entries, - size * sizeof (grub_efi_char16_t) + prev_entries_start_size - prev_entries_size, + (p - efi_entries) * sizeof (*efi_entries), GRUB_EFI_VARIABLE_BOOTSERVICE_ACCESS | GRUB_EFI_VARIABLE_RUNTIME_ACCESS); /* Record that we set the generated entries by this command to LoaderEntries */ -- 2.53.0 ++++++ 0009-blsuki-conservative-UTF-8-buffer-size.patch ++++++ >From a5b58fdf1f775f12c7560603d729f0415f47a4c1 Mon Sep 17 00:00:00 2001 From: Michael Chang <[email protected]> Date: Wed, 1 Apr 2026 12:44:29 +0200 Subject: [PATCH 9/9] blsuki: conservative UTF-8 buffer size To be on safe side, use GRUB_MAX_UTF8_PER_UTF16 as UTF-8 for non ascii characters can be up to 4 bytes. --- grub-core/commands/blsuki.c | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/grub-core/commands/blsuki.c b/grub-core/commands/blsuki.c index 298f04a98..adc87207e 100644 --- a/grub-core/commands/blsuki.c +++ b/grub-core/commands/blsuki.c @@ -1516,11 +1516,30 @@ set_bli_loader_entries (enum blsuki_cmd_type cmd_type) if (prev_entries_size != 0 && prev_entries) { do { + grub_size_t prev_entry_size; + tmp16 = prev_entries; len16 = 0; while (*tmp16++ != '\0') len16++; - prev_entry = grub_malloc (len16 + 1); + + if (grub_mul (len16, GRUB_MAX_UTF8_PER_UTF16, &prev_entry_size) || + grub_add (prev_entry_size, 1, &prev_entry_size)) + { + grub_free (prev_entries_start); + grub_free (efi_entries); + return grub_error (GRUB_ERR_OUT_OF_RANGE, + "LoaderEntries entry is too large"); + } + + prev_entry = grub_malloc (prev_entry_size); + if (prev_entry == NULL) + { + grub_free (prev_entries_start); + grub_free (efi_entries); + return grub_errno; + } + *grub_utf16_to_utf8 ((grub_uint8_t*) prev_entry, prev_entries, len16) = '\0'; rc = filevercmp (prev_entry, entry->filename); if (rc == 0) -- 2.53.0 ++++++ grub2-btrfs-01-add-ability-to-boot-from-subvolumes.patch ++++++ --- /var/tmp/diff_new_pack.hIjhwA/_old 2026-04-30 20:25:57.031896548 +0200 +++ /var/tmp/diff_new_pack.hIjhwA/_new 2026-04-30 20:25:57.035896712 +0200 @@ -25,6 +25,9 @@ * Fix gcc-12 error: the comparison will always evaluate as 'true' for the address of 'label' will never be NULL [-Werror=address] +v3: + * Check find_pathname() in grub_cmd_btrfs_list_subvols() and return an error + on failure --- grub-core/fs/btrfs.c | 561 +++++++++++++++++++++++++++++++++++++++++++++++++-- @@ -372,7 +375,7 @@ grub_btrfs_unmount (data); -@@ -2431,6 +2638,248 @@ +@@ -2431,6 +2638,253 @@ } #endif @@ -578,7 +581,12 @@ + } + buf[elemsize] = 0; + -+ find_pathname(data, ref->dirid, fs_root, ref->name, &p); ++ err = find_pathname(data, ref->dirid, fs_root, ref->name, &p); ++ if (err) ++ { ++ r = -err; ++ break; ++ } + + if (print) + { @@ -621,7 +629,7 @@ static struct grub_fs grub_btrfs_fs = { .name = "btrfs", .fs_dir = grub_btrfs_dir, -@@ -2446,13 +2895,89 @@ +@@ -2446,13 +2900,89 @@ #endif }; ++++++ grub2-btrfs-09-get-default-subvolume.patch ++++++ --- /var/tmp/diff_new_pack.hIjhwA/_old 2026-04-30 20:25:57.087898846 +0200 +++ /var/tmp/diff_new_pack.hIjhwA/_new 2026-04-30 20:25:57.091899011 +0200 @@ -3,9 +3,15 @@ * Use overflow checking primitives where the arithmetic expression for buffer allocations may include unvalidated data +v2: + * Check find_pathname() in grub_btrfs_get_parent_subvol_path() and return + an error on failure + * Use get_fs_root() with offset -1 in grub_btrfs_get_parent_subvol_path() so + lower_bound() can find the highest-offset ROOT_ITEM for the subvolume id + --- a/grub-core/fs/btrfs.c +++ b/grub-core/fs/btrfs.c -@@ -3104,6 +3104,254 @@ +@@ -3146,6 +3146,260 @@ return 0; } @@ -70,7 +76,7 @@ + ref = (struct grub_btrfs_root_ref *)buf; + + err = get_fs_root(data, data->sblock.root_tree, grub_le_to_cpu64 (key_out.offset), -+ 0, &fs_root); ++ -1, &fs_root); + if (err) + { + grub_free(buf); @@ -78,7 +84,13 @@ + return err; + } + -+ find_pathname(data, grub_le_to_cpu64 (ref->dirid), fs_root, ref->name, &parent_path); ++ err = find_pathname(data, grub_le_to_cpu64 (ref->dirid), fs_root, ref->name, &parent_path); ++ if (err) ++ { ++ grub_free(buf); ++ free_iterator(&desc); ++ return err; ++ } + + if (child_path) + { @@ -260,7 +272,7 @@ static struct grub_fs grub_btrfs_fs = { .name = "btrfs", .fs_dir = grub_btrfs_dir, -@@ -3122,6 +3370,7 @@ +@@ -3164,6 +3418,7 @@ static grub_command_t cmd_info; static grub_command_t cmd_mount_subvol; static grub_extcmd_t cmd_list_subvols; @@ -268,7 +280,7 @@ static char * subvolid_set_env (struct grub_env_var *var __attribute__ ((unused)), -@@ -3192,6 +3441,11 @@ +@@ -3235,6 +3490,11 @@ "[-p|-n] [-o var] DEVICE", "Print list of BtrFS subvolumes on " "DEVICE.", options);
